# Tracking and branded pages

Every purchased shipment has a tracking status that Ship Jay keeps up to date from the carrier.

## Read tracking

`GET /shipments/{id}/tracking` needs the `shipments:read` permission.

```bash
curl https://shipjay.com/api/v1/shipments/$SHIPMENT_ID/tracking \
  -H "Authorization: Bearer $SHIPJAY_KEY"
```
```js
const res = await fetch(`https://shipjay.com/api/v1/shipments/${shipmentId}/tracking`, {
  headers: { Authorization: `Bearer ${process.env.SHIPJAY_KEY}` },
});
const tracking = await res.json();
```
```python
tracking = requests.get(
    f"https://shipjay.com/api/v1/shipments/{shipment_id}/tracking",
    headers={"Authorization": f"Bearer {os.environ['SHIPJAY_KEY']}"},
    timeout=30,
).json()
```
```json
{
  "tracking_code": "9400100000000000000000",
  "status": "in_transit",
  "tracking_url": "https://shipjay.com/t/k3v9...",
  "events": [
    { "status": "in_transit", "message": "Arrived at regional facility", "location": "Minneapolis, MN", "occurred_at": "2026-05-04T14:12:00Z" },
    { "status": "pre_transit", "message": "Shipping label created", "location": null, "occurred_at": "2026-05-03T18:40:00Z" }
  ]
}
```

`events` holds up to the 100 most recent scans, newest first. `location` is the city and state when the carrier gave them, otherwise `null`.

## Statuses

| Status | Meaning |
| --- | --- |
| `unknown` | The carrier has not reported anything yet. |
| `pre_transit` | The label exists but the carrier has not scanned the parcel. |
| `in_transit` | On its way. |
| `out_for_delivery` | With the local carrier for delivery. |
| `delivered` | Delivered. |
| `available_for_pickup` | Waiting at a pickup location. |
| `return_to_sender` | On its way back to you. |
| `failure` | Delivery failed. |
| `cancelled` | The shipment was cancelled. |
| `error` | The carrier reported a problem with the tracking number. |

The shipment object (`GET /shipments/{id}`) has the current value as `tracking_status`, next to its purchase `status`, which is a different field.

## Get notified instead of polling

Subscribe a webhook endpoint to `tracking.updated`. Each event carries the new `status` and the `previousStatus`. See [Webhooks](/docs/webhooks). If you cannot receive webhooks, poll `GET /events` with the `after` parameter, which returns events oldest first.

## The branded tracking page

Each shipment has a `tracking_url`. It opens a tracking page for the recipient that uses your brand settings. The link contains a private token, so anyone with the link can see that shipment's status. Share it with the recipient, not publicly. Tracking emails sent from the app link to the same page.