deposit.completed— the deposit has been credited to your balance.deposit.failed— the deposit has reached a terminal failure state.
data that follows the same field conventions as v3 REST API responses — camelCase fields, string amounts, RFC 3339 timestamps.
Event envelope
This routing-only example collapsesdata to an empty object. It deliberately omits the required Deposit fields shown in the complete, schema-checked examples below.
Payload
- Fiat (wire / ACH / SEPA)
- Stablecoin (USDC / USDT / EURC)
status is one of PENDING, COMPLETED, or ERROR. The webhook catalog
ships terminal deposit.completed and deposit.failed events; the v3 API
surfaces the same record with matching status via GET /v3/fx/deposits — no
normalization needed between webhook and API surfaces.Deposit resource fields
Idempotency on your side
Webhook deliveries can repeat — networks fail, your service restarts, OpenFX retries. The eventid is unique per event; persist it on first successful processing and treat repeat ids as no-ops. Do not rely on data.id (the deposit resource ID) for dedup — a single deposit can legitimately appear in multiple event deliveries if your handler returned a non-2xx on an earlier attempt.
This handler fragment assumes signature verification has already produced rawBody and omits the surrounding asynchronous route plus application-provided db, res, and processDeposit definitions.
Verification
Every event is signed in theX-OpenFX-Signature header using HMAC-SHA256 over the signed payload timestamp + "." + raw_body. Always verify with a constant-time comparator before reading any payload field. See Webhook authentication for the signing scheme, language-specific verifiers, and rotation steps.
What’s next
Webhook authentication
Signature verification with constant-time comparators.
Withdrawal webhooks
The other side of the deposit/withdrawal lifecycle.
Deposit lifecycle
How deposits transition from pending to completed.
Errors
Stable error codes and the retry triage matrix.