Receive and verify webhooks
Outcome: a receiver verifies Thor’s raw-body signature, durably deduplicates an event, acknowledges it quickly, and processes it outside the request path.
Prerequisites: a public HTTPS receiver, durable queue or inbox table, secret storage, and the exact WebhookEventType values needed by the integration.
Create a subscription
Store the returned secret in a secret manager. Rotate it by replacing the subscription when your operational policy requires rotation.
Delivery contract
Thor sends an HTTP POST with an application/json event envelope. Important headers are:
Thor-Signature:t=<unix-seconds>,v1=<hex-hmac>.Thor-Topic: the dot-notated event topic.Thor-Project: the project identifier.Thor-Webhook-Id: the subscription ID.Thor-Triggered-At: an ISO 8601 timestamp.Thor-Event-Id: the delivery ID.
The body contains id, object, created, idempotency_key, data, and type. Treat fields you do not recognize as forward-compatible additions.
Verify before parsing
- Read the raw request bytes. Do not parse and reserialize them first.
- Parse
tandv1fromThor-Signature. - Reject timestamps outside a short tolerance appropriate for your system.
- Compute HMAC-SHA256 over
<t>.<raw-body>using the subscription secret. - Hex-encode the digest in lowercase and compare it to
v1with a constant-time comparison. - Only then parse and dispatch the event.
Respond quickly and process idempotently
Return a 2xx response within 30 seconds. Queue slow work and acknowledge after the event has been durably accepted. Deduplicate with idempotency_key or Thor-Event-Id; webhook consumers must be safe to run more than once.
Non-2xx, timeout, and network responses are recorded on the delivery. Inspect deliveries through the subscription or webhookDelivery. To resend a delivery, call webhookDeliveryResend; the resend keeps the original idempotency key.
Receiver example
This Node request handler assumes rawBody is the exact byte sequence received and headers contains normalized lower-case keys:
Implement insertInboxOnce with a unique durable key and enqueue processing in the same durable workflow. Do not parse JSON before signature verification.
Verify
Send a captured test delivery through the receiver, confirm one inbox row and one queued job, then resend it and confirm no second business action occurs. Test a changed body, stale timestamp, wrong secret, and missing header; each must be rejected.