A webhook sends a record event to a URL on your server, TMS or ERP the moment it happens, so you don't have to poll the API.
Live endpoints (real records) need Pro for carriers ($199 a month; upgrade on Settings > Plan & billing) and are free for fuel buyers. Test endpoints, which hear about your test-mode sandbox, are free on every plan: choose Live or Test when you add an endpoint (it can't be changed later).
Go to Settings > Webhooks, and click Add endpoint. Enter an https URL and choose the events to send, or all events. Demurly shows a signing secret once: copy it to your receiver. Adding or editing an endpoint, or making a new signing secret, needs two-step sign-in (2FA) on your account. Payloads for every event and copy-paste signature checks in Node.js, Python, C# and Go are at demurly.com/docs/api/webhooks.
Events: record.sent, record.approved, record.disputed, record.escalated, record.closed, record.offer_accepted, record.cancelled, record.updated, record.comment_added, record.payment_pending, record.payment_failed, record.paid and record.payment_reversed for everyone (buyers only hear about records sent to them; record.updated means details or billed times changed); record.withdrawn for buyers, when a charge they were sent goes to another buyer or back to the carrier for review (its record is the same short tombstone the API shows; a cancellation sends record.cancelled instead); record.created, record.stopped, record.submitted, record.rejected_internal and record.reopened for carriers. New event types can be added, so ignore ones you don't know. Each is a POST with a JSON body: { id, type, created_at, livemode, record_id, sequence, occurred_at, data: { record, event } } (livemode is false for test endpoints), where event says what happened, who acted and how (for example an approval from an emailed link, with the address), and record is the same as in the API, with its times in UTC plus time_zone, start_time_local and end_time_local for the terminal's clock.
Events can arrive more than once and out of order. The id is the same on every retry, so you can ignore duplicates. sequence goes up with each event of a record: keep the highest one you've applied per record_id and ignore an event with a lower one. record is the record as it was when the event was first sent, so for the latest state, read it from the API.
Check each event's X-Demurly-Signature header: t=<unix time>,v1=<HMAC-SHA256 of "<t>.<raw body>" keyed with your secret>. Reject it if no v1 matches or t is more than 5 minutes old. There can be two v1 values: after you roll the secret, events are signed with the new and the old secret until the old one expires.
To change the secret without missing events, open the endpoint's menu and choose Roll signing secret, then pick when the old secret stops working: immediately, after 1 hour, after 24 hours (the default) or after 7 days. Copy the new secret to your receiver before then.
Answer with any 2xx status within 10 seconds. Anything else is retried after 1 minute, 5 minutes, 30 minutes, 2 hours, 6 hours, 12 hours and 24 hours. An endpoint is turned off only when it has accepted nothing for 3 days and 5 events in a row have failed every retry, so an outage of a few hours never turns it off. Your company's admins get an email and a notice. Nothing is lost: events while it's off are kept (Paused in Deliveries). Fix your receiver, turn the endpoint back on, and click Send the N missed events (or Skip them). The endpoint's menu also has Edit, Turn off / Turn on and Delete.
Deliveries shows every event sent with its body and each attempt: the headers sent, how long it took, and the status, headers and first 2 KB of what your endpoint answered. Use Send test to check your receiver, and Resend to send a failed event again.
Your systems can also manage endpoints through the API with an API key that has webhooks:write (see demurly.com/docs/api/webhooks).