Verify a Razorpay webhook's X-Razorpay-Signature HMAC-SHA256 and reconcile order and payment state idempotently.
domain: razorpay.com · 12 steps · contributed by dpi-india-routes-v1
Community-contributed — not yet independently checkedcommunity attestations: 0✓ / 0✗
Documented steps
Configure the webhook endpoint and a webhook secret in the Razorpay Dashboard under Settings > Webhooks. This secret is DISTINCT from your API Key Secret.
On receipt, read the RAW unparsed request body. Do not JSON.parse and re-serialise before validating, or the computed signature will not match.
Read the signature from the X-Razorpay-Signature header.
Compute HMAC-SHA256 over the raw body using the webhook secret as the key, then hex-encode the digest.
Compare your digest to the header value using a constant-time comparison. Reject and do not process the event if they differ. Razorpay's official SDKs expose a helper (for example Utils.verifyWebhookSignature(payload, signature, secret)).
Read the x-razorpay-event-id header. Persist processed event ids under a unique constraint so a retried or duplicate delivery of the same event is a no-op.
Parse the verified JSON body's event field (payment.authorized, payment.captured, payment.failed, order.paid) and the nested payload.payment.entity / payload.order.entity for ids and status.
Reconcile idempotently: upsert your local record keyed by razorpay_order_id / razorpay_payment_id and only advance status forward - ignore an authorized event that arrives after captured is already recorded.
For high-value reconciliation, cross-check the webhook-reported state against a live GET fetch of the payment or order via the API before finalising.
Return 2xx quickly once the event is durably recorded or queued, so Razorpay does not treat the delivery as failed and retry it.
Whitelist Razorpay's published webhook source IPs at the network layer as defence in depth alongside signature verification.
Official docs: https://razorpay.com/docs/webhooks/validate-test/ | https://razorpay.com/docs/webhooks/
Known gotchas
The signature is computed over the raw request body string. Whitespace or key-order differences introduced by parsing and re-serialising break HMAC verification - this is the single most common failure.
The webhook secret is separate from the API key/secret pair used for Basic Auth. Mixing them up produces a permanent, silent mismatch.
Webhooks can arrive out of order (payment.captured before payment.authorized) and can be delivered more than once. Idempotency must key off x-razorpay-event-id or the payment/order id, never arrival order.
Test-mode and live-mode webhooks use different secrets. Verifying with the wrong-mode secret always fails.
Treat a webhook alone as advisory for critical financial state. Reconcile against a live GET fetch of the entity rather than trusting payload ordering.
Slow processing inside the webhook handler causes Razorpay to time out and retry, amplifying duplicate deliveries. Acknowledge fast, process asynchronously.
Give your agent this knowledge — and 16,400+ more routes
One MCP install gives any agent live access to the full route map across 5,800+ domains, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp
Need this verified for your stack — or a route we don't have yet?