razorpay-patterns-demo

Razorpay webhook idempotency + retry patterns. India-accessible mirror of stripe-payments-demo.

→ Try the live Standard Checkout demo

Endpoints

Sequence

Razorpay -> POST /api/webhook
  verify X-Razorpay-Signature (HMAC-SHA256 of raw body)
    invalid -> 400
    valid   -> extract eventId from payload.payment.entity.id (etc.)
            -> SETNX razorpay:event:{eventId} EX 86400
                  duplicate -> 200 { duplicate: true }  [no-op]
                  new       -> dispatch by event.type -> 200

Why this exists

Razorpay retries webhooks on non-2xx for up to 24 hours. Without an idempotency guard, every retry would re-fire whatever side-effects the handler does — duplicate database writes, duplicate emails, duplicate grants of paid access. The SETNX guard is a single atomic operation that makes the whole flow exactly-once from the business logic's perspective, even though the transport is at-least-once.

The pattern is identical to Stripe's: only the signing scheme differs (Razorpay uses straight HMAC-SHA256 of the body; Stripe adds a timestamp and structured Stripe-Signature header). Both demos share lib/idempotency.ts and lib/retry.ts in spirit — copy once, adapt signature verification, done.

Source: github.com/Shailesh93602/razorpay-patterns-demo