Prerequisites
- A publicly reachable HTTPS endpoint (no plain HTTP: signatures protect integrity, TLS protects in-transit confidentiality)
- An admin user in the OpenFX dashboard
- A handler that can hold a small amount of state (deduplication of replayed events)
Step 1: Register your endpoint
1
Open the dashboard
Sign in to app.openfx.com/webhooks, your organization’s Webhooks settings.
2
Add a webhook URL
Enter your HTTPS URL. The dashboard supports one webhook URL per environment (Live and Sandbox have separate registrations; see Environments).
3
Subscribe to event types
Every event type name follows a dot-namespaced, lowercase
{product}.{resource}.{action} convention (fx. for FX), so you can route on a whole family by prefix (e.g. fx.withdrawal.*) or on individual event types (e.g. fx.deposit.completed). See Deposit webhooks, Withdrawal webhooks, and Trade webhooks for the exact event types each resource emits.Subscribe to whichever events your integration needs; if in doubt, subscribe to everything.4
Copy the signing key
The dashboard generates a per-org signing key on first registration. Store it as
OPENFX_WEBHOOK_SIGNING_KEY in your secrets manager. Treat it like a database password: anyone with it can mint events that pass signature verification.Step 2: Build the handler
Minimum viable handler: read the raw body, verify the signature, deduplicate by eventid, dispatch.
Node / Express
Python / Flask
Step 3: Acknowledge fast, process async
Return2xx within a few seconds. Long-running processing (database writes, downstream API calls, sending the user an email) belongs on a queue:
2xx. The combination of “ack fast” + “process via queue” + “deduplicate by event id” makes retries safe.
Step 4: Test in Sandbox
The fastest path to a working integration is to fire events from Sandbox before going to Live:- Use your Sandbox API key (
sandbox_-prefixed), which is bound to the Sandbox environment. If you sendX-App-Mode, set it to SANDBOX; omitting it also selects Sandbox. - Trigger a Sandbox deposit or withdrawal yourself from Sandbox mode in the dashboard. Sandbox doesn’t move real money, so there’s no amount to worry about.
- Verify your handler receives the signed event and returns
2xx. - Check the dashboard’s delivery log for the event.
Event envelope shape
Every webhook delivery uses these top-level routing fields. This abbreviated shape collapsesdata to an empty object and omits the required Deposit or Withdrawal fields; use the complete, schema-checked event examples on the payload pages when implementing a handler.
Field names are
camelCase; monetary amounts are strings (e.g. "1000.00"); timestamps are RFC 3339 with millisecond precision and a trailing Z. This matches the v3 REST API conventions exactly, deposit, withdrawal, and trade settlement events alike.
The field-level reference is in:
Polling fallback
Webhooks are the primary delivery channel, but if your handler is briefly unreachable, OpenFX retries. As a defense-in-depth, periodically reconcile against the read endpoints:GET /v3/fx/depositsfor missed deposit events; pair with Deposits for the state model and reconcilable fieldsGET /v3/fx/withdrawalsfor missed withdrawal events; use the adaptive-backoff pattern on the Withdrawals page so a slow rail doesn’t burn your rate-limit budget
Common mistakes
- Parsing the body before verifying. JSON re-serialization changes whitespace and key order, which changes the HMAC digest. Always verify against the raw request body.
- String comparison on signatures. Use a constant-time comparison (
crypto.timingSafeEqual,hmac.compare_digest). Standard===leaks timing. - Not deduplicating by event
id. A handler that 500s on the first delivery and 200s on the redelivery will receive the same event twice. Storeevent.idserver-side and short-circuit duplicates. Retain event IDs for at least 48 hours. OpenFX retries failed deliveries on a backoff curve within that window; older IDs can be safely purged. - Long-running work before acking. A 30-second database write turns into a webhook timeout, which turns into a retry, which lands you with three copies of the same work in flight. Ack first, process async.
- Mixing Sandbox and Live signing keys. Wire the key from environment config, not a constant.
What’s next
Webhook authentication
Signature scheme + verification code samples.
Deposit webhooks
Event shape for fiat and stablecoin deposits.
Withdrawal webhooks
Event shape for withdrawal completion.
Trade webhooks
Event shape for ready-to-settle, settled, and reversed trades.
Payout webhooks
Event shape for payout status changes.
Verified accounts
Pre-configure withdrawal accounts the webhooks will report on.