Razorpay
Accept payments with Razorpay. Use this skill when the project needs to integrate Razorpay for payments in India and international markets, UPI, subscriptions, payment links, invoicing, route (split payments), or Razorpay Checkout. Covers the Razorpay API, Checkout.js, orders, subscriptions, webhooks, and UPI.
You are a payments specialist who integrates Razorpay into projects. Razorpay is
India's leading payment gateway supporting UPI, cards, net banking, wallets, and
international payments. It dominates the Indian market and is expanding globally.
## Key Points
- Always create orders server-side before opening Checkout
- Verify payment signatures — never trust client callbacks alone
- Use notes on orders and subscriptions for your business references
- Test with Razorpay test mode and test card numbers
- Handle `subscription.halted` — it means payment retries exhausted
- Use webhooks as source of truth, not checkout callbacks
- Support UPI for Indian customers — it's the dominant payment method
- Accepting payments without signature verification
- Creating checkout without a server-side order
- Not handling subscription halted/cancelled webhooks
- Using live keys in development
- Ignoring UPI — it's how most Indian users pay
## Quick Example
```bash
npm install razorpay
```
```typescript
const refund = await razorpay.payments.refund(paymentId, {
amount: 29900, // Full or partial refund in paise
notes: { reason: 'Customer request' },
});
```skilldb get payment-services-skills/razorpayFull skill: 223 linesRazorpay Payment Integration
You are a payments specialist who integrates Razorpay into projects. Razorpay is India's leading payment gateway supporting UPI, cards, net banking, wallets, and international payments. It dominates the Indian market and is expanding globally.
Core Philosophy
Orders before payments
Razorpay uses an order-first flow. Create a server-side order, pass the order ID to the client checkout, and verify the payment signature on completion. Never accept a payment without creating an order first.
UPI is essential for India
UPI (Unified Payments Interface) accounts for the majority of digital payments in India. Razorpay's integration handles UPI intent flows, QR codes, and collect requests natively.
Verify signatures, always
Every successful payment must be verified by checking Razorpay's signature using your key secret. Without verification, anyone can forge a payment callback.
Setup
Install
npm install razorpay
Initialize
import Razorpay from 'razorpay';
const razorpay = new Razorpay({
key_id: process.env.RAZORPAY_KEY_ID,
key_secret: process.env.RAZORPAY_KEY_SECRET,
});
Key Techniques
Create order + Checkout.js
// Server: create order
const order = await razorpay.orders.create({
amount: 29900, // INR 299.00 in paise
currency: 'INR',
receipt: `order_${Date.now()}`,
notes: { userId: '123', plan: 'pro' },
});
<!-- Client: Razorpay Checkout -->
<script src="https://checkout.razorpay.com/v1/checkout.js"></script>
<script>
const options = {
key: 'rzp_live_xxx',
amount: order.amount,
currency: order.currency,
order_id: order.id,
name: 'Your App',
description: 'Pro Plan',
handler: async (response) => {
// Send to server for verification
await fetch('/api/razorpay/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
orderId: response.razorpay_order_id,
paymentId: response.razorpay_payment_id,
signature: response.razorpay_signature,
}),
});
},
prefill: { email: 'user@example.com' },
theme: { color: '#d4a843' },
};
const rzp = new Razorpay(options);
rzp.open();
</script>
Verify payment signature
import crypto from 'crypto';
export async function POST(req: Request) {
const { orderId, paymentId, signature } = await req.json();
const expectedSignature = crypto
.createHmac('sha256', process.env.RAZORPAY_KEY_SECRET)
.update(`${orderId}|${paymentId}`)
.digest('hex');
if (expectedSignature !== signature) {
return Response.json({ error: 'Invalid signature' }, { status: 400 });
}
// Payment verified — grant access
await grantAccess(orderId);
return Response.json({ status: 'verified' });
}
Subscriptions
// Create plan
const plan = await razorpay.plans.create({
period: 'monthly',
interval: 1,
item: {
name: 'Pro Plan',
amount: 29900,
currency: 'INR',
description: 'Monthly Pro subscription',
},
});
// Create subscription
const subscription = await razorpay.subscriptions.create({
plan_id: plan.id,
total_count: 12,
quantity: 1,
notes: { userId: '123' },
});
// Cancel subscription
await razorpay.subscriptions.cancel(subscriptionId);
Payment Links
const paymentLink = await razorpay.paymentLink.create({
amount: 29900,
currency: 'INR',
description: 'Pro Plan',
customer: { email: 'user@example.com' },
callback_url: 'https://yourdomain.com/success',
notes: { userId: '123' },
});
// Share paymentLink.short_url with the customer
Refunds
const refund = await razorpay.payments.refund(paymentId, {
amount: 29900, // Full or partial refund in paise
notes: { reason: 'Customer request' },
});
Webhook Processing
| Event | Action |
|---|---|
payment.authorized | Log authorization |
payment.captured | Grant access |
payment.failed | Notify user |
subscription.activated | Set up subscription |
subscription.charged | Renew access |
subscription.cancelled | Revoke access |
subscription.halted | Restrict access (payment failures) |
refund.processed | Adjust access |
import crypto from 'crypto';
export async function POST(req: Request) {
const body = await req.text();
const signature = req.headers.get('x-razorpay-signature');
const secret = process.env.RAZORPAY_WEBHOOK_SECRET;
const expectedSig = crypto.createHmac('sha256', secret).update(body).digest('hex');
if (expectedSig !== signature) {
return new Response('Invalid signature', { status: 401 });
}
const event = JSON.parse(body);
switch (event.event) {
case 'payment.captured':
const userId = event.payload.payment.entity.notes?.userId;
await grantAccess(userId);
break;
case 'subscription.cancelled':
await revokeAccess(event.payload.subscription.entity.notes?.userId);
break;
}
return new Response('OK');
}
Best Practices
- Always create orders server-side before opening Checkout
- Verify payment signatures — never trust client callbacks alone
- Use notes on orders and subscriptions for your business references
- Test with Razorpay test mode and test card numbers
- Handle
subscription.halted— it means payment retries exhausted - Use webhooks as source of truth, not checkout callbacks
- Support UPI for Indian customers — it's the dominant payment method
Anti-Patterns
- Accepting payments without signature verification
- Creating checkout without a server-side order
- Not handling subscription halted/cancelled webhooks
- Using live keys in development
- Ignoring UPI — it's how most Indian users pay
- Not implementing refund handling
Install this skill directly: skilldb add payment-services-skills
Related Skills
Square
Accept payments with Square. Use this skill when the project needs to integrate Square for online payments, in-person POS, invoicing, subscriptions, catalog management, or omnichannel commerce. Covers the Square API, Web Payments SDK, Orders, Subscriptions, Invoices, Catalog, and webhooks.
Stripe
Accept payments and manage subscriptions with Stripe. Use this skill when the project needs to integrate Stripe for one-time payments, recurring subscriptions, checkout sessions, payment intents, customer management, invoicing, webhook processing, billing portal, metered billing, or payment method management. Covers the Stripe API, Stripe.js, Checkout, Elements, Billing, and webhooks.
Adyen
Accept payments with Adyen. Use this skill when the project needs to integrate Adyen for online payments, drop-in checkout, tokenization, subscriptions, payouts, or omnichannel payment processing. Covers Adyen Checkout API, drop-in components, webhooks, and recurring payments.
Braintree
Accept payments with Braintree (PayPal). Use this skill when the project needs to integrate Braintree for credit card payments, PayPal, Venmo, Apple Pay, Google Pay, subscriptions, vaulting payment methods, or drop-in UI. Covers the Braintree SDK, Drop-in UI, hosted fields, vaulting, subscriptions, and webhooks.
Checkout Com
Accept payments with Checkout.com. Use this skill when the project needs to integrate Checkout.com for online payments, hosted payment pages, tokenization, subscriptions, payouts, or multi-currency processing. Covers Checkout.com Unified Payments API, Flow (hosted pages), webhooks, and saved cards.
Coinbase Commerce
Accept cryptocurrency payments with Coinbase Commerce. Use this skill when the project needs to integrate Coinbase Commerce for Bitcoin, Ethereum, USDC, or other crypto payments. Covers Coinbase Commerce API, charges, checkout links, webhooks, and payment verification.