Documentation
Tracking
Scan history for a parcel, in one status vocabulary that means the same thing for every carrier.
/v1/tracking/:tracking
Pass the tracking_number from a shipment. The history is
refreshed from the carrier when you ask for it, and events are always
returned in chronological order regardless of what order the carrier sent
them in.
curl https://api.shipstack.example/v1/tracking/15012345678901 \
-H "Authorization: Bearer $SHIPSTACK_API_KEY"
{
"tracking_number": "15012345678901",
"courier": "dpd",
"status": "out_for_delivery",
"events": [
{
"status": "pre_transit",
"description": "Label created",
"occurred_at": "2026-09-01T10:24:11Z"
},
{
"status": "in_transit",
"description": "Parcel collected",
"location": "Leeds",
"occurred_at": "2026-09-01T18:02:00Z",
"carrier_code": "PU"
},
{
"status": "out_for_delivery",
"description": "Out for delivery",
"location": "Bristol",
"occurred_at": "2026-09-02T07:41:00Z",
"carrier_code": "WC"
}
]
}
Status vocabulary
Every carrier's own status strings map onto exactly one of these, so you never write carrier-specific branching.
| Status | Meaning |
|---|---|
pre_transit | The label exists; the carrier does not have the parcel yet. |
in_transit | Moving through the carrier's network. |
out_for_delivery | With the driver, out for delivery today. |
delivered | Delivered. Terminal. |
exception | Something went wrong: a failed attempt, a customs hold, damage. |
returned | Returned to sender. Terminal. |
unknown | The carrier sent something we do not recognise. |
Polling
delivered and returned are terminal: once a parcel
reaches either, stop polling it. Each event also carries the carrier's own
raw status in carrier_code, which is useful for support
conversations but should not be branched on.