Webhook map
notificationsdelivery(notifications.delivery)
HTTP handler setup
app/api/webhook/route.ts
Response.json, not result.response on its own: the latter is a plain object, and returning it makes even a handled delivery fail when Next.js tries to serialize the reply.
Read the body as text, not request.json(). HMAC verification runs over the exact bytes Shippo signed, so a re-serialized body never matches; the handler needs the raw string.
Pass the query through as the fourth argument. Shippo’s delivery carries no account id, so a subscription URL like ?tenantId=acme is the only way to route a delivery to a tenant; without it every delivery runs under default. That URL parameter is also one of Shippo’s own security options, alongside an IP allowlist and HMAC.
Verifying deliveries
Shippo supports optional HMAC, arranged with their support team rather than throughPOST /webhooks. When a secret is configured — webhookSecret on the plugin, or stored with set_webhook_signature — this plugin verifies the Shippo-Auth-Signature header on every delivery before any hook runs: SHA-256 over <timestamp>.<raw body>, compared in constant time, and a mismatch throws so the delivery is refused.
With no secret configured, deliveries are accepted unsigned and the handler returns signatureVerified: false, so an unverified delivery is visible rather than silently trusted.
Events
Notifications
Delivery
notifications.delivery
A Shippo webhook delivery: the { event, test, data } envelope whose data is the full track, transaction or batch object
Payload
data full type
data full type
Response data full type
Response data full type
webhookHooks example