Fires the first time an order leaves pending/reserved and enters fulfillment — at
most once per order. Later internal transitions do not repeat it. data.status is always
processing.
Treat it as a progress signal: the wallet reservation is being spent and a terminal event
(order.fulfilled or order.failed) will follow. Nothing needs to change in your system
yet unless you surface progress to your own users.
Delivery contract — every Xegora webhook is delivered the same way:
| Header | Value |
|---|---|
X-Xegora-Event-Id | Your dedupe key — the envelope id without dashes (32 lowercase hex). Identical on every retry. |
X-Xegora-Timestamp | Unix seconds at send time; reject if more than 5 minutes from your clock. |
X-Xegora-Signature | v1=<64 lowercase hex> — HMAC-SHA256 over {X-Xegora-Timestamp}.{X-Xegora-Event-Id}.{raw body} keyed with your endpoint's xgwh_… secret. |
X-Xegora-Delivery-Contract | xegora-webhook-at-least-once-v1 |
Acknowledge with any 2xx within 5 seconds; redirects are not followed, and endpoints
must be public HTTPS on port 443. Delivery is at-least-once: dedupe durably by
X-Xegora-Event-Id. A non-2xx or timeout is retried with exponential backoff (5 s,
doubling per attempt — up to 8 attempts over roughly 11 minutes), except that a 4xx other
than 401/403/404/408/410/425/429 counts as a permanent rejection and stops retries.
Exhausted or rejected deliveries are parked for operator review — never silently dropped.
Retries can interleave across events, so order by the payload's occurredAtUtc or re-read
the API as the source of truth. Fulfillment artifacts and buyer personal data never appear
in webhook payloads.
200Acknowledged — any 2xx accepts the event. Non-2xx responses and timeouts trigger the retry schedule described above.