diagram.mmd — sequence
Payment Webhook Processing sequence diagram

Payment webhooks are HTTP POST requests that a payment gateway sends to a merchant's server to notify it of asynchronous events — authorization results, captures, refunds, disputes, and subscription renewals — without the merchant needing to poll.

The flow begins when an event occurs in the payment system (for example, a charge succeeds). The gateway constructs a JSON payload describing the event and signs it using HMAC-SHA256 with a secret shared with the merchant. The signature is sent in a request header (e.g., Stripe-Signature or X-Webhook-Signature). The gateway then delivers the POST to the merchant's configured webhook endpoint URL.

The merchant's webhook handler must process the request quickly. The first action is signature verification: extract the raw request body (before any JSON parsing, since parsing may alter byte ordering), compute the HMAC, and compare it against the header value. Any mismatch must be rejected with a 401. This prevents replay attacks and forged events. The timestamp embedded in the signature should also be checked — most implementations reject events older than five minutes.

After verification, the handler looks up the event type and dispatches it to the appropriate business logic (fulfill order, update subscription status, trigger a retry). The handler must return an HTTP 200 response promptly — ideally within 5–10 seconds — or the gateway will treat it as a failed delivery and retry. Long-running operations should be handed off to an async worker queue before returning.

If the endpoint consistently fails to acknowledge delivery, the gateway retries with exponential backoff (typically over 24–72 hours) before marking the webhook as failed and alerting the merchant. To ensure idempotency, the merchant should deduplicate incoming events by storing the event ID and skipping re-processing of already-handled IDs. The general pattern for reliable webhook delivery is covered in depth in the Webhook Delivery Flow diagram.

Free online editor
Edit this diagram in Graphlet
Fork, modify, and export to SVG or PNG. No sign-up required.
Open in Graphlet →

Frequently asked questions

Payment webhooks are HTTP POST requests a payment gateway sends to a merchant's server to notify it of asynchronous events — charge successes, captures, refunds, disputes, and subscription renewals — without requiring the merchant to poll the gateway API.
The gateway computes an HMAC-SHA256 of the raw request body using a shared secret and includes the result in a request header. The merchant recomputes the HMAC from the raw body before JSON-parsing it, then compares it to the header value. Mismatches are rejected with a 401, preventing forged or replayed events.
Always hand off long-running operations (database writes, email sends, third-party API calls) to an async worker queue before returning an HTTP 200. The webhook handler must respond within 5–10 seconds or the gateway marks delivery as failed and retries with backoff.
Common mistakes include verifying the signature after JSON-parsing (which alters byte order), not deduplicating by event ID (causing double-fulfilment on retries), fulfilling orders only on redirect rather than on webhook, and not validating the timestamp to block replay attacks.
mermaid
sequenceDiagram participant Gateway as Payment Gateway participant Endpoint as Merchant Webhook Endpoint participant Worker as Background Worker participant DB as Database Gateway->>Gateway: Payment event occurs (charge.succeeded) Gateway->>Gateway: Sign payload with HMAC-SHA256 Gateway->>Endpoint: POST /webhooks (signed payload) Endpoint->>Endpoint: Extract raw body before parsing Endpoint->>Endpoint: Verify HMAC signature Endpoint->>Endpoint: Check timestamp not older than 5 minutes alt Signature invalid or expired Endpoint-->>Gateway: 401 Unauthorized else Signature valid Endpoint->>DB: Check event ID for duplicate alt Duplicate event Endpoint-->>Gateway: 200 OK (idempotent skip) else New event Endpoint->>DB: Store event ID Endpoint->>Worker: Enqueue business logic task Endpoint-->>Gateway: 200 OK Worker->>DB: Update order / subscription state end end Gateway->>Gateway: Retry with backoff if no 2xx received
Copied to clipboard