# Razorpay

Source: https://developers.swell.is/app-guides/razorpay

The Razorpay app makes Razorpay the payment gateway for credit cards in your Swell store. Shoppers pay in Razorpay's window in Swell's hosted checkout, and Razorpay saves their card. The app captures payments when Swell takes them, charges the saved card for subscription renewals and later charges, and refunds payments from the order.

Card details stay with Razorpay. Swell keeps Razorpay's token for the card with its brand, last four digits and expiry date. Before the app takes any money, it checks the Razorpay payment against the Swell payment's amount, currency and card method, and it never takes the money twice for one Swell payment, even when a request is retried.

## How it works

| When | What the app does |
| --- | --- |
| A shopper pays by card and clicks Complete order | Creates a Razorpay order for the total and opens the Razorpay window, with cards only. When the shopper pays, Razorpay authorizes the payment and saves the card, and the app checks the payment's signature before the order is placed. |
| The order is placed | With Charge automatically on under Settings > Orders, which is the default, captures the payment. With it off and Require payment authorization on, the payment is only authorized. |
| You click Charge order on an order with an authorized payment, within 5 days | Captures the authorization for its full amount. |
| You charge an order that has no usable authorization | Charges the shopper's saved card with a new Razorpay payment. The payment shows Pending until a workflow records it as Paid, usually within seconds. |
| A subscription renews | Charges the saved card the same way, with no checkout for the customer. |
| You refund a payment | Refunds the amount, in full or in part, to the card through Razorpay. |
| Every 30 minutes | Finishes saved card charges that are still pending 30 minutes after they started, up to 10 per run, for example when their workflow failed. |

## Before you begin

- A Razorpay account and its API keys, from **Account & Settings > API Keys** in the Razorpay Dashboard. Test keys start with `rzp_test_` and live keys with `rzp_live_`.
- Recurring card payments enabled on your Razorpay account. The app saves every card at checkout so it can be charged again, and without recurring payments Razorpay can't save it.
- Orders in a currency that Razorpay accepts for recurring card payments. The app sends the order's currency to Razorpay as it is, and Razorpay decides which cards and currencies can be saved and charged again.
- An email address and a phone number for each shopper. Razorpay needs both to save the card. The app takes the phone number from the customer's account, or from the checkout's billing or shipping address.
- Swell's hosted checkout. The app adds the Razorpay window to its card payment method.

## Set up

Install Razorpay from the Swell App Store, and set it up in your test environment before the live one.

**1. Copy your test API keys**

In the Razorpay Dashboard, switch to test mode and go to **Account & Settings > API Keys**. Copy the **Key ID**, which starts with `rzp_test_`, and the **Key secret** of a test key.

**2. Choose Razorpay as the card gateway**

In Swell, go to **Settings > Payments**. Under **Credit cards**, click **Edit settings**, or **Use a different gateway** while the Swell test gateway is selected. In **Credit card settings**, choose **Razorpay** as the **Payment gateway**, enter the **Key ID** and **Key secret**, and click **Save**. Card payments go through Razorpay once you save.

If the toggle next to **Credit cards** is off, turn it on and click **Save changes**.

**3. Ask for a phone number at checkout**

Go to **Settings > Checkout**. Under **Form fields**, set **Phone number** to **Required** and click **Save changes**. Razorpay can't save a card without the shopper's phone number.

**4. Choose when payments are captured**

In **Settings > Orders**, **Charge automatically** and **Require payment authorization** are on by default, so payments are captured when the order is placed. To capture payments later from the order, turn off **Charge automatically**, keep **Require payment authorization** on, and click **Save changes**.

**5. Place a test order**

Place an order in the hosted checkout, pay by card and click **Complete order**. The Razorpay window opens. Pay with a Razorpay test card, such as `4111 1111 1111 1111` with any future expiry date and any CVV. In the order's **Transactions**, the payment shows **Paid**, or **Authorized** when **Charge automatically** is off.

To test a saved card charge, click **Charge order** on the order, enter an amount and charge it. The payment shows **Pending**, then **Paid**. To test a refund, click **Refund order**.

**6. Go live**

Settings are saved separately for each environment. In the live environment, repeat steps 2 to 4 with the Key ID and Key secret of a live key from Razorpay's live mode, which starts with `rzp_live_`.

In live mode, Razorpay charges a saved Indian card only after it notifies the cardholder, so saved card charges on those cards stay **Pending** for about 36 hours.

## Using Razorpay

### Checkout

When a shopper chooses to pay by card, the checkout shows `You will enter your card details in a secure Razorpay window.` When they click **Complete order**, the app creates a Razorpay order for the cart's total and opens the Razorpay window, with the shopper's name, email address and phone number filled in. The window offers cards only. If a card is declined, the shopper can try again in the same window. If they close it, the order isn't placed, with the error `Payment cancelled` or the reason the last attempt failed.

When the shopper pays, Razorpay authorizes the payment and saves the card for later charges. The app checks the payment's signature with your Key secret, and the order is placed with the authorized payment and the saved card: Razorpay's token, the card brand, the last four digits and the expiry date. The Razorpay payment is set to manual capture, so Swell decides when it's captured.

The first time a customer pays, the app creates a Razorpay customer with their name, email address and phone number, and keeps it on their Swell account. Their later checkouts and charges use the same Razorpay customer, even if their phone number changes.

### Capturing payments

Swell decides when a payment is captured, with **Charge automatically** and **Require payment authorization** under **Settings > Orders**:

- Both on, the default: the payment is authorized when the order is placed and captured right away.
- **Charge automatically** off: the payment is only authorized, and shows **Authorized** in the order's **Transactions**. Capture it within 5 days.
- Both off: no payment is taken when the order is placed. Charge the order later with **Charge order**.

To capture an authorized payment, open the order and click **Charge order**. Keep the amount at the authorized amount and click the **Charge** button. The app captures the Razorpay payment after checking that it's a card payment for the same amount and currency, and that no other Swell payment has used it.

Razorpay keeps an authorization from the checkout for 5 days. After that, the capture fails with `The authorization is no longer valid; charge the saved card with a new payment`. Click **Charge order** again to charge the saved card. To take a different amount than the authorization, enter it in **Charge order**: the app charges the saved card with a new payment, and Razorpay releases the authorization when it expires.

When Razorpay doesn't answer a capture, or answers with a server error, the capture fails, and the app doesn't charge the saved card instead, because the capture may still go through. Check the payment in the Razorpay Dashboard before you charge the order again: a new **Charge order** charges the saved card.

### Charging the saved card

The app charges the shopper's saved card with a new Razorpay payment when a charge has no usable authorization, such as a subscription renewal, a **Charge order** after the authorization expired, or a different amount. The shopper doesn't need to be present.

Razorpay takes several seconds to charge a saved card, so the payment shows **Pending** in the order's **Transactions**, and a workflow finishes it, usually within seconds. It then shows **Paid**, or **Error** with the reason. The runs are listed under **Apps > Razorpay > Workflows**. Every 30 minutes, the app also finishes saved card charges that are still pending, for example after a workflow failed.

A saved card can be charged up to ₹10,000 at a time, or 10,000 in another currency with two decimals. The customer's account needs an email address, and a phone number unless the app already created their Razorpay customer.

### Pending charges on Indian cards in live mode

In live mode, Razorpay charges a saved Indian card only after it notifies the cardholder, about 36 hours later. Until then, the payment stays **Pending**. The app checks it every 6 hours, for up to 8 days, and records it as **Paid** once Razorpay has charged the card. If the card still isn't charged after 8 days, the payment fails with `Saved card payment … was not finalized: Payment is still pending (status: created) after 8 days`. In test mode, saved cards are charged without the wait.

### Refunds

To refund a payment, open the order and click **Refund order**. Choose the payment, enter the **Refund amount** and an optional **Reason**, and click the **Refund** button. The app refunds the amount to the card through Razorpay. You can refund a payment in full or in parts, up to the amount paid. Refunds made in the Razorpay Dashboard aren't sent to Swell.

### Subscriptions

The app supports subscriptions, so the card payment method is offered at checkout for carts with subscription products. The first payment is taken at checkout. Renewals are charged on the saved card with no checkout, when Swell charges the subscription. With **Charge automatically** on under **Settings > Subscriptions**, that's when the renewal is due.

Each renewal payment shows **Pending** until its workflow finishes it, which on a live Indian card takes about 36 hours.

### Never charged twice

Every Razorpay order the app creates for a saved card charge carries the Swell payment's ID as its receipt. When a charge is retried, the app finds the earlier Razorpay payment by that receipt and finishes it instead of charging the card again. A new saved card payment is created at most once. If Razorpay's answer is lost, the app waits a minute and looks for the payment before it records anything.

A Razorpay payment the app captures is marked with its Swell payment, and the app never uses it for another one. If the app finds a Razorpay payment that was captured but not by the app, for example in the Razorpay Dashboard, it stops with `Payment already captured but not recorded; contact support` rather than charging again.

### In the dashboard

| Where | What it's for |
| --- | --- |
| Settings > Payments, Credit cards | Edit settings: the Payment gateway, and the Key ID and Key secret while Razorpay is selected. The toggle turns card payments on or off. |
| Apps > Razorpay > Settings | The Key ID and Key secret. |
| Apps > Razorpay > Workflows | The runs that finish saved card charges. |
| Settings > Orders | Charge automatically and Require payment authorization, which decide when payments are captured. |
| Settings > Subscriptions | Charge automatically for renewals, and the dunning and retry rules. |
| Settings > Checkout, Form fields | Phone number, which Razorpay needs to save the card. |
| An order's Transactions | Each payment's status, Authorized, Pending, Paid or Error, and its refunds. |
| An order's Charge order button | Captures an authorized payment, or charges the saved card. |
| An order's Refund order button | Refunds a payment in full or in part. |
| Developer > Console > Logs | The app's logs. |

## Settings

Settings are in **Settings > Payments**: under **Credit cards**, click **Edit settings** while Razorpay is the payment gateway. The same settings are in **Apps > Razorpay > Settings**. They're saved separately for each environment.

| Setting | Description | Default |
| --- | --- | --- |
| Key ID | From Account & Settings > API Keys in the Razorpay Dashboard. Opens the Razorpay window in the checkout, so it's sent to the shopper's browser. Test keys start with rzp_test_, live keys with rzp_live_. Required. | None |
| Key secret | From the same page. Used only by the app's functions, never sent to the browser. Masked on the settings page. Required. | None |

## Limitations

- Cards only. Razorpay's other payment methods, such as UPI, netbanking and wallets, aren't offered.
- The Razorpay window is part of Swell's hosted checkout.
- A charge on a saved card is limited to 1,000,000 in the currency's smallest unit: ₹10,000, or 10,000 in another currency with two decimals. The card is saved with that limit.
- An authorization from the checkout can be captured for 5 days, and only for its full amount. A different amount is charged on the saved card as a new payment.
- The app doesn't cancel authorizations in Razorpay, even when Swell voids the payment. Razorpay releases an authorization that isn't captured after 5 days.
- In live mode, saved Indian cards are charged about 36 hours after Razorpay notifies the cardholder. The payment stays **Pending** until then, for up to 8 days.
- Captures and refunds made in the Razorpay Dashboard aren't sent to Swell. A payment captured there can't be captured from Swell.
- Each shopper needs an email address and a phone number.
- Razorpay decides which cards and currencies can be saved and charged again.

## Troubleshooting

Errors at checkout are shown to the shopper. A charge or refund that fails shows **Error** in the order's **Transactions**, with the reason when you point at it. The app also logs its errors. In the Swell dashboard, the logs are under **Developer > Console > Logs**, and saved card charges are under **Apps > Razorpay > Workflows**.

### The Razorpay window doesn't open

`Razorpay is not configured` means no **Key ID** is saved in this environment, and `Razorpay keys are not configured` that the **Key ID** or the **Key secret** is missing. Enter both under **Settings > Payments** and save. `Razorpay checkout could not be loaded` means the shopper's browser couldn't load Razorpay's checkout script from `checkout.razorpay.com`. The shopper can click **Complete order** again.

### "An email address is required to save the card" or "A phone number is required to save the card"

Razorpay needs the shopper's email address and phone number to save the card. Under **Settings > Checkout > Form fields**, set **Phone number** to **Required**. The same messages ending in `to charge the saved card` mean the customer's account is missing them. Add them to the account, then charge the order again.

### "The card could not be saved"

Razorpay authorized the payment without saving the card, so the order isn't placed, and Razorpay releases the authorization after 5 days. Check that recurring card payments are enabled on your Razorpay account. Razorpay decides which cards can be saved, so the shopper can also try another card.

### "Invalid payment signature"

Razorpay's signature on the payment didn't match your Key secret, so the order isn't placed and the payment is left uncaptured. The shopper can pay again.

### Messages that start with "Razorpay:"

Razorpay refused the request, and the rest of the message is Razorpay's reason. Check the keys, that test keys are used in the test environment and live keys in the live one, and that recurring card payments are enabled on your Razorpay account.

### A payment stays Pending

A saved card charge shows **Pending** until its workflow finishes, usually within seconds. On a live Indian card it waits for Razorpay to notify the cardholder, about 36 hours. Open **Apps > Razorpay > Workflows** to see the run and its steps. If a run failed, the app finishes the charge within 30 minutes. If Razorpay has no payment for it by then, the payment fails with `The saved card charge did not complete`, and nothing was charged.

### "The authorization is no longer valid; charge the saved card with a new payment"

The authorization expired or was released before it was captured, for example after 5 days. Click **Charge order** again to charge the saved card.

### "Payment already captured but not recorded; contact support"

The Razorpay payment was captured, but not by this Swell payment, for example in the Razorpay Dashboard. The app doesn't charge the card again. Check the payment in the Razorpay Dashboard, and email support@swell.is.

### "Saved card payment … was not finalized: …"

A saved card payment exists in Razorpay but couldn't be completed, and its money may be on hold or taken. The message names the Razorpay payment and the reason. Look it up in the Razorpay Dashboard before you charge the order again. `Saved card payment … is still pending (status: created); contact support` means a charge was retried while Razorpay was still waiting to charge the card.

### A refund fails

`No Razorpay payment to refund` means the Swell payment has no Razorpay payment ID. Other reasons start with `Razorpay:` and come from Razorpay.

## Uninstalling

Uninstalling the app removes its functions, its workflow and its settings, including your API keys, and removes Razorpay from the **Payment gateway** options. Uninstalling applies to the environment you are in, so remove the app from the test and live environments separately.

Before you uninstall, choose another payment gateway for **Credit cards** under **Settings > Payments**. Uninstalling doesn't change the card method's gateway, and while it's still Razorpay, card payments stop working: **Charge order** and subscription renewals fail with an error that the payment app isn't installed.

Wait until no saved card charge shows **Pending**. After the app is removed, nothing finishes them: the Swell payment stays pending, and the Razorpay payment isn't captured.

Cards saved through the app are Razorpay tokens and can only be charged through Razorpay. Subscriptions paid with a saved card need a new card from the customer to renew on another gateway. Customers, saved cards, payments and refunds stay in your Razorpay account. The app isn't notified when it's uninstalled, so if you no longer need the API keys, regenerate them in the Razorpay Dashboard under **Account & Settings > API Keys**.

## For developers

| Function | Runs on | What it does |
| --- | --- | --- |
| card-intent-create | after:payment.create_intent, for the card extension | Creates or reuses the Razorpay customer and creates the Razorpay order the checkout window pays. |
| card-intent-get | after:payment.get_intent, for the card extension | Checks the window's payment signature and returns the payment with its saved card token. |
| card-charge | after:payment.charge, for the card extension | Captures the shopper's authorization when it's valid, or creates an order for a saved card charge, starts card-charge-finish and answers async. |
| card-charge-finish | A workflow, started by card-charge | Creates the recurring payment at most once, waits for live debits, captures it when the Swell payment asks for it, and records the result. |
| card-charge-sweep | Every 30 minutes | Finishes pending saved card charges created between 30 minutes and 8 days ago, 10 per run. |
| card-refund | after:payment.refund, for the card extension | Refunds the amount on the Razorpay payment. |

The app is the gateway of Swell's `card` method through a `payment` extension with `subscriptions: true`, so the gateway ID is `app_<app id>_card`. Its settings are `key_id`, which is public, and `key_secret`, in the `card` settings. The Razorpay customer is kept on the account under `$app.razorpay` as `customer_id` and `contact`, the phone it was created with.

The checkout component, `components/Razorpay.tsx`, is an `@swell/apps-sdk` component on the `card` extension and the `checkout.payment.methods` target. On submit it loads `https://checkout.razorpay.com/v1/checkout.js`, calls `createIntent` with the cart's `capture_total` in the currency's smallest unit, opens the window with `recurring: '1'` and a card-only display block, and passes the signed response to `getIntent`. It returns `billing.card` with the token, `last4`, `brand`, `exp_month` and `exp_year`, and `billing.intent.razorpay.id`.

The app calls the Razorpay API at `https://api.razorpay.com/v1` with Basic auth: `POST /customers` with `fail_existing: '0'`, `POST /orders`, `GET /orders?receipt=…`, `GET /orders/{id}/payments`, `GET /payments/{id}` with `expand[]=token`, `POST /payments/create/recurring`, `PATCH /payments/{id}` for notes, `POST /payments/{id}/capture` and `POST /payments/{id}/refund`. Errors are thrown as `Razorpay: <description>`. The checkout order has `method: card`, `token.max_amount: 1000000` with `frequency: as_presented`, and manual capture with `manual_expiry_period: 7200`. Amounts are converted to the smallest unit in `lib/amount.ts`, with zero-decimal and three-decimal currencies.

`get_intent` checks the HMAC-SHA256 hex signature of `order_id|payment_id` with the key secret in constant time. `card-charge` takes the Razorpay payment from `transaction_id` or `intent.razorpay.id`, and uses it only when it's a card payment with the Swell payment's amount and currency, `authorized`, and not marked with another Swell payment in `notes.swell_payment_id`. After a capture it writes that note. A captured payment without the note fails closed. A capture that gets a network error, a 408, a 429 or a 5xx while the payment is still authorized fails the charge. Only another 4xx refusal falls back to the saved card.

A saved card charge reads the customer, looks up earlier attempts and creates an order with `payment_capture: false`, `receipt` set to the Swell payment ID, in parallel. An earlier payment is finished in the hook. Otherwise the hook starts `card-charge-finish` with identifiers only and answers `async: true`, because creating a recurring payment takes Razorpay longer than the hook can wait. While a Swell payment is `async` without `success`, a new charge of it answers `async: true` and creates nothing. A capture of a Swell payment that already has its result never starts a saved card charge.

The workflow's steps are `check pending`, `charge saved card` (never retried), `wait for Razorpay` and `find by receipt` after an unknown outcome, `read payment` and `wait for debit 1` to `wait for debit 32` at 6-hour intervals, `capture`, `record` and `late capture`. Each step that calls Razorpay reads the keys itself and doesn't return them. Step names are the step cache keys, so they mustn't change while runs sleep. The sweep reads the gateway from `/settings/payments`, reads up to 10 `async`, `pending`, non-void `card` payments of that gateway, newest first, works on 5 at a time and starts none after 6 seconds.

## Support

Swell builds and maintains the Razorpay app. For help with the app, email support@swell.is. For questions about your Razorpay account, API keys or recurring payments, contact Razorpay.
