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:
- An API key for your account.
- 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.
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.
/v1/couriers
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.
/v1/quotes
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 }
]
}'
{
"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.
/v1/shipments
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 }
]
}'
{
"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.
/v1/shipments/:id/label
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:
curl https://api.shipstack.example/v1/tracking/15012345678901 \
-H "Authorization: Bearer $SHIPSTACK_API_KEY"
Next steps
- Quotes: customs, service options, pickup points and multi-piece consignments.
- Shipments and labels: listing, voiding and label formats.
- Errors and rate limits: what to retry, and what not to.