A webhook is an HTTP POST that Superroute sends to a URL you configure whenever something happens — an order is created, a delivery is completed, a tracking event is recorded. You build a receiver endpoint, we deliver the event there.
How delivery works
Events are queued and sent asynchronously. Each request carries an HMAC-SHA256 signature so you can verify it really came from us. Failed deliveries (non-2xx response or timeout) are retried with exponential backoff up to 5 times.
Security model
You configure a shared secret on the settings page. Every outgoing webhook is signed with that secret. Your receiver recomputes the signature and compares — if they match, the payload is genuine and untampered.
Event Catalog
Five outbound event types are available. Each has its own URL field on your settings page — you can subscribe to any subset.
order.created
Fires whenever a local-delivery order (Delivery / Pickup / P2P) is created via any path — web form, REST/GraphQL API, ecommerce platform sync, automatic rules, import rows, etc. Excludes label-service and other non-delivery order types. Skipped in batch flow when order_create_async_postback_url is also configured for the same recipient. Configure with order_create_webhook_url.
Fires on each tracking lifecycle event recorded against a package (information submitted, start delivery, delivery success, not delivered, etc.). Configure with tracking_event_webhook_url.
You can configure webhooks at two levels: at the business level (covers everything) or per customer (overrides for that specific B2B sub-account).
1. Get to the settings
Log in and go to Settings → API & Webhooks. Customer-level overrides are on the customer detail page.
2. Set the signing secret
Pick any string at least 16 characters long, ideally 32+ random bytes. This secret is what your receiver will use to verify signatures.
3. Set the event URLs you want
Fill in only the URLs for events you care about. Leave the rest blank to skip them.
webhook_sign_secretYou configure a shared secret on the settings page. Every outgoing webhook is signed with that secret. Your receiver recomputes the signature and compares — if they match, the payload is genuine and untampered.
order_create_webhook_urlFires whenever a local-delivery order (Delivery / Pickup / P2P) is created via any path — web form, REST/GraphQL API, ecommerce platform sync, automatic rules, import rows, etc. Excludes label-service and other non-delivery order types. Skipped in batch flow when order_create_async_postback_url is also configured for the same recipient. Configure with order_create_webhook_url.
order_status_change_webhook_urlFires on every order status transition — picked up, in transit, delivered, exception, cancelled. Configure with order_status_change_webhook_url.
tracking_event_webhook_urlFires on each tracking lifecycle event recorded against a package (information submitted, start delivery, delivery success, not delivered, etc.). Configure with tracking_event_webhook_url.
order_create_async_postback_urlFires once after a batch order import finishes processing. Payload contains the per-row results array. Configure with order_create_async_postback_url.
Signature & Verification
Every outgoing webhook carries a hex-encoded HMAC-SHA256 signature in the request header. Your receiver must recompute the signature over the raw request body using the shared secret, and reject the request if it does not match.
Algorithm
HMAC-SHA256 (hex)
Header name
Signature
Verification steps
Read the raw request body before any parsing or middleware modifies it.
Compute hash_hmac('sha256', rawBody, sharedSecret) and hex-encode the result.
Compare with the Signature header using a constant-time comparison (hash_equals in PHP, crypto.timingSafeEqual in Node).
Return 2xx only if signatures match. Return 401 otherwise.
func handleWebhook(w http.ResponseWriter, r *http.Request) {
body, _ := io.ReadAll(r.Body)
received := r.Header.Get("Signature")
mac := hmac.New(sha256.New, []byte(sharedSecret))
mac.Write(body)
expected := hex.EncodeToString(mac.Sum(nil))
if !hmac.Equal([]byte(received), []byte(expected)) {
w.WriteHeader(401); return
}
// ... handle event ...
w.WriteHeader(200)
w.Write([]byte("ok"))
}
require 'openssl'
require 'rack/utils'
post '/webhooks/superroute' do
raw = request.body.read
received = request.env['HTTP_SIGNATURE'] || ''
expected = OpenSSL::HMAC.hexdigest('sha256', shared_secret, raw)
halt 401 unless Rack::Utils.secure_compare(received, expected)
payload = JSON.parse(raw)
# ... handle event ...
status 200
'ok'
end
Retry & Reliability
Your endpoint should respond with a 2xx status quickly. If it returns anything else, times out, or is unreachable, the delivery is retried.
Max attempts
5 (initial + 4 retries)
Per-attempt timeout
3 seconds
Backoff
Exponential — roughly 10s, 100s, 1000s, 10000s between attempts
Build for idempotency. Because a delivery can be retried, your receiver may see the same event more than once. Use the order id / tracking number as a dedupe key — store processed event IDs for at least 24 hours.
Recommended response. Acknowledge fast (HTTP 200) and process asynchronously on your side. Avoid doing slow work synchronously inside the webhook handler — it will hit our 3-second timeout.
Signature Verifier
Paste a payload you received from us along with the Signature header value and your secret — this tool recomputes the signature in your browser (nothing leaves this page) and tells you if it matches.
Send a Test Webhook
Fire a real, properly-signed webhook from our server to a URL you provide. Use this to test that your receiver is reachable, that you parse the payload correctly, and that your signature verification logic works.
Recent Webhook Deliveries
View the most recent webhook delivery attempts on your account — both real production events and tests sent from this page. Paste your Bearer token to load.
Time
Event
URL
Status
HTTP
Attempt
Time (ms)
Test?
Actions
No webhook deliveries found yet.
Best Practices
Acknowledge fast (HTTP 200) and process work asynchronously to stay under the 3-second timeout.
Always verify the signature before trusting the payload.
Treat events as at-least-once — dedupe on the order/tracking number.
Use HTTPS endpoints with a valid certificate.
Log incoming requests so you can replay them if your handler has a bug.