Webhooks converts events produced by Formance modules into outbound HTTP POST requests. Use it when your application must react to a Ledger transaction, a payment update, a workflow transition, or another Stack event without polling the source API.
A webhook is an asynchronous notification, not a remote procedure call. The source operation does not wait for your endpoint, and a successful source operation does not mean that your application has already processed its webhook.
How Webhooks fits into the Stack#
Three terms describe this flow:
| Term | Meaning |
|---|---|
| Event | An immutable message published by a Formance module, such as ledger.committed_transactions. |
| Delivery | The work required to send one event to one webhook configuration. If three configurations subscribe to the same event, Webhooks creates three independent deliveries. |
| Attempt | One HTTP request for a delivery. A delivery can have several attempts when the endpoint times out or returns a retryable response. |
Webhooks 2.5.0 uses a durable delivery model. It stores matching deliveries before acknowledging the event broker, sends them through a separate dispatcher, records every HTTP attempt, and exposes delivery inspection and replay APIs. This separates event ingestion from endpoint availability: a slow or unavailable endpoint does not block Webhooks from accepting later events into its delivery queue.
See Delivery lifecycle and guarantees for the exact retry policy, state transitions, duplicate and ordering semantics, retention, and replay behavior.
Create a webhook configuration#
A configuration binds an endpoint to an explicit list of event types. Event type matching is exact and case-insensitive; Webhooks stores identifiers in lowercase.
If you omit secret, Webhooks generates a 24-byte secret and returns it base64-encoded. Store it in your secrets manager: your endpoint needs it to verify every delivery.
Use an HTTPS endpoint in production. Event subscriptions do not currently support wildcards such as ledger.*; list every event type that the endpoint handles.
New configurations are active immediately. You can deactivate a configuration to stop new deliveries, reactivate it later, update its endpoint or event types, rotate its signing secret, send a test request, or delete it.
What your endpoint receives#
For every attempt, Webhooks sends:
- an HTTP
POSTrequest withContent-Type: application/json; - a normalized Formance event envelope and its module-specific
payload; - a stable delivery identifier and, when provided by the source module, an idempotency key;
- an HMAC-SHA256 signature and a fresh attempt timestamp;
- a
formance-webhook-testflag that distinguishes test requests from live events.
Webhooks waits up to 30 seconds for the endpoint response. A 2xx response marks the delivery as successful.
Other responses are either retried or marked as permanently failed according to the delivery policy.
Return a 2xx response only after your application has durably accepted the event. A common pattern is to verify the signature, reject stale requests, write the delivery to an internal queue or inbox table, and then respond. Perform slower business processing asynchronously.
Build a reliable receiver#
Your endpoint should implement four controls:
- Verify the signature against the exact raw request body before parsing JSON.
- Reject timestamps outside a short tolerance window to limit replay attacks.
- Deduplicate deliveries by
formance-webhook-idbefore applying business effects. - Process events without assuming that they arrive in source order.
The Receiving webhooks guide documents the headers, signature input, verification code, idempotency strategy, secret rotation, and test deliveries.