Receive signed events
Webhooks are recommended automation, not a requirement. Polling remains a supported fallback and recovery path.
A webhook is a change signal
Save the deposit ID when you create the checkout. When a signed webhook
arrives, verify and deduplicate it, then retrieve
GET /v1/deposits/{depositId} whenever you need the authoritative current
state. Fulfill exactly once only when that state is succeeded; never fulfill
from the browser return or delivery order alone.
Create and activate an endpoint
- Open Webhook endpoints and add an HTTPS URL.
- Select events. Outcome events and
webhook.testare selected by default; lifecycle events are opt-in. - Copy the one-time
whsec_…signing secret. - Send a test delivery. The first successful
2xxresponse activates the endpoint.
Verify every delivery
Read the raw request bytes before JSON parsing. The signature is HMAC-SHA256 over
<timestamp>.<raw-body> and uses the current signature version v1.
import { createHmac, timingSafeEqual } from "node:crypto";
function verifyWebhook(rawBody: Buffer, timestamp: string, signature: string, secret: string) {
const ageSeconds = Math.abs(Date.now() / 1000 - Number(timestamp));
if (!Number.isFinite(ageSeconds) || ageSeconds > 300) return false;
const expected = createHmac("sha256", secret)
.update(`${timestamp}.`)
.update(rawBody)
.digest("hex");
const received = signature.startsWith("v1=") ? signature.slice(3) : "";
if (received.length !== expected.length) return false;
return timingSafeEqual(Buffer.from(received, "hex"), Buffer.from(expected, "hex"));
}Required headers:
| Header | Purpose |
|---|---|
VerifyCheckout-Event | Event type |
VerifyCheckout-Event-Id | Stable event ID for deduplication |
VerifyCheckout-Delivery-Id | This delivery attempt |
VerifyCheckout-Timestamp | Unix timestamp included in the signature |
VerifyCheckout-Signature | v1=<hex-hmac-sha256> signature |
VerifyCheckout-Api-Version | Webhook payload contract version |
VerifyCheckout-Test | Present on test deliveries |
The current webhook payload API version is 2026-06-01.
Reject stale timestamps before processing, compare signatures in constant time,
and return 2xx only after the event is durably accepted.
Events and delivery semantics
Outcome events cover completed, failed, expired, and review results. Optional
lifecycle events describe earlier progress; webhook.test verifies connectivity.
The dashboard event selector is the authoritative catalog for your account.
Deliveries are at least once. They can be duplicated, retried after non-2xx
responses, and arrive out of order. Deduplicate by event ID and make wallet
crediting idempotent by deposit ID. Do not assume the next event is newer—retrieve
the current deposit when ordering matters.
The recommended end-to-end sequence is: create checkout → save deposit ID →
send the customer to checkout → accept the signed webhook → retrieve the
deposit when confirmation is needed → fulfill only when its current status is
succeeded. See Create a Deposit for the complete flow.
Webhook payloads include environment: "live" as a compatibility field. The
current platform has one active flow; do not branch business logic on this value.
Rotate a signing secret
Create or rotate the endpoint secret in the dashboard, deploy the new whsec_…
value to your receiver, send a test delivery, and remove the old value after the
transition window. Never use an API key as a webhook secret.
Receive, verify, retry, and rotate signed deposit event deliveries.
Last updated October 6, 2026