Webhooks
Receive and verify terminal order-status events
When an API-placed order reaches a terminal status, Voodoo Center POSTs a
signed JSON event to your configured webhook URL. This is the recommended
way to learn an order’s outcome — it is push-based, so you don’t have to poll.
When webhooks fire
A webhook is sent when all of the following are true:
- The order reaches a terminal status:
completed,failedorpartial. - The order was placed through the API (
source: "api"). Orders created in the dashboard do not trigger webhooks. - A webhook URL is configured for your account.
Payload
The request body is compact, sorted-keys JSON with these fields:
Verifying the signature
Every webhook carries a header:
where <hex> is HMAC-SHA256(webhook_secret, raw_request_body_bytes).
Verify against the raw received bytes, exactly as delivered — never against a dict you re-serialized. The signed body is compact, sorted-keys JSON, so any re-encoding (different key order, spacing or number formatting) will produce a different signature and fail verification.
Compute the same HMAC with your signing secret and compare it to the header using a constant-time comparison.
FastAPI receiver + verifier
This receiver verifies the raw bytes before parsing, uses a constant-time
compare, and returns 200 quickly:
Acknowledging, retries and timeouts
- Acknowledge with HTTP
200as soon as you have stored the event. Any non-200response (or a timeout) is treated as a failed delivery. - Failed deliveries are retried up to 3 attempts, 60 seconds apart.
- Each attempt has a 30-second timeout.
- Redirects are not followed, and your URL must be publicly routable — a server-side request forgery (SSRF) guard blocks internal/private addresses.
Because a single event may be delivered more than once (e.g. a retry after your
200 was slow to arrive), make your handler idempotent: dedupe on
order_id and treat re-delivery of an already-processed event as a no-op.
Do heavy work (fulfilling your own downstream order, sending email, etc.) in the
background and return 200 fast — a slow handler risks the 30-second timeout
and an unnecessary retry.
Configuring the URL and rotating the secret
Both the webhook settings live on the dashboard API page (they are dashboard-only, not API endpoints):
- Webhook URL — where events are
POSTed. Must be publicly reachable over HTTPS. - Signing secret — used to compute
X-Webhook-Signature. Its format iswhsec_...and it is shown once, at creation/rotation. Rotate it if it may have leaked, and updateWEBHOOK_SECRETin your receiver to match.