Skip to main content

Overview

Webhooks let your server receive real-time notifications when deposits arrive, sweeps complete, and withdrawals broadcast / confirm / fail. They are the recommended way to drive your integration — polling is a fallback for when a delivery is missed.

How it works

  1. You register a webhook URL and pick which event types it should receive (one URL can subscribe to any subset of the six events).
  2. The gateway shows you a one-time signing secret at creation time. Copy it now — it's never displayed again.
  3. When a matching event fires, the delivery worker POSTs a signed JSON envelope to your URL. It expects a 2xx response within 10 seconds.
  4. Non-2xx (or timeouts / network errors) trigger an exponential-ish retry — up to 7 attempts spanning ~38 hours. See Retries & delivery log.
  5. After the final retry fails, the row is marked failed (dead) and stops auto-retrying. You can manually requeue it from your dashboard's delivery log.

Registering a webhook

Go to the Webhooks page in your dashboard:

  1. URL — must be HTTPS. The gateway only delivers to https:// URLs.
  2. Subscribed events — tick the events you care about. Common starting set: deposit.confirmed + withdrawal.confirmed + withdrawal.failed.
  3. Signing secret — shown once after creation. Store it in your secrets manager immediately. If you lose it, you must delete the webhook and create a new one — there is no "reveal" or "rotate" endpoint.

A single account can register multiple webhooks. Each gets its own signing secret. Useful when you want one URL for production events and another for staging-mirror or alerting.

Lifecycle of one delivery

Every event triggers one row in tbl_webhook_deliveries per subscribed webhook, then moves through this state machine:

StatusMeaning
pendingAwaiting the next worker tick (every ~10 s). A brand-new delivery starts here, and a delivery that failed an attempt but still has retries left returns here — with attempt_count bumped and a future next_retry_at.
deliveringWorker claimed the row and is about to POST.
deliveredReceiver responded 2xx. Final state.
failedAll 7 attempts exhausted. Final state — you'll need to manually requeue if needed.

There is no separate "retrying" status — a row waiting to be retried sits in pending. The dashboard's delivery log shows the current state of every delivery, the most recent HTTP response status code, and a "retry" button for failed rows.

What you'll need to implement

Every webhook receiver should:

  1. Verify the signature on the raw request body — see Verifying signatures. Reject the request with 401 if it doesn't match.
  2. Respond 2xx quickly — within 10 seconds, ideally under 1 second. Persist the event to your queue or store first, process asynchronously.
  3. Dedupe by the envelope's id — the same delivery row's id is constant across all retries, so id is the right primary key to dedupe on.
  4. Tolerate unknown fields — payloads MAY gain new optional fields without bumping api_version. Don't fail validation on extras.

What you'll find in this section

  • Events — the six event types, when each fires, and the exact shape of each payload.
  • Verifying signatures — canonical string, HMAC algorithm, and copy-paste verifier recipes in Python, Node.js, and PHP.
  • Retries & delivery log — backoff schedule, success/failure criteria, and how to debug from the dashboard.