Webhooks
Payload structure
Every webhook delivery follows the same envelope: metadata, changes, and a full snapshot of the affected order.
Example payload
{
"webhook_id": "wh_5fa178c2083189b168663201",
"topic": "order_status_changed",
"msg_info": {
"timestamp": "2026-05-12T18:42:01.000Z",
"shipper_id": "DEPW",
"event_origin": "hub_scan"
},
"changes": {
"status": { "from": 10, "to": 3 }
},
"order": {
"order_id": "22200041771",
"ref_order_number": "PO-12345",
"status": 3,
"service_level": "wg",
"customer": {
"first_name": "Jane",
"last_name": "Doe",
"email": "jane@example.com",
"address": {
"address1": "123 Main St",
"city": "Austin",
"state": "TX",
"zip": "78701"
}
},
"line_items": [
{
"item_id": "22200041771-1",
"sku": "SOFA-001",
"status": 3
}
],
"tracking": [
{ "event_id": 41, "timestamp": "2026-05-10T..." },
{ "event_id": 42, "timestamp": "2026-05-11T..." }
],
"created_at": "2026-05-10T14:38:43.969Z",
"updated_at": "2026-05-12T18:42:01.000Z"
}
}
Envelope fields
webhook_id
Unique ID for this delivery. Use it to deduplicate on your end.
topic
The topic that triggered this delivery. See Topics.
msg_info
Metadata about the event: timestamp, shipper_id, event_origin.
msg_info.timestamp
When the event occurred.
msg_info.shipper_id
Your SCAC or shipper identifier.
msg_info.event_origin
What triggered the event (hub_scan, dispatcher_action, customer_action, system, etc.).
changes
What changed in this event. Object of
{field: {from, to}} entries. Empty for creation events.order
Full snapshot of the affected order at this point in time. Same shape as
GET /api/orders/{id}/.Processing best practices
- Ack fast. Return 2xx immediately, then process asynchronously. Don't block on database writes or downstream API calls inside the webhook handler.
- Dedupe on webhook_id. Store processed IDs for at least 48 hours.
- Trust the order snapshot. The full order object is the source of truth; the
changesfield is a hint, not authoritative. - Verify the signature. See Verifying webhooks.