> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dodopayments.com/llms.txt
> Use this file to discover all available pages before exploring further.

# India Payment Methods

> Accept UPI, Indian-issued cards, and Apple Pay in INR from customers in India. Understand RBI subscription mandates, the 48-hour delay, and mandate limits.

Accept UPI, Indian-issued cards (Visa, Mastercard, and RuPay), and Apple Pay from customers in India. UPI carries more than 80% of India's digital payment transactions by volume. Dodo Payments supports subscriptions on UPI and Indian-issued cards through RBI-compliant mandates.

## Why India Payment Methods Matter

<CardGroup cols={3}>
  <Card title="UPI Dominance" icon="mobile">
    UPI processes more than 20 billion transactions a month, and many Indian customers don't have an international card.
  </Card>

  <Card title="Low-Value Payments" icon="indian-rupee-sign">
    UPI suits high-volume, lower-value transactions.
  </Card>

  <Card title="Subscription Support" icon="repeat">
    Unlike most alternative payment methods, UPI and Indian-issued cards, including Visa, Mastercard, and RuPay, support recurring payments through RBI mandates.
  </Card>
</CardGroup>

## Supported Methods

The table lists each method and whether it supports subscriptions:

| Method | Type | Subscriptions |
| :- | :- | :-: |
| **UPI** | QR code | Yes\* |
| **RuPay Credit** | Card | Yes\* |
| **RuPay Debit** | Card | Yes\* |
| **Apple Pay** | Digital wallet | Yes\* |

\*Subscriptions require RBI-compliant mandates with special processing rules. The 48-hour processing delay applies to recurring charges on all Indian-issued cards, UPI, and Apple Pay.

A payment billed in INR must be at least ₹5.00 and at least the equivalent of the USD minimum: \$0.50 for one-time payments and \$1.00 for subscriptions. See [Minimum Amounts](/features/adaptive-currency#minimum-amounts).

## Configuration

### API Method Types

Pass these values in `allowed_payment_method_types`:

| Type | Description |
| :- | :- |
| `upi_intent` | UPI via QR code |
| `credit` | Credit cards, including RuPay |
| `debit` | Debit cards, including RuPay |
| `apple_pay` | Apple Pay, on Apple devices. See [Apple Pay in India](/features/payment-methods/digital-wallets#apple-pay-in-india) |

<Warning>
  Checkout offers UPI only as `upi_intent`. If `allowed_payment_method_types` lists `upi_collect` but not `upi_intent`, UPI doesn't appear at checkout.
</Warning>

### Example: India-Focused Checkout

This session offers UPI, cards, and Apple Pay to a customer in India, billed in INR:

```javascript theme={null}
// `client` is an initialized DodoPayments client.
const session = await client.checkoutSessions.create({
  product_cart: [{ product_id: 'pdt_123', quantity: 1 }],
  allowed_payment_method_types: [
    'upi_intent',
    'credit',
    'debit',
    'apple_pay'
  ],
  billing_currency: 'INR',
  customer: {
    email: 'customer@example.com',
    name: 'Priya Sharma',
    phone_number: '+919876543210'
  },
  billing_address: {
    country: 'IN',
    zipcode: '560001'
  },
  return_url: 'https://example.com/success'
});
```

### Requirements for UPI

UPI appears at checkout only when all of these are true:

1. The **billing country** is India (`IN`).
2. The **billing currency** is INR.
3. For subscriptions from merchants outside India, **Adaptive Currency** is enabled. One-time checkouts don't need it if the product is priced in INR.

<Warning>
  If you're a merchant outside India and Adaptive Currency is disabled, your customers can't pay for subscriptions with UPI.
</Warning>

## Subscriptions with RBI Mandates

Subscriptions paid with UPI or Indian-issued cards run on RBI (Reserve Bank of India) mandates, which add rules that other payment methods don't have.

### How RBI Mandates Work

The customer authorizes a mandate when they subscribe. Each renewal charge then waits 48 hours after a pre-debit notification before the bank debits the funds:

```mermaid theme={null}
sequenceDiagram
    participant Customer
    participant Your App
    participant Dodo
    participant Bank
    
    Customer->>Your App: Subscribe
    Your App->>Dodo: Create subscription
    Dodo->>Bank: Create mandate
    Bank->>Customer: Authorize mandate
    Customer->>Bank: Approve (billing amount or mandate floor)
    Bank->>Dodo: Mandate active
    
    Note over Dodo,Bank: On renewal date...
    
    Dodo->>Bank: Initiate charge
    Note over Bank: 48-hour window starts
    Bank->>Customer: Pre-debit notification
    Note over Bank: After 48 hours...
    Bank->>Dodo: Debit completed
    Dodo->>Your App: payment.succeeded webhook
```

### Mandate Types

The mandate type depends on how the subscription amount compares with the mandate floor:

| Subscription Amount | Mandate Type | Limit |
| :- | :- | :- |
| **Below the mandate floor** | On-demand mandate | Mandate floor (default ₹15,000) |
| **At or above the mandate floor** | Fixed-amount mandate | Exact subscription amount |

The amount registered with the customer's bank is `max(mandate_floor, billing_amount)`. When the billing amount is below the floor, the floor becomes the customer-facing **authorization ceiling**.

**Plan changes:** If an upgrade produces a charge above the existing mandate limit, the charge fails and the customer must authorize again.

### Configurable Mandate Floor

Set the mandate floor for INR e-mandates with the `mandate_min_amount_inr_paise` field, in **INR paise** (₹1 = 100 paise).

<Warning>
  This setting only affects e-mandates registered for Indian-issued cards (Visa, Mastercard, RuPay) on INR subscriptions. UPI subscriptions follow their own AutoPay flow and aren't affected.
</Warning>

You can override the system default of ₹15,000 at three levels:

| Level | Where to set | Scope |
| - | - | - |
| **Per request** | `mandate_min_amount_inr_paise` on a checkout session or subscription | One transaction |
| **Merchant** | Business-level default, if one is configured | All your INR subscriptions |
| **System** | — | ₹15,000 default |

Dodo Payments uses the first value that's set: the per-request override, then the merchant setting, then the system default.

To set the floor, pass `mandate_min_amount_inr_paise` in the request body when you [create a checkout session](/api-reference/checkout-sessions/create). The deprecated [Create Subscription](/api-reference/subscriptions/post-subscriptions) endpoint accepts the same field.

```typescript theme={null}
// `client` is an initialized DodoPayments client.
// Per-checkout override
const session = await client.checkoutSessions.create({
  product_cart: [{ product_id: 'pdt_inr_monthly', quantity: 1 }],
  mandate_min_amount_inr_paise: 2_000_000, // ₹20,000 ceiling
  return_url: 'https://yoursite.com/return'
});

// Per-subscription override
// Note: POST /subscriptions is deprecated — prefer checkout sessions for new integrations
const subscription = await client.subscriptions.create({
  product_id: 'pdt_inr_monthly',
  quantity: 1,
  customer: { email: 'customer@example.com' },
  billing: { country: 'IN', zipcode: '560001' },
  mandate_min_amount_inr_paise: 2_000_000
});
```

The field accepts these values:

| Field | Type | Validation | Applies to |
| - | - | - | - |
| `mandate_min_amount_inr_paise` | `integer` (INR paise) | `>= 1` | Indian-card INR subscriptions on non-Airwallex connectors |

<Info>
  A higher floor lets you make larger one-off charges later, such as plan upgrades or usage-based overages, without asking customers to authorize again. A lower floor keeps the customer's authorization closer to the actual billing amount, but leaves less room for future variable charges.
</Info>

### The 48-Hour Processing Delay

A renewal charge on an Indian card or UPI completes about 48 hours after the renewal date. This is the most important difference from international card payments:

<Steps>
  <Step title="Charge Initiated (Day 0)">
    On the scheduled renewal date, Dodo Payments initiates the charge with the bank.
  </Step>

  <Step title="Pre-Debit Notification">
    The customer's bank notifies them about the upcoming debit.
  </Step>

  <Step title="48-Hour Window">
    During this period, the customer can cancel the mandate in their banking app.
  </Step>

  <Step title="Debit Completed (~48-51 Hours)">
    After 48 hours, plus up to 3 more hours for bank processing, the bank debits the funds.
  </Step>

  <Step title="Webhook Sent">
    Dodo Payments sends the `payment.succeeded` webhook after the actual debit, not when the charge is initiated.
  </Step>
</Steps>

<Warning>
  **Don't grant benefits when the charge is initiated.** Wait for the `payment.succeeded` webhook, which arrives about 48–51 hours after the scheduled charge date.
</Warning>

### Handling the 48-Hour Window

Grant access from the payment webhook, not from the renewal date:

```javascript theme={null}
// grantPremiumAccess and revokePremiumAccess are your own access-control functions.

// DON'T do this:
async function handleSubscriptionRenewal(subscription) {
  // Bad: Granting access immediately when charge is initiated
  grantPremiumAccess(subscription.customer.customer_id);
}

// DO this:
async function handlePaymentWebhook(event) {
  if (event.type === 'payment.succeeded') {
    // Good: Only grant access after payment is confirmed
    grantPremiumAccess(event.data.customer.customer_id);
  }
  
  if (event.type === 'payment.failed') {
    // Handle failed payment (mandate cancelled, insufficient funds)
    revokePremiumAccess(event.data.customer.customer_id);
  }
}
```

### Webhook Events for Indian Subscriptions

Handle these events for subscriptions paid with UPI or Indian-issued cards:

| Event | When | Action |
| :- | :- | :- |
| `subscription.active` | Mandate authorized | Record subscription start |
| `payment.succeeded` | \~48h after charge date | Grant/continue access |
| `payment.failed` | Debit failed | Notify customer, pause access |
| `subscription.on_hold` | Payment failed | Prompt for payment method update |
| `subscription.active` | Reactivated after payment | Restore access |

## Testing

### UPI Test IDs

In test mode, enter these UPI IDs to simulate each outcome:

| Status | UPI ID |
| :- | :- |
| Success | `success@upi` |
| Failure | `failure@upi` |

### Indian Card Test Numbers

Use these Indian-issued test cards:

| Brand | Scenario | Card Number | Expiry | CVV |
| :- | :- | :- | :- | :- |
| Visa | Success | `4576238912771450` | 06/32 | 123 |
| Visa | Declined | `4706131211212123` | 06/32 | 123 |
| Mastercard | Success | `5409162669381034` | 06/32 | 123 |
| Mastercard | Declined | `5105105105105100` | 06/32 | 123 |

## Best Practices

<AccordionGroup>
  <Accordion title="Plan for the 48-hour delay">
    Build your application to handle the gap between charge initiation and the actual payment. Consider:

    * Grace periods for subscription access
    * Clear communication to customers about processing time
    * Webhook-driven fulfillment, not date-driven fulfillment
  </Accordion>

  <Accordion title="Handle mandate cancellations">
    Customers can cancel mandates in their banking apps at any time. Monitor `subscription.on_hold` webhooks, and prompt customers to subscribe again or update their payment method.
  </Accordion>

  <Accordion title="Set appropriate mandate amounts">
    For variable pricing, such as usage-based billing, check whether an on-demand mandate at the mandate floor (₹15,000 by default) covers your largest charge. If charges might exceed it, raise the floor with [`mandate_min_amount_inr_paise`](#configurable-mandate-floor). Otherwise, customers must authorize a new mandate.
  </Accordion>

  <Accordion title="Offer UPI prominently">
    For Indian customers, make UPI the primary payment option. Many prefer it to cards because it's familiar and has less friction.
  </Accordion>
</AccordionGroup>

## Troubleshooting

<AccordionGroup>
  <Accordion title="UPI not appearing at checkout">
    **Check:**

    1. Is the billing country set to `IN`?
    2. Is the billing currency set to `INR`?
    3. If you're a merchant outside India, is Adaptive Currency enabled?
    4. Is `upi_intent` included in `allowed_payment_method_types`?

    **Solution:** Set `country: "IN"` in the billing address and `billing_currency: "INR"`. If Adaptive Currency is disabled, the API ignores `billing_currency`, so price the product in INR instead.
  </Accordion>

  <Accordion title="Subscription charge failed after upgrade">
    **Cause:** The new charge amount exceeds the existing mandate limit: the mandate floor (₹15,000 by default), or the subscription amount if that's higher.

    **Solution:** The customer must update their payment method to set up a new mandate with the correct limit.
  </Accordion>

  <Accordion title="Subscription on hold but customer claims they didn't cancel">
    **Cause:** The customer may have cancelled the mandate during the 48-hour window, or their bank declined the debit.

    **Solution:** The customer needs to authorize the mandate again or update their payment method.
  </Accordion>

  <Accordion title="Payment deduction delayed beyond 48 hours">
    **Cause:** Bank API delays can extend processing by 2–3 hours.

    **Solution:** This is expected. Build your system to handle delays of up to about 51 hours in total.
  </Accordion>

  <Accordion title="Mandate cancelled but subscription still active">
    **Cause:** An edge case in RBI regulations: cancelling a mandate during the processing window doesn't cancel the subscription right away.

    **Solution:** The next charge fails, and the subscription moves to `on_hold`. Monitor webhooks for `payment.failed`.
  </Accordion>
</AccordionGroup>

## Related Pages

<CardGroup cols={2}>
  <Card title="Payment Methods Overview" icon="credit-card" href="/features/payment-methods">
    See all supported payment methods.
  </Card>

  <Card title="Subscriptions" icon="repeat" href="/features/subscription">
    Complete subscription documentation including RBI mandates.
  </Card>

  <Card title="Webhooks" icon="webhook" href="/developer-resources/webhooks">
    Webhook handling for payment events.
  </Card>

  <Card title="Testing Process" icon="flask" href="/miscellaneous/testing-process">
    All test data including UPI IDs and Indian cards.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.