Overview
The controlRazorpay action opens the Razorpay Checkout modal (web) or the Razorpay SDK's payment screen (Android/iOS) for a pre-created Razorpay order. It handles the entire payment UI and returns the payment result — success with signature credentials, or failure with an error — to your defined callback action chains.
Note: Server-side order creation is required. Razorpay requires that an Order ID be created on your server using the Razorpay Orders API before the checkout is opened. The controlRazorpay action does not create the order — call your order-creation API via a Data Source action first, then pass the returned order_id to this action.
Prerequisites
Warning: Complete these steps before using the action:
Parameters
| Parameter | Type | Required | Default | Description |
| orderId | string | Required (required) | — | The Razorpay order ID returned by your server-side order creation API. Format: order_XXXXXXXXXXXXXXXXXX. Typically bound to a data source response: {{ ds_createOrder.response.id }}. |
| amount | number | Optional (optional) | From order | Payment amount in the smallest currency unit (paise for INR, cents for USD). If omitted, the amount is read from the Razorpay order object automatically. Providing it here is optional but recommended for display validation. |
| currency | string | Optional (optional) | "INR" | ISO 4217 currency code. Must match the currency of the Razorpay order. Razorpay supports INR natively; international currencies require activation on your account. |
| prefill.name | string | Optional (optional) | — | Customer name to pre-fill in the checkout form. |
| prefill.email | string | Optional (optional) | — | Customer email to pre-fill. Pre-filled values reduce checkout time and improve conversion. |
| prefill.contact | string | Optional (optional) | — | Customer phone number in E.164 format (e.g. +919876543210). Used for OTP and UPI verification. |
| theme.color | string | Optional (optional) | "#528FF0" | Hex colour code for the Razorpay checkout modal's header and CTA button. Use your brand's primary colour to maintain visual consistency. |
| onSuccess | ActionChain | Optional (optional) | — | Fires when payment completes successfully. Receives { razorpay_payment_id, razorpay_order_id, razorpay_signature }. You must verify the signature server-side before fulfilling the order. |
| onFailure | ActionChain | Optional (optional) | — | Fires when payment fails or the user cancels. Receives { code: string, description: string, source: string, step: string, reason: string }. |
Payment Flow Architecture
The recommended end-to-end flow:
Create order server-side: Fire a Data Source action that calls your backend endpoint (POST /orders). Your server calls the Razorpay Orders API and returns the
order_id.Open Razorpay checkout: In the
onSuccessof the order creation data source, fire thecontrolRazorpayaction with the returnedorder_id.Verify payment server-side (onSuccess callback): Pass the three Razorpay signature fields to another Data Source action that calls your backend's verification endpoint. Only fulfil the order after server-side verification passes.
Handle failure (onFailure callback): Show an error notification with the failure reason. Optionally offer a retry button that re-opens checkout with the same order ID (Razorpay orders support multiple payment attempts).
Examples
Open Razorpay checkout after order creation
{ "actionType": "controlRazorpay", "payload": { "orderId": "{{ ds_createOrder.response.id }}", "amount": "{{ ds_createOrder.response.amount }}", "currency": "INR", "prefill": { "name": "{{ appUser.name }}", "email": "{{ appUser.email }}", "contact": "{{ appUser.phone }}" }, "theme": { "color": "#1A3C5E" }, "onSuccess": [ { "actionType": "triggerDataSource", "payload": { "dataSourceId": "ds_verifyPayment", "params": { "paymentId": "{{ onSuccess.razorpay_payment_id }}", "orderId": "{{ onSuccess.razorpay_order_id }}", "signature": "{{ onSuccess.razorpay_signature }}" } } }, { "actionType": "showNotification", "payload": { "type": "success", "title": "Payment successful!", "description": "Payment ID: {{ onSuccess.razorpay_payment_id }}" } } ], "onFailure": [ { "actionType": "showNotification", "payload": { "type": "error", "title": "Payment failed", "description": "{{ onFailure.description }}" } } ] } }
Frequently Asked Questions
How do I test Razorpay payments without real money?
Use a Test Mode Key ID (rzp_test_...) in App Settings. In the checkout modal, use Razorpay's test card number 4111 1111 1111 1111 (any future expiry, CVV 111). For UPI, use success@razorpay. Payments made with a test key are not real transactions and do not move money. Switch to a Live Mode Key ID only when deploying to production.
Why must I verify the payment signature server-side?
The razorpay_signature returned in the onSuccess callback is a SHA-256 HMAC of the payment ID and order ID, signed with your Razorpay Key Secret. Client-side verification is impossible and insecure — an attacker could forge a success callback without making a real payment. Always call your backend to verify the signature using your Key Secret before marking the order as paid.
Can the user retry a failed payment?
Yes. A Razorpay order remains active (in created state) after a failed payment attempt. You can reuse the same orderId in another controlRazorpay action call — the user will be taken back to checkout for the same order. Razorpay supports multiple payment attempts per order until the order either succeeds or expires (default: 30 minutes).