Skip to content

Documentation

Quickstart

From an API key to a label you can print, in four requests.

Before you start

You need two things, both set up in Shipstack Manager:

  1. An API key for your account.
  2. At least one courier enabled, with the credentials for a carrier account you already hold.

Shipstack does not resell postage. Quotes come back at the rates you have negotiated with the carrier directly.

Set your key once
export SHIPSTACK_API_KEY="sk_live_your_key_here"

1. Check which couriers are enabled

This confirms your key works and shows what your account can currently quote against.

GET /v1/couriers
Request
curl https://api.shipstack.example/v1/couriers \
  -H "Authorization: Bearer $SHIPSTACK_API_KEY"

2. Ask every courier for a rate

Describe the parcel once. Shipstack asks every enabled courier at the same time and returns the rates sorted cheapest first.

POST /v1/quotes
Request
curl -X POST https://api.shipstack.example/v1/quotes \
  -H "Authorization: Bearer $SHIPSTACK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": {
      "name": "Acme Supplies", "line1": "1 Mill Lane",
      "city": "Leeds", "postcode": "LS1 4DL", "country": "GB"
    },
    "to": {
      "name": "Sam Reed", "line1": "44 Bright Street",
      "city": "Bristol", "postcode": "BS1 5TR", "country": "GB",
      "email": "[email protected]", "residential": true
    },
    "parcels": [
      { "weight_g": 1200, "length_mm": 300, "width_mm": 200, "height_mm": 100 }
    ]
  }'
200 OK
{
  "rates": [
    {
      "courier": "royalmail_clickanddrop",
      "service_code": "TPN48",
      "service_name": "Royal Mail Tracked 48",
      "total": { "amount": 419, "currency": "GBP" },
      "estimated_days": 2
    },
    {
      "courier": "dpd",
      "service_code": "1^16",
      "service_name": "DPD Next Day",
      "total": { "amount": 749, "currency": "GBP" },
      "estimated_days": 1
    }
  ]
}

Pick a rate. You buy it by quoting its courier and service_code back to us.

3. Buy the label

Buying a label costs money, so always send an Idempotency-Key. Retrying with the same key returns the original shipment instead of buying a second label.

POST /v1/shipments
Request
curl -X POST https://api.shipstack.example/v1/shipments \
  -H "Authorization: Bearer $SHIPSTACK_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-10432-attempt-1" \
  -d '{
    "courier": "dpd",
    "service_code": "1^16",
    "label_format": "pdf",
    "from": {
      "name": "Acme Supplies", "line1": "1 Mill Lane",
      "city": "Leeds", "postcode": "LS1 4DL", "country": "GB"
    },
    "to": {
      "name": "Sam Reed", "line1": "44 Bright Street",
      "city": "Bristol", "postcode": "BS1 5TR", "country": "GB",
      "email": "[email protected]", "residential": true
    },
    "parcels": [
      { "weight_g": 1200, "length_mm": 300, "width_mm": 200, "height_mm": 100 }
    ]
  }'
201 Created
{
  "id": "shp_01HQ8W3ZK9V2A7",
  "courier": "dpd",
  "service_code": "1^16",
  "service_name": "DPD Next Day",
  "tracking_number": "15012345678901",
  "total": { "amount": 749, "currency": "GBP" },
  "label_format": "pdf",
  "created_at": "2026-09-01T10:24:11Z"
}

4. Download the label and track the parcel

The label document is fetched separately, so you can print it whenever you need it.

GET /v1/shipments/:id/label
Save the PDF
curl https://api.shipstack.example/v1/shipments/shp_01HQ8W3ZK9V2A7/label \
  -H "Authorization: Bearer $SHIPSTACK_API_KEY" \
  -o label.pdf

And the scan history, refreshed from the carrier when you ask for it:

Track
curl https://api.shipstack.example/v1/tracking/15012345678901 \
  -H "Authorization: Bearer $SHIPSTACK_API_KEY"

Next steps