Dispute Created Webhook

Truemed calls your endpoint when a dispute first becomes visible to you — a new chargeback, or a live inquiry you can respond to in order to pre-empt its escalation. An inquiry that later escalates into a chargeback phase fires `dispute.created` again for the chargeback. **Authentication**: Requests are HMAC-SHA256 signed. The `x-truemed-signature` header carries a timestamp and the signature in the form `t=<unix-timestamp>,v0=<hex-signature>`. Compute HMAC-SHA256 over `<t>.<raw-request-body>` with your webhook signing secret and compare the hex digest to `v0`. Sign the raw body bytes exactly as received, since re-serializing the JSON changes the bytes and breaks the signature. ## Payload The signed body is the standard Truemed envelope: - `webhook_delivery_id` - Delivery id (`dlv_…`). Retries of the same event repeat the same value; use it to deduplicate. - `event_type` - The wire event name (`dispute.created`, `dispute.updated`, or `dispute.closed`). - `data` - The full canonical dispute, the same shape returned by `GET /api/v1/disputes/{dispute_id}` — including `dispute_id`, `state`, `phase`, `reason`, `amount`, `due_by`, `counters`, and `metadata`. Null fields are omitted. Payloads carry canonical Truemed fields and the public `dispute_id` UUID only, never raw processor shapes. Always key your records on `dispute_id`. (Unsigned legacy endpoints receive the `data` object as the flat top-level body, with no envelope and no `event_type`.) The model is **notify, then fetch**: the snapshot is complete enough to act on directly, and you can re-fetch the dispute for authoritative state when a delivery is delayed or retried out of order. **Inquiries notify too, with one exception.** A live inquiry fires `dispute.created` / `dispute.updated` just like a chargeback, so you can respond to pre-empt its escalation. If the bank later drops a surfaced inquiry, the terminal `closed` state fires `dispute.closed` — so `dispute.closed` marks any terminal outcome, whether a chargeback result (`won` / `lost` / `accepted` / `expired`) or a dropped inquiry (`closed`). The only silent case is an inquiry that opens and closes between webhook deliveries — already terminal the first time Truemed sees it — which fires no webhook. ## Response Notes Return HTTP `204` with an empty body. Truemed retries failed deliveries with backoff for up to 7 days.