Accept payments with Razorpay in DaloyJS
Razorpay is the default payment stack for India — UPI, cards, netbanking, wallets, EMI, and BNPL through one API. This guide uses the official razorpay Node SDK with the Orders flow, the SDK's built-in validatePaymentVerification for the post-checkout callback, and validateWebhookSignature for IPN.
What you should know up front
- Two signatures, not one. Razorpay signs two different things: (1) the client-side checkout result — verify with
validatePaymentVerificationusing your key secret; (2) the server-side webhook — verify withvalidateWebhookSignatureusing your webhook secret. They're different secrets and different payloads. - Orders are the source of truth, not raw payments. Create an Order on your server, hand
order_idto Checkout, then verify the callback. Skipping the Order step is technically allowed but loses you idempotency, reconciliation, and the "late authorisation" protection. - Amounts are paise. ₹500.00 →
{ amount: 50000, currency: "INR" }. Don't pass floats — the API rejects them. - Webhook verification needs the raw body.
JSON.parse+JSON.stringifychanges byte order, which breaks the HMAC. Read the request body as a string before parsing it. - Don't roll your own HMAC. The SDK exposes both verifiers as plain helpers; using them keeps you aligned when Razorpay tweaks the algorithm or adds new fields.
1. Provision
- Sign in to the Razorpay dashboard.
- Account & Settings → API Keys → Generate Test Key. Save the
key_idandkey_secret— the secret is shown once. - Account & Settings → Webhooks → Add new. Point it at your DaloyJS endpoint and set a webhook secret. Subscribe to at least
payment.captured,payment.failed,order.paid, andrefund.processed. - Activate the methods you need (UPI/cards are on by default; netbanking and wallets typically need explicit enabling).
2. Install
3. Environment variables
4. Plugin
The verifier helpers live at razorpay/dist/utils/razorpay-utilsin the published bundle — Razorpay's own README points there. They're plain functions over node:crypto; no SDK instance needed.
5. Create an order
The frontend uses Razorpay Checkout JS with the orderId from this endpoint plus your public key_id.
6. Verify the client callback
After a successful payment, Checkout JS posts { razorpay_order_id, razorpay_payment_id, razorpay_signature } back to your client. Forward to the server and verify before doing anything:
7. Webhook
Always return 200 once the signature checks out — even for events you don't handle. Razorpay retries non-2xx responses with exponential backoff for up to 24 hours.
8. Refunds
Runtimes
The razorpay SDK ships CJS and depends on Node's https module — it runs on Node 18+ but is not edge-runtime compatible. For Cloudflare Workers or Vercel Edge, hit https://api.razorpay.com/v1 directly with fetch and Basic auth (Authorization: Basic base64(key_id:key_secret)). The two signature helpers are pure HMAC and easy to reimplement with crypto.subtleif you don't want the bundled ones.
Errors
Razorpay throws errors with a structured error.error object containing code, description, field, and reason. Map them through problem+json with the Razorpay code on the type field so reconciliation tools can match them later.
Modernisation notes
- Use Orders, not bare payment links. The Orders flow gives you a server-side anchor for idempotency, lets Checkout JS show the right amount, and unlocks
order.paidwebhooks that fire even when the customer closes the tab before the success callback. - Verify both signatures. The client callback signature stops forged success posts from the browser; the webhook signature stops spoofed IPNs. Skipping either is a foot-gun.
- Don't fulfil on the client callback alone. The signature proves the call came from Razorpay, but
status: createdisn'tcaptured. Always re-fetch the payment (or wait for the webhook) before flipping an order to paid. - Use Promises, ignore the callback API. Every method on the SDK returns a Promise. The error-first callback parameter still works but exists for legacy code only.
See also the payments overview, Tap Payments guide, PayTabs guide, and problem+json errors.