Tracking

Updated May 31, 20263 min read

Carriyo keeps shipment statuses fresh so you always know where a parcel is. From the moment a shipment leaves the warehouse through to a terminal state (delivered, returned, cancelled), Carriyo tracks it in the background. The recommended way to stay in sync is webhooks, Carriyo pushes each status change to your endpoint; you can also read the current state from the shipment record at any time.

Two methods

Carriyo uses whichever method the carrier supports, with the real-time path preferred where available.

Carrier callbacks (real-time)

Where the carrier supports it, the carrier pushes status events to Carriyo as the shipment moves (pickup, in-transit scans, delivery), and Carriyo translates each into a Carriyo-canonical status. This is the preferred method: latency is seconds rather than minutes, with no polling overhead.

How those callbacks get wired up depends on the carrier:

  • Automatic. Carriyo registers the callback with the carrier itself, nothing for you to do.
  • One-time. A single configuration step, then it's live.
  • Manual. You add Carriyo's callback URL on the carrier side, it's on the Carrier account under Callback Settings.

For carriers that support real-time updates, Carriyo additionally runs scheduled refreshes as a safety net to catch any events the carrier missed pushing.

Scheduled proactive refreshes

For carriers that don't expose webhook callbacks, Carriyo polls the carrier at scheduled intervals to fetch the current status. This is the fallback method: it works for any carrier with a status query API, but introduces refresh-cadence latency.

The refresh schedule for scheduled-only carriers is age-based:

Shipment age (from booking)Refresh frequencyWhat's tracked
0–7 daysHourlyEvery open shipment
8–14 daysDailyEvery open shipment
15–60 daysDailyOnly collected shipments

Two implications worth knowing:

  • Uncollected after 14 days. If a shipment hasn't been collected by the carrier within 14 days of booking, scheduled tracking stops. This is a long-tail efficiency cut (most abandoned shipments fall into this bucket). If you ship via a scheduled-only carrier, your code should monitor for shipments stuck in pre-collection states.
  • 60-day cap. Tracking ends 60 days after booking regardless of state. Long-tail returns or post-delivery exceptions after that window won't be reflected automatically.

These limits don't apply to real-time carriers. Those keep pushing for as long as the carrier itself produces events.

Consuming status updates

Two ways to read status, in order of preference:

  • Webhooks (push) — recommended. Subscribe a webhook in the Dashboard to the events you care about (status changes, reason-code changes, label updates), and Carriyo pushes the full updated Shipment object to your endpoint as each event fires. This is the recommended, and effectively the primary, way to stay in sync. See Webhooks.
  • GET /shipments/{shipment_id} (pull) — fallback. Fetch the full Shipment object on demand. The current status is in post_shipping_info.status, and post_shipping_info.key_milestones records when each status was reached.

What key_milestones does and doesn't capture

key_milestones is a map of status → timestamp, so it records only the first time each status was set. If a status repeats, the later timestamp isn't recorded, a shipment that goes out_for_deliveryfailed_delivery_attemptout_for_delivery keeps only the first out_for_delivery time. It also doesn't preserve the full history: the carrier's raw status and the reason code at the moment of each transition aren't kept.

So key_milestones answers "did this shipment reach status X, and when did it first get there?", not "what was the full sequence of events?" For the complete, ordered history, consume the webhook stream and record events on your side.

How it fits with other modules

  • Shipment lifecycle. The state machine that tracking events drive transitions through.
  • Webhooks. The push side of tracking-event delivery.
  • Pre-booked shipments. Pre-booked shipments use the same tracking machinery via the input_carrier to carrier-account mapping.
  • Carrier configuration. Whether a carrier supports real-time callbacks is per-carrier configuration.