> ## Documentation Index
> Fetch the complete documentation index at: https://openapidocs.flexforwardship.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Poll Tracking Updates

> How to retrieve and use normalized tracking data for customer notifications

# Poll tracking updates

Use `GET /tracking/{id}` to retrieve real-time shipment tracking data in a unified format. This guide covers the polling flow, how to interpret tracking statuses, and patterns for building customer notifications.

## Retrieve tracking data

Use the `id` from the label creation response:

<CodeGroup>
  ```bash cURL theme={null}
  curl https://api.flexforward.com/tracking/f47ac10b-58cc-4372-a567-0e02b2c3d479 \
    -H "Authorization: Bearer YOUR_API_TOKEN"
  ```

  ```javascript Node.js theme={null}
  const response = await fetch(
    'https://api.flexforward.com/tracking/f47ac10b-58cc-4372-a567-0e02b2c3d479',
    { headers: { 'Authorization': 'Bearer YOUR_API_TOKEN' } }
  );
  const tracking = await response.json();
  console.log(tracking.tag); // High-level status: InTransit, Delivered, etc.
  ```

  ```python Python theme={null}
  import requests

  response = requests.get(
      'https://api.flexforward.com/tracking/f47ac10b-58cc-4372-a567-0e02b2c3d479',
      headers={'Authorization': 'Bearer YOUR_API_TOKEN'}
  )
  tracking = response.json()
  print(tracking['tag'])  # High-level status: InTransit, Delivered, etc.
  ```
</CodeGroup>

### Response

```json 200 OK theme={null}
{
  "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "trackingNumber": "YT2503010001CN",
  "tag": "InTransit",
  "subtag": "InTransit_001",
  "subtagMessage": "In transit",
  "slug": "yunexpress",
  "checkpoints": [
    {
      "checkpointTime": "2026-03-17T08:15:00Z",
      "city": "Los Angeles",
      "state": "CA",
      "countryRegion": "US",
      "location": "LAX Distribution Center",
      "message": "Arrived at destination country",
      "tag": "InTransit",
      "subtag": "InTransit_001",
      "subtagMessage": "In transit",
      "slug": "yunexpress"
    },
    {
      "checkpointTime": "2026-03-16T02:30:00Z",
      "city": "Shenzhen",
      "state": "Guangdong",
      "countryRegion": "CN",
      "location": null,
      "message": "Departed from sorting center",
      "tag": "InTransit",
      "subtag": "InTransit_001",
      "subtagMessage": "In transit",
      "slug": "yunexpress"
    },
    {
      "checkpointTime": "2026-03-15T10:30:00Z",
      "city": "Tokyo",
      "state": "Tokyo",
      "countryRegion": "JP",
      "location": null,
      "message": "Shipment information received",
      "tag": "InfoReceived",
      "subtag": "InfoReceived_001",
      "subtagMessage": "Shipment information received",
      "slug": "yunexpress"
    }
  ]
}
```

Checkpoints are ordered with the most recent event first.

## Understand the tracking status

Use the top-level `tag` field for high-level status logic:

| Tag            | Customer-facing meaning          | Action                                                        |
| -------------- | -------------------------------- | ------------------------------------------------------------- |
| `Pending`      | Order is being processed         | No notification needed                                        |
| `InfoReceived` | Shipment registered with courier | Notify: "Your order has shipped"                              |
| `InTransit`    | Package is on the way            | Notify: "Your package is in transit"                          |
| `Delivered`    | Package delivered                | Notify: "Your package has been delivered"                     |
| `Exception`    | Delivery issue                   | Notify: "There's an issue with your delivery" and investigate |
| `Cancelled`    | Shipment cancelled               | Handle internally                                             |
| `Unknown`      | Status unavailable               | No notification — retry later                                 |

## Polling pattern

Since webhooks are not currently available, poll `GET /tracking/{id}` at a reasonable interval to detect status changes.

### Recommended approach

```javascript theme={null}
async function pollTracking(labelId, token) {
  let lastTag = null;

  const interval = setInterval(async () => {
    const response = await fetch(
      `https://api.flexforward.com/tracking/${labelId}`,
      { headers: { 'Authorization': `Bearer ${token}` } }
    );
    const tracking = await response.json();

    if (tracking.tag !== lastTag) {
      lastTag = tracking.tag;
      await notifyCustomer(tracking); // Your notification logic
    }

    // Stop polling when shipment reaches a terminal state
    if (['Delivered', 'Cancelled'].includes(tracking.tag)) {
      clearInterval(interval);
    }
  }, 30 * 60 * 1000); // Every 30 minutes
}
```

### Polling guidelines

| Shipment stage             | Recommended interval               |
| -------------------------- | ---------------------------------- |
| `Pending` / `InfoReceived` | Every 4–6 hours                    |
| `InTransit`                | Every 30–60 minutes                |
| `Delivered` / `Cancelled`  | Stop polling                       |
| `Exception`                | Every 15–30 minutes until resolved |

<Note>
  Tracking data is fetched from the courier in near-real-time. Polling more frequently than every 15 minutes is unlikely to yield new data and counts against the recommended rate limit of 10 requests per second.
</Note>

## Error handling

| Status | Meaning                 | Action                                   |
| ------ | ----------------------- | ---------------------------------------- |
| 200    | Tracking data retrieved | Process the `tag` and `checkpoints`      |
| 403    | Access denied           | The label belongs to a different account |
| 404    | Label not found         | Verify the label ID is correct           |
| 502    | Upstream service error  | Retry with exponential backoff           |

## Next steps

<CardGroup cols={2}>
  <Card title="Core Concepts" icon="book" href="/core-concepts#tracking-status-model">
    Full reference for tracking status tags and checkpoint schema.
  </Card>

  <Card title="Idempotency and Retries" icon="rotate" href="/idempotency-and-retries">
    Safe retry patterns for handling transient failures.
  </Card>
</CardGroup>
