Receive a Razorpay webhook delivery
Verifies the HMAC-SHA256 signature (X-Razorpay-Signature) over the raw request body against RAZORPAY_WEBHOOK_SECRET, timing-safe. A valid, fresh event (deduplicated on X-Razorpay-Event-Id) is persisted to a pending-events store and acknowledged; nothing is processed inline — settlement/lifecycle processing is a future milestone (M4b, see docs/CLAIMS.md). Not registered at all (404) when RAZORPAY_WEBHOOK_SECRET is not configured.
Authorizations
Caller API key issued by scripts/generate-api-key.ts. Sent as Authorization: Bearer . Verified against a stored SHA-256 hash in constant time by packages/api/src/auth/StaticKeyAuthenticator.ts. Required on every route except GET /health. See /api-reference/authentication.
Headers
hex(HMAC-SHA256(rawBody, RAZORPAY_WEBHOOK_SECRET))
Required once the signature has verified; a request missing it is rejected even with a valid signature.
Body
Request payload for POST /webhooks/razorpay — Razorpay's own webhook envelope, forwarded verbatim. Shape and fields vary by event type; this schema only documents the fields this route itself reads (event, payload.payment.entity.id, payload.refund.entity.id) for audit metadata extraction. The full payload is persisted as-is for later processing (M4b) and is not otherwise validated against this schema at runtime — signature verification (X-Razorpay-Signature) is what actually authenticates a request, not payload shape.
Response
Verified event accepted (fresh) or acknowledged (duplicate).
Response body for POST /webhooks/razorpay on a 200. "accepted" means this event id was fresh and has been persisted to the pending-events store. "acknowledged" means this event id had already been recorded (a replay/duplicate delivery) — it was not persisted or reprocessed again.
accepted, acknowledged