Supercommerce API Docs
Store API

Payment Razorpay Module — Storefront

HTTP surface for the customer-side payment-verify callback used by the Razorpay Checkout SDK after the user completes payment. Verifies the HMAC signature, pins to the place-time…

HTTP surface for the customer-side payment-verify callback used by the Razorpay Checkout SDK after the user completes payment. Verifies the HMAC signature, pins to the place-time order_payment row, and funnels into the shared reconciliation path. Idempotent — the webhook may win the race and the verify call still returns 200 with the current order view.

Source: api-modules/payment-razorpay/src/controllers/store-payment-verify.controller.ts.

Razorpay is one of several payment providers. Admin enable/disable + key management and the webhook ingest surface live in docs/separated/admin/payment-razorpay.md and docs/separated/webhooks/payment-razorpay.md. This file documents the customer-callable SDK-handler endpoint only.


Conventions

Authentication

EndpointAuth
POST /store/orders/:id/payment-verifyrequired (customer session)

The order must belong to the calling customer — cross-customer ids return 404, never 403. A valid Razorpay signature only proves the payment came from a real Razorpay session against this merchant account; it does not prove the session was created for this order. The endpoint also pins to the order_payment row written at place-order (the place-time razorpay_order_id) so a leaked-and-replayed signature for a different order is rejected.

Response envelope

{
  "data": <OrderResponse>,
  "message": "Success",
  "statusCode": 200
}

Error envelope

statusCodeerrorCode examples
400BAD_REQUEST, VALIDATION_ERROR (provider mismatch, razorpay_order_id mismatch)
401UNAUTHORIZED (invalid Razorpay signature)
404NOT_FOUND (order not yours, or does not exist)
500INTERNAL_SERVER_ERROR

Endpoint

POST /store/orders/:id/payment-verify — Confirm a Razorpay-driven payment

Called by the Razorpay Checkout SDK's handler callback. The endpoint:

  1. Looks up the order by :id and rejects (404) if it doesn't belong to the caller.
  2. Rejects (400) if the order's paymentProvider !== "razorpay".
  3. Looks up the place-time order_payment row by (orderId, "razorpay", body.razorpay_order_id). If absent → 400 razorpay_order_id does not match this order (cross-order replay protection).
  4. Verifies the HMAC (razorpay_order_id|razorpay_payment_id, key_secret) matches body.razorpay_signature. If not → 401.
  5. If the order is already paid (webhook reconciled first), returns the current view as 200.
  6. Otherwise drives reconcileSuccess — transitions the parent to confirmed/paid, stamps paidAt, emits order.paid, and commits the inventory reservation.

Path params

NameNotes
idInternal order id (not the Razorpay order id)

Body

{
  "razorpay_payment_id": "pay_29QQoUBi66xm2f",
  "razorpay_order_id":   "order_DBJOWzybf0sJbb",
  "razorpay_signature":  "<hmac-sha256-hex>"
}
FieldConstraints
razorpay_payment_idtrimmed, 1..100 chars
razorpay_order_idtrimmed, 1..100 chars
razorpay_signaturetrimmed, 1..200 chars

Response 200OrderResponse (see order.md for the full shape). The response reflects the post-reconciliation state: paymentStatus: "paid", paidAt set, pendingClientAction: null.

Errors

StatusCodeWhen
400VALIDATION_ERRORBody fails zod
400BAD_REQUESTOrder was not placed via the Razorpay provider
400BAD_REQUESTrazorpay_order_id does not match the place-time row for this order
401UNAUTHORIZEDInvalid Razorpay signature
404NOT_FOUNDOrder does not exist or belongs to another customer

Idempotency — safe to retry. If the webhook reconciled first the second verify call returns the current view (200) without re-running reconcileSuccess. If two verifies race the row-level transition in reconcileSuccess serializes them.


  • orderpendingClientAction returned by POST /store/checkout/place-order is the SDK bootstrap data the storefront feeds to Razorpay Checkout; this endpoint is the back-end of that callback. See order.md.
  • webhooks/payment-razorpay — the asynchronous webhook ingest path that may reconcile before or after this verify call.

On this page