Events & webhooks
Digital Treasury pushes an event to your endpoint whenever something happens to money you're moving. Every delivery is a signed JSON envelope, sent at-least-once from a durable outbox — so your handler must verify the signature and dedupe on the event id.
The envelope
Every event — whatever its type — arrives in the same envelope. The type tells you what happened; data is the resource in the same shape the REST API returns it.
Shape
{ "id": "evt_1f4c…",
"type": "payment_order.completed",
"created_at": "2026-07-27T14:03:11Z",
"data": { /* the resource */ } }
Headers
POST /your/endpoint Content-Type: application/json X-DigitalTreasury-Signature: 9f86d08… X-DigitalTreasury-Event: payment_order.completed X-DigitalTreasury-Delivery: 1
The signature is HMAC-SHA256 over the raw body. During a secret rotation the header carries several comma-separated signatures — accept if any matches.
Event catalogue
The events shipping on /v1 today. Vertical-specific events (for example fuel-tax remittances) only reach tenants on that vertical.
Payment orders
| Event | Fires when | data |
|---|---|---|
| payment_order.pending | An order passed risk/approval and was submitted to a rail — it's now in flight. | PaymentOrder |
| payment_order.completed | The rail settled the payment. Terminal — funds moved. | PaymentOrder |
| payment_order.failed | The order was declined — risk decline, validation failure, or a rail rejection before settlement. | PaymentOrder + failureReason |
| payment_order.returned | The payment settled and was later returned by the receiving bank (e.g. ACH R01/R03). | PaymentOrder + returnCode |
| payment_order.cancelled | A not-yet-submitted order was cancelled via the API or the console. | PaymentOrder |
Check deposits
| Event | Fires when | data |
|---|---|---|
| check_deposit.posted | A remotely-deposited check cleared and the funds posted to the ledger account. | CheckDeposit |
| check_deposit.rejected | The deposit was rejected — unreadable image, amount mismatch, or a return. | CheckDeposit + reason |
Fuel-tax remittances Fuelry vertical
| Event | Fires when | data |
|---|---|---|
| fuel_tax.remittance_cleared | A scheduled IFTA/fuel-tax remittance settled with the jurisdiction. | Remittance |
| fuel_tax.remittance_returned | A remittance was returned unpaid and needs to be re-originated. | Remittance + returnCode |
Testing
| Event | Fires when | data |
|---|---|---|
| webhook.test | You trigger a test delivery from the console — a real signed delivery to confirm your endpoint before go-live. | { message } |
Delivery & retries
At-least-once
A retry or replay reuses the same id. Deduplicate on it and make your handler idempotent — never assume exactly-once.
Backoff & dead-letter
Respond 2xx to acknowledge. Anything else is retried with backoff (1m, 5m, 30m) and dead-lettered after three attempts.
Replay
Dead-lettered events can be replayed from the console once your endpoint is healthy — no event is ever silently dropped.