{
"id": "evt_d2a94c17f06b8e3512c7ab04e9f6130d",
"type": "shipment.updated",
"created_at": "2026-11-03T16:20:00.000Z",
"data": {
"shipment": {
"id": "7c1e0000-…",
"status": "shipped",
"card_ids": [
"0e94dc61-…"
],
"carrier": "USPS",
"service": "Priority Mail",
"service_token": "usps_priority",
"cost": 12.85,
"cover_amount": null,
"insurance_cost": 0,
"tracking_number": "9400100000000000000000",
"tracking_url": "https://tools.usps.com/go/TrackConfirmAction?tLabels=9400100000000000000000",
"created_at": "2026-11-02T18:04:11.000Z",
"status_updated_at": "2026-11-03T16:20:00.000Z",
"shipped_at": "2026-11-03T16:20:00.000Z",
"expected_delivery": null,
"delivered_at": null
}
}
}Shipment updated
We send this to your URL, once we’ve set a webhook up for your key: contact us with its name and your URL, and we give you a signing secret once. Setup, checking the signature and retries: Webhooks. A shipment made with this key changed status. Only the key that created the shipment gets it, and that key needs ship:cards as well as read:account. No part of a customer’s address is ever in an event.
Two quick changes can collapse into one event, so delivered can arrive with no shipped before it, and delivery is unordered: compare status_updated_at to tell which of two events is newer. Get a shipment always has the current status.
{
"id": "evt_d2a94c17f06b8e3512c7ab04e9f6130d",
"type": "shipment.updated",
"created_at": "2026-11-03T16:20:00.000Z",
"data": {
"shipment": {
"id": "7c1e0000-…",
"status": "shipped",
"card_ids": [
"0e94dc61-…"
],
"carrier": "USPS",
"service": "Priority Mail",
"service_token": "usps_priority",
"cost": 12.85,
"cover_amount": null,
"insurance_cost": 0,
"tracking_number": "9400100000000000000000",
"tracking_url": "https://tools.usps.com/go/TrackConfirmAction?tLabels=9400100000000000000000",
"created_at": "2026-11-02T18:04:11.000Z",
"status_updated_at": "2026-11-03T16:20:00.000Z",
"shipped_at": "2026-11-03T16:20:00.000Z",
"expected_delivery": null,
"delivered_at": null
}
}
}Headers
t=<unix seconds>,v1=<hex>. v1 is the HMAC-SHA256 of <t>.<raw request body>, keyed with your whole secret, whsec_ included. Compute it over the raw bytes before any JSON parsing, compare in constant time, and refuse a t more than 5 minutes from your clock.
The event's type.
The event's id, which stays the same on every retry.
Which try this is, from 1 to 8.
1 <= x <= 8Body
The event's id, evt_ and 32 hex characters. It never changes, including across retries, so dedupe on it.
More event types will be added without notice, so ignore a type you don't recognize.
"shipment.updated"When the thing happened, not when we sent the event.
Show child attributes
Show child attributes
Response
Answer any 2xx within 5 seconds, and do slow work after you've answered. Anything else counts as a failure, including a redirect. We retry after 1 minute, 5 minutes, 30 minutes, 2, 6, 12 and 24 hours, then stop at 8 attempts. Delivery is at-least-once and unordered, so dedupe on id.

