Skip to content
Sign in
An image of the Stripe logo
Create account
Sign in
Home
Payments
Finance automation
Banking as a service
Developer tools
No-code
All products
Home
Payments
Finance automation
Home
Payments
Finance automation
Banking as a service
Developer tools
Overview
Online payments
In-person payments
Multiparty payments
After the payment
Add payment methods
Fraud detection
Payment Links
Stripe Checkout UI
Stripe Elements UI
Financial Connections
Crypto
Identity
Climate
About the APIs
Regulation support
    SCA readiness
    India recurring payments
Implementation guides
Testing
HomePayments

India recurring payments

Learn how to update an integration to support RBI e-mandates.

The Reserve Bank of India (RBI) issued a directive (amended subsequently in December 2020 and March 2021) that introduces additional security measures for recurring payments on India issued cards. These measures include:

  • Banks need to register cardholders and create an e-mandate through a one-time process, using additional factor authentication (AFA) like 3D Secure (3DS).
  • Banks must alert cardholders at least 24 hours before charges take place and give them the ability to opt out of transactions.
  • Recurring transactions over 15,000 INR (or equivalent in other currencies) must go through AFA each time.

If you’re an India-based Stripe user or an international (non-IN) Stripe user, your business is impacted if you have customers who use India cards for:

  • Off-session payments
  • Subscriptions or Invoices where the collection_method is set to charge_automatically

How payments work with an e-mandate

Stripe has worked with a partner platform to support registering e-mandates and issuing pre-debit notifications to customers.

Note

We don’t currently offer the use of e-mandates to Stripe users in Mexico and Japan.

Depending on how you’ve integrated with Stripe, you might need to send Stripe additional information to set up a mandate. The customer must go through AFA (3DS) to register the mandate.

Subsequent off-session payments or auto-debits for a Subscription undergo a significant change. Customers need to receive a pre-debit notification at least 24 hours before the actual payment with the exact debit amount mentioned. The pre-debit notification contains information about the payment and an option to cancel the mandate. If the payment amount is above 15,000 INR or the mandate’s maximum amount, the pre-debit notification contains a link to perform AFA (3DS) to authorize the payment.

Because Stripe is integrating with a partner platform, we wait 26 hours before charging the customer after receiving a payment request (we add a buffer for possible downstream issues, which necessitates the 26 hours advance notification). This means that Stripe delays collecting payment by 26 hours.

Without a mandate for an off-session payment, the card issuer will likely decline the payment.

Integration

 

If you use PaymentIntents or SetupIntents to create off-session payments on India issued cards, you must update your integration.




Create a mandate

To create a mandate, populate the following parameters on the PaymentIntent or SetupIntent objects (in addition to existing parameters).

ParameterRequiredDescription
payment_method_options[card][mandate_options][reference]YesUnique identifier for the mandate or subscription.
payment_method_options[card][mandate_options][description]NoA description of the mandate or subscription that the customer sees. If not passed, Stripe populates it with {merchant_name} - {reference}.
payment_method_options[card][mandate_options][amount_type]YesOne of fixed, maximum. If set to fixed, the amount parameter refers to the exact amount to be charged in future payments. If set to maximum, a customer can be charged more than the maximum amount, but the payment requires AFA (3DS) for amounts greater than the maximum or 15,000 INR (whichever is less).
payment_method_options[card][mandate_options][amount]YesAmount to be charged for future payments.
payment_method_options[card][mandate_options][currency]YesThis parameter is only for SetupIntents. It sets the currency for future payments. Stripe supports INR mandates for all businesses. The following currencies are supported only for international (non-IN) businesses: USD, EUR, GBP, SGD, CAD, CHF, SEK, AED, JPY, NOK, MYR, HKD.
payment_method_options[card][mandate_options][start_date]YesStart date of the mandate or subscription, specified as the epoch timestamp. The start date must be later than yesterday.
payment_method_options[card][mandate_options][end_date]NoEnd date of the mandate or subscription, specified as the epoch timestamp. If not provided, the mandate remains active until canceled.
payment_method_options[card][mandate_options][interval]YesSpecifies payment frequency. One of day, week, month, year, sporadic.
payment_method_options[card][mandate_options][interval_count]NoThe number of intervals between payments. For example, interval=month and interval_count=3 indicates one payment every 3 months. Intervals have a maximum of 1 year (1 year, 12 months, or 52 weeks). This parameter is optional only when interval=sporadic.
payment_method_options[card][mandate_options][supported_types]YesAn array specifying the mandate types supported for this payment. The only possible value is [‘india’].

Note

You can pass the payment_method_options[card][mandate_options] parameter for all requests. Stripe ignores these parameters if your customer is using a non-India issued card because the regulation doesn’t apply to them.

If the amount paid might vary, set up the mandate with amount_type=maximum. You can’t charge a customer more than the amount defined in an amount_type=fixed mandate. However, with amount_type=maximum, you can still charge more than the maximum amount. The caveat here is that amounts more than the maximum or 15,000 INR (whichever is less) require AFA (3DS).

Examples:

  • If you have amount_type=maximum, amount=100000, the customer would be required to authenticate for amounts more than 1,000 INR.
  • If you have amount=2000000, the customer would be required to authenticate for amounts more than 15,000 INR.
Command Line
curl https://api.stripe.com/v1/payment_intents \ -u "
sk_test_4eC39HqLyjWDarjtT1zdp7dc
:"
\ -d amount=2000000 \ -d currency=inr \ -d customer=
{{CUSTOMER_ID}}
\ -d setup_future_usage=off_session \ -d "payment_method_types[]"=card \ -d "payment_method_options[card][mandate_options][reference]"={{REFERENCE}} \ -d "payment_method_options[card][mandate_options][description]"={{DESCRIPTION}} \ -d "payment_method_options[card][mandate_options][amount]"=2000000 \ -d "payment_method_options[card][mandate_options][start_date]"=1675238400 \ -d "payment_method_options[card][mandate_options][amount_type]"=maximum \ -d "payment_method_options[card][mandate_options][interval]"=month \ -d "payment_method_options[card][mandate_options][interval_count]"=1 \ -d "payment_method_options[card][mandate_options][supported_types][]"=india

After confirming the PaymentIntent with a payment method, the PaymentIntent transitions to a requires_action state. The cardholder needs to complete AFA (3DS) before the PaymentIntent transitions to a succeeded state and a mandate is created.

Stripe doesn’t return a mandate ID if any of the following is true:

  • A card isn’t an India issued card.
  • The currency for the mandate isn’t supported by either the issuer or for the Stripe account’s country.
  • The India issued card is neither Visa nor Mastercard. Stripe only supports mandates for these two card brands.

Stripe supports INR mandates for all businesses. The following currencies are supported only for international (non-IN) businesses:

  • USD
  • EUR
  • GBP
  • SGD
  • CAD
  • CHF
  • SEK
  • AED
  • JPY
  • NOK
  • MYR
  • HKD

There are over 100 issuing banks in India and the process of fully adapting to the new requirements is expected to take some time. An issuer might not support e-mandates for a particular currency yet. If so, Stripe doesn’t return a mandate ID.

The mandate ID is in the PaymentIntent’s corresponding Charge object. See Identifying charges on a PaymentIntent to learn more about how to retrieve the Charge.

{ "id": "ch_xxxxxxxxxxxxxxxxxxxxxxxx", "object": "charge", "payment_intent": "pi_xxxxxxxxxxxxxxxxxxxxxxxx", "payment_method": "pm_xxxxxxxxxxxxxxxxxxxxxxxx", "payment_method_details": { "card": { "brand": "visa", "country": "IN", "mandate": "mandate_xxxxxxxxxxxxxxxxxxxxxxxx", // id of the mandate created ... }, ... "status": "succeeded", ... }

Mandate webhooks

Listen for the mandate.updated event to make sure the mandate is active before you charge the saved payment method off-session.

Even though the PaymentIntent or SetupIntent might have transitioned into status=succeeded, the mandate might not yet be active. Stripe creates the Mandate object in the pending state. When the mandate transitions to an active state, Stripe sends a mandate.updated event. In rare cases, a mandate can take up to 30 minutes to transition to active in live mode. If the mandate doesn’t become active after 30 minutes, assume that you can’t use the mandate.

{ "object": { "id": "mandate_xxxxxxxxxxxxxxxxxxxxxxxx", "object": "mandate", "customer_acceptance": { "accepted_at": 1677301688, "online": { "ip_address": "xx.xxx.xx.xxx", "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36" }, "type": "online" }, "livemode": false, "multi_use": { }, "payment_method": "pm_xxxxxxxxxxxxxxxxxxxxxxxx", "payment_method_details": { "card": { }, "type": "card" }, "status": "active", "type": "multi_use" }, "previous_attributes": { "status": "pending" } }

If a mandate can’t be created, you can suggest using a different card, or offer alternative options such as paying on-session on your site, or with a link to a hosted invoice page.

For more information on receiving webhooks, see Steps to receive webhooks.

Charge the saved payment method later

When you’re ready to charge your customer off-session, use the Customer, PaymentMethod ID, and corresponding mandate ID to create a PaymentIntent.

Command Line
curl https://api.stripe.com/v1/payment_intents \ -u "
sk_test_4eC39HqLyjWDarjtT1zdp7dc
:"
\ -d amount=2000000 \ -d currency=inr \ -d customer={{CUSTOMER_ID}} \ -d confirm=true \ -d "payment_method_types[]"=card \ -d payment_method={{PAYMENT_METHOD_ID}} \ -d mandate={{MANDATE_ID}} \ -d off_session=true

Cloning

Pre-debit notification

When the off-session PaymentIntent is confirmed, the issuing bank sends the customer the pre-debit notification. The PaymentIntent transitions to a processing state for the entire duration of the pre-debit notification period (26 hours) and can’t be canceled.

{ "object": "payment_intent", ... "processing": { "card": { "customer_notification": { "approval_requested": true, "completes_at": 1677307005 } }, "type": "card" }, ... "status": "processing", ... }

If processing.card.customer_notification.approval_requested is true, the customer needs to authenticate the payment using the pre-debit notification sent to them by the issuing bank.

The processing.card.customer_notification.completes_at attribute specifies the time that the Stripe attempts to charge the card. If successfully processing the payment requires customer approval, they need to authenticate the payment by the specified time.

Decline codes

Note the decline codes that can occur in the following scenarios:

Decline codeDescription
india_recurring_payment_mandate_canceledThis decline code is shown when a payment is attempted using a canceled mandate
transaction_not_approvedThis decline code is shown when a payment is attempted and the customer has paused permissions to auto-debit, or doesn’t authenticate the payment when it’s required.

Testing

You can use these test card numbers to simulate different scenarios.

In test mode, it takes approximately 15 minutes for the PaymentIntent to transition out of the processing state.

Caution

Stripe no longer supports 3D Secure 1, except for IN Stripe accounts. If you have a non-IN account, use the 3D Secure 2 test cards. If a non-IN business uses a 3D Secure 1 test card, a mandate isn’t created.

Test card numberScenario
Simulates successful mandate setup and renewals.
Simulates a cardholder receiving a pre-debit notification for an off-session payment and either canceling or pausing the payment for a mandate of any amount.
Simulates the issuing bank’s failure to send a pre-debit notification to the cardholder for an off-session payment for a mandate of any amount.
Simulates a cardholder canceling a mandate of any amount.

Limitations

Keep in mind the following limitations:

  • Stripe attempts to automatically create mandates only on Subscriptions created after October 1, 2021. If you have a Subscription created before then, cancel and create a new Subscription to make sure a mandate is created.
  • You can’t create a mandate using the Charges and Sources APIs. If you want to create a mandate, you must use the PaymentIntent or SetupIntent APIs.
  • You can’t pass an existing mandate to a Subscription.
  • You can’t cancel or update a mandate.
Was this page helpful?
Need help? Contact Support.
Watch our developer tutorials.
Check out our product changelog.
Questions? Contact Sales.
Powered by Markdoc
You can unsubscribe at any time. Read our privacy policy.
On this page
How payments work with an e-mandate
Integration
Create mandate
Mandate webhooks
Charge the saved payment method later
Pre-debit notification
Decline codes
Testing
Limitations
Stripe Shell
Test mode
Welcome to the Stripe Shell! Stripe Shell is a browser-based shell with the Stripe CLI pre-installed. Login to your Stripe account and press Control + Backtick on your keyboard to start managing your Stripe resources in test mode. - View supported Stripe commands: - Find webhook events: - Listen for webhook events: - Call Stripe APIs: stripe [api resource] [operation] (e.g. )
The Stripe Shell is best experienced on desktop.
$