Test Razorpay Payments — Orders API, Paise and HMAC
Test Razorpay
in paise — not rupees
Razorpay's Orders API works in paise — India's smallest currency unit. ₹1 = 100 paise, ₹500 = 50000 paise, integer only. This mock handles the full order → redirect → signature verification flow without any Razorpay account or dashboard access.
Paise amounts
integer only, no decimals
HMAC sig
mandatory verification
0 credentials
to get started
{
"amount": 50000,
"currency": "INR",
"receipt": "receipt#0042"
}
// ₹500.00 = 50000 paise ← always integer
Razorpay is the dominant payment gateway in India. The integration uses an Orders API: you create an order on your server, open the Razorpay checkout in the browser, and after the customer pays, verify the payment signature before fulfilling. All amounts are in paise — the smallest Indian currency unit. ₹1 = 100 paise. If you send 500 instead of 50000, the customer gets charged ₹5 instead of ₹500.
Signature verification is mandatory and often skipped in tutorials. After payment, Razorpay sends razorpay_order_id, razorpay_payment_id, and razorpay_signature to your frontend. Your server must compute HMAC-SHA256(order_id + '|' + payment_id, key_secret) and compare it against the signature. Skip this check and anyone can send a fake payment callback to your server.
Razorpay supports cards, UPI, netbanking, wallets, and EMI — all from the same checkout. UPI accounts for over 70% of digital transactions in India and is instant 24/7. The payment.captured webhook fires after the payment is finalized — that's the right place to fulfill orders, not the frontend callback. This mock delivers the full Orders API flow with signature verification and webhook events.
How do paise amounts work in Razorpay?
₹1 = 100 paise
₹500 = 50000
Integer only. No decimals.
Razorpay — like Stripe, Checkout.com, and most modern gateways — works in the smallest indivisible currency unit. For INR, that is paise. Floating point numbers are unreliable for money: 0.1 + 0.2 !== 0.3 in most languages. Integers never have this problem.
Watch out
If you send 500 instead of 50000, the customer pays ₹5 not ₹500. Razorpay applies no conversion — the number you send is interpreted directly as paise.
| Rupees (₹) | Send as (paise) |
|---|---|
| ₹1 | 100 |
| ₹10 | 1,000 |
| ₹100 | 10,000 |
| ₹500 | 50,000 |
| ₹999 | 99,900 |
| ₹1,499 | 1,49,900 |
Conversion is always: rupee_amount × 100. No rounding needed — paise is already the smallest unit.
How do you verify a Razorpay payment signature?
After the customer pays, Razorpay sends three values back to your callback. You must verify them with HMAC-SHA256 before fulfilling the order.
HMAC-SHA256(
razorpay_order_id + "|" + razorpay_payment_id,
key_secret
)
The resulting hex string must match razorpay_signature exactly. If it does not, reject the callback with a 400.
Without this check, an attacker who knows your order_id can send a fake payment_id to your callback and get their order fulfilled without paying. This has happened to real apps.
razorpay_order_idThe order ID you created in step 1. Starts with order_
razorpay_payment_idThe unique ID for this payment attempt. Starts with pay_
razorpay_signatureHMAC hex string. Verify this against your own calculation. Must match exactly.
Which Razorpay payment methods use the same webhook shape?
Razorpay's checkout supports all major Indian payment methods through a single integration. Every method fires the same payment.captured webhook format.
Cards
Visa, Mastercard, Rupay
UPI
GPay, PhonePe, BHIM
Netbanking
50+ banks supported
Wallets
Paytm, MobiKwik, Freecharge
EMI
Bank and No-cost EMI
Pay Later
Simpl, LazyPay, HDFC PayLater
Unified response: Whether the customer pays with a Visa card, UPI, or a wallet, your webhook handler receives the same payment.captured event shape with method indicating which rail was used. You do not need separate handlers per method.
Integration code
curl -X POST https://mockgateway.com/api/base/razorpay/v1/orders \
-H "Authorization: Bearer YOUR_MOCK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"amount": 50000,
"currency": "INR",
"receipt": "receipt#ORD-0042",
"notes": {
"order_id": "ORD-0042",
"customer": "Priya Sharma"
}
}'
// amount = 50000 paise = ₹500.00
// INR is the only supported currency in this mockRequest parameters
Sent to POST /api/base/razorpay/v1/orders
| Parameter | Type | Required | Description |
|---|---|---|---|
amount | integer | required | Amount in smallest currency unit (paise for INR) e.g. 50000 |
currency | string | required | ISO 4217 currency (e.g. INR) e.g. INR |
description | string | optional | Payment description |
order_id | string | optional | Your order reference e.g. ORD-12345 |
Response fields
| Field | Type | Description |
|---|---|---|
id | string | Razorpay payment ID |
status | enum | Payment status |
order_id | string | Razorpay order ID |
created_at | integer | |
payment_link_id | string | Razorpay payment link identifier |
Questions about Razorpay
Other gateway templates
Looking for a different provider?
Stripe
Test Stripe payments without credentials.
PayPal
Test PayPal payments without credentials.
2Checkout
Test 2Checkout payments without credentials.
Braintree
Test Braintree payments without credentials.
Adyen
Test Adyen payments without credentials.
Square
Test Square payments without credentials.
Mollie
Test Mollie payments without credentials.
Authorize.Net
Test Authorize.Net payments without credentials.
Checkout.com
Test Checkout.com payments without credentials.
Worldpay
Test Worldpay payments without credentials.
Helcim
Test Helcim payments without credentials.
Skrill
Test Skrill payments without credentials.
Payoneer
Test Payoneer payments without credentials.