FS Logistik · partner integration

Skynet Shipment API

Create shipments in the FS Logistik order system and follow their status. Built for Skynet; one account, one token.

v1 · sandbox live Last updated 27 Aug 2026

Overview

This API lets Skynet register shipments directly in the FS Logistik order system and check where each one stands. Every shipment is bound to the Skynet account, so it appears in the FS Logistik panel with all other work under that account.

The API covers two jobs and deliberately nothing else:

  • Create a shipment — sender, receiver, and package details in, an FS Logistik order number out.
  • Track a shipment — current status and the status history for a shipment Skynet created.

Rates and prices are not part of this API. Pricing is calculated on the FS Logistik side from the account's price list and never returned in any response. There is no rate-quote endpoint.

Where this stands

The sandbox is live and can be integrated against today. The production environment is being enabled — until FS Logistik confirms it, use the sandbox base URL only.

Base URLs

EnvironmentBase URLNotes
Productionhttps://admin.fslogistik.com/api/v1Real shipments, real invoicing
Sandboxhttps://test-admin.sendpakke.nu/api/v1Isolated database, separate key

All requests and responses are JSON. Send Content-Type: application/json and Accept: application/json. Timestamps are ISO 8601 with an offset, in Europe/Copenhagen time.

Getting started

  1. FS Logistik opens a partner account for Skynet in its admin panel and assigns it a price list and payment terms.
  2. FS Logistik sends Skynet the account's email address and password over a secure channel.
  3. Skynet calls POST /token once with those credentials and stores the API token it returns. The password is never sent again.
  4. Skynet integrates against the sandbox base URL and creates a few test shipments end to end.
  5. FS Logistik reviews the sandbox shipments in the panel, then opens the production account.

Authentication

Skynet has an account in the FS Logistik panel. Its email and password are exchanged once for a long-lived API token, and every later request carries that token. The password is never sent again.

POST/api/v1/token
{
  "email": "api@skynet.example",
  "password": "the account password",
  "name": "Skynet integration"
}

Response — 201 Created

{
  "token": "sk_live_9f2c41a7e8b34d05a6c1e7fbd9204e83",
  "token_type": "Bearer",
  "account": "SkyNet",
  "created_at": "2026-08-27T14:02:11+02:00"
}

Wrong credentials return 401. After five failed attempts in a minute the endpoint returns 429 and refuses further attempts for a short while.

Using the token

Every other request carries the token as a bearer token. It does not expire on its own; it stops working when FS Logistik revokes it.

Authorization: Bearer sk_live_9f2c41a7e8b34d05a6c1e7fbd9204e83
Content-Type: application/json
Accept: application/json

A missing, malformed, or revoked token returns 401. The token identifies the account, so no account or customer id is ever sent in a request body — a shipment always belongs to the token that created it, and only that account can read it back.

Handling credentials

Keep the password and the token server-side. Never place either in browser code, a mobile app, a URL query string, or a shared document. If either is exposed, tell FS Logistik — the token is revoked and reissued the same day.

Postman collection

Every endpoint on this page, with example requests and responses, ready to run.

Download the Postman collection (JSON, Postman v2.1 — import it with File → Import).

Fill in the email and password collection variables, run Get an API token once, and the token is stored automatically for the other requests. The collection defaults to the sandbox base URL.

Kept in step

The collection is updated together with this page whenever the API changes. If the two ever disagree, this page is correct — re-import the collection.

Create a shipment

POST/api/v1/shipments

Request

{
  "reference": "SKY-889271",
  "order_type": "package",
  "content_description": "Textile samples",
  "sender": {
    "name": "Atlas Tekstil A.S.",
    "phone": "+90 212 555 0134",
    "email": "export@atlastekstil.com",
    "company_name": "Atlas Tekstil A.S.",
    "address": {
      "street": "Mahmutbey Mah. Taşocağı Cad. No 12",
      "city": "Istanbul",
      "postal_code": "34218",
      "country_code": "TR"
    }
  },
  "receiver": {
    "name": "Lise Andersen",
    "phone": "+45 26 13 42 16",
    "email": "lise.andersen@example.dk",
    "address": {
      "street": "Nyholms Alle 30 B, 2. th",
      "city": "Rodovre",
      "postal_code": "2610",
      "country_code": "DK"
    }
  },
  "packages": [
    { "quantity": 1, "weight_kg": 2.4, "length_cm": 40, "width_cm": 30, "height_cm": 20 }
  ]
}

Fields

FieldRequiredDescription
referenceyesSkynet's own identifier for the shipment. Must be unique within the Skynet account, max 255 characters. Used for tracking and for idempotency.
order_typeyespackage or document.
content_descriptionyesPlain description of the goods, in English. Used on customs paperwork.
sender, receiveryesName, phone, and full address are required on both. Email is optional but is what triggers the receiver's notifications.
address.country_codeyesISO 3166-1 alpha-2, uppercase. The country name is resolved on the FS Logistik side.
packagesyesAt least one line. Each line needs quantity, weight, and all three dimensions. See Limits.

No pricing fields are accepted. Anything sent under pricing, unit_price, or total_price is ignored.

Response — 201 Created

{
  "reference": "SKY-889271",
  "order_number": "20260827004",
  "status": "pending",
  "created_at": "2026-08-27T14:12:08+02:00"
}

Store order_number alongside the reference — it is the number FS Logistik staff use when discussing a shipment.

Repeating a request

The reference is the idempotency key. Sending the same reference twice does not create a second shipment: the first call returns 201, and any repeat returns 200 with the existing shipment. This makes retries after a timeout safe.

Track a shipment

GET/api/v1/shipments/{reference}

Returns the current status of one shipment and how it got there. Only shipments created by the calling key are visible; anything else returns 404.

Response — 200 OK

{
  "reference": "SKY-889271",
  "order_number": "20260827004",
  "status": "shipped",
  "status_label": "Shipped",
  "carrier": "ups",
  "tracking_number": "1ZK919J46899000001",
  "updated_at": "2026-08-29T09:41:55+02:00",
  "history": [
    { "status": "pending",    "occurred_at": "2026-08-27T14:12:08+02:00" },
    { "status": "processing", "occurred_at": "2026-08-28T08:30:11+02:00" },
    { "status": "shipped",    "occurred_at": "2026-08-29T09:41:55+02:00" }
  ]
}

carrier and tracking_number are null until the shipment is handed to a carrier. The response carries no prices, no invoice data, and no billing details.

List shipments

GET/api/v1/shipments

Lists the calling account's shipments, newest first. Intended for reconciliation, not for polling individual shipments.

ParameterDefaultDescription
statusFilter by one status value.
created_afterISO 8601 date or datetime.
per_page50Maximum 200.
page1Page number.
{
  "data": [
    { "reference": "SKY-889271", "order_number": "20260827004", "status": "shipped",
      "updated_at": "2026-08-29T09:41:55+02:00" }
  ],
  "meta": { "page": 1, "per_page": 50, "total": 1 }
}

Statuses

A shipment always sits in exactly one of these. They are the same values FS Logistik staff see in the panel.

ValueMeaning
pendingRegistered, not yet picked up for processing.
processingBeing prepared — labelling, customs paperwork, carrier booking.
shippedHanded to the carrier. A tracking number is normally present from here on.
deliveredDelivered to the receiver. Terminal.
cancelledCancelled before dispatch. Terminal.

New statuses may be added over time. Treat an unrecognised value as "in progress" rather than failing.

Errors

Errors use standard HTTP status codes with a consistent body. Field-level problems are listed under errors, keyed by the field path from the request.

{
  "success": false,
  "message": "Validation failed",
  "errors": {
    "packages.0.weight_kg": ["The weight must not be greater than 30."],
    "receiver.address.postal_code": ["The receiver postal code is required."]
  }
}
CodeMeaningWhat to do
401Key missing, malformed, or revokedCheck the Authorization header. Do not retry.
404No shipment with that reference on this accountCheck the reference. Do not retry.
422Validation failedFix the fields listed in errors and send again.
429Rate limit exceededWait for the number of seconds in Retry-After.
500Something broke on the FS Logistik sideRetry with the same reference — it will not duplicate.

Limits

LimitValue
Weight per package0.1 – 30 kg (documents: 0.1 – 2 kg)
DimensionsLength ≤ 120 cm, width ≤ 50 cm, height ≤ 50 cm
Quantity per package line1 – 100
Package lines per shipmentAt least 1
Request rate60 requests per minute per key
Request body2 MB

These mirror the limits already enforced in the FS Logistik order system. If Skynet's shipments regularly fall outside them, say so before integration — the limits can be raised per account, but only deliberately.

Open points

Three things are still to be agreed between FS Logistik and Skynet. None of them change the shape of the API, but all three need an answer before the production key is issued.

  • Payment terms. Whether the Skynet account is prepaid or invoiced, and on what cycle.
  • Weight and dimension limits. Whether the standard limits above cover Skynet's traffic.
  • Cancellations. Whether Skynet needs to cancel a shipment through the API, or whether cancellation stays a manual request to FS Logistik.

Questions on this document go to FS Logistik before any code is written against it.