Event type guides
- Deposit events cover required Travel Rule information and terminal deposit outcomes.
- Withdrawal events cover terminal withdrawal outcomes, including partially settled bulk NGN withdrawals.
- Exchange events cover order acceptance, fills, replacement, cancellation, and rejection.
data shape.
The body does not contain endpoint, delivery-attempt, signing-secret, or account
routing metadata.
Subscribe to events
Create an HTTPS endpoint withPOST /v1/partner/webhooks. An account can have
at most three enabled endpoints. Subscriptions are exact event names; wildcard
subscriptions are not supported.
deposit.action_requireddeposit.successdeposit.failedwithdrawal.successwithdrawal.partialwithdrawal.failedexchange.acceptedexchange.filledexchange.replacedexchange.cancelledexchange.rejected
wallets:view for deposit and withdrawal topics, and
trades:view for exchange topics, in addition to webhooks:manage to create,
replace, delete, or rotate an endpoint. Listing endpoints and reading delivery
history require webhooks:view. Neither webhook scope is in the default scope
set, so select them when creating the key.
event_types must be non-empty with no duplicates, enabled is required on
both create and replace, and description is limited to 255 bytes. The URL must
be HTTPS without credentials or a fragment, at most 2048 bytes, and must resolve
to a public address; a URL that fails these checks returns 422 at create or
replace time. This check resolves DNS but does not send a test delivery.
The create response contains a generated whsec_... signing secret exactly
once. Store it in your secrets manager. Rotating a secret returns
webhook_id, the new secret exactly once, secret_version, and
previous_secret_valid_until. Until that time, by default 24 hours, the
signature header contains signatures for both the new and previous secret;
accept the delivery when any one signature verifies with a secret you currently
trust. Rotating again before the overlap ends returns 409 with code
SECRET_ROTATION_IN_PROGRESS.
Manage an endpoint
Use the endpoint ID returned at creation:PUT replaces the complete endpoint configuration, including the subscription
list. To stop deliveries without deleting history, update the endpoint with
enabled: false. Deliveries already queued for a disabled or deleted endpoint
are cancelled and are not resumed if you re-enable it. Use
DELETE /partner/webhooks/{webhook_id} only when the endpoint is no longer
needed.
There is no synthetic test-delivery endpoint. Validate your receiver in staging
by completing a staging workflow that produces one of its subscribed events,
then confirm the event and delivery through the history endpoints. Endpoint
creation by itself does not test network delivery.
Delivery contract
Stabyl sends the exact JSON body as aPOST with
content-type: application/json, a user-agent of Stabyl-Webhooks/1.0, and
these headers:
2xx
within 5 seconds of the request starting. A slower response counts as a failed
attempt. Commit the inbox row and respond first; do heavier processing after
the response.
Calculate the signature over the unmodified request bytes:
whsec_ and decoding
the remaining standard Base64 text. Compare signatures in constant time and
reject timestamps outside your chosen tolerance. The examples below use five
minutes.
Node.js verification
Python verification
Retries, duplicates, and ordering
A failed initial delivery can receive up to three retries. The nominal retry delays are approximately 30 seconds, 5 minutes, and 30 minutes, with jitter. Stabyl retries transient network failures and HTTP408, 409, 425, 429,
and 5xx responses. Other 4xx responses and redirects are not retried. A
valid Retry-After response can delay a retry by up to 30 minutes.
Network ambiguity can repeat the same logical attempt, so always deduplicate by
webhook-id. No ordering is guaranteed across events, endpoints, topics, or
retries. Return any 2xx response only after your durable inbox transaction is
committed.
Use GET /v1/partner/webhook/events and
GET /v1/partner/webhook/deliveries for eventually consistent delivery
history, and GET /v1/partner/webhook/events/{event_id} or
GET /v1/partner/webhook/deliveries/{delivery_id} for one record. History is
kept for 30 days, may lag live delivery, and does not replace REST
reconciliation.