How to use this page
This page walks you through building one capability, start to finish: charging a customer repeatedly, automatically, with their permission. Subscriptions, SIPs, insurance premiums, loan instalments.
It feeds every product that bills more than once.
The rules changed on 21 April 2026 and most published guidance is out of date. The RBI's Digital Payments — E-mandate Framework, 2026 (Circular RBI/DPSS/2026-27/396) consolidated eight earlier circulars into one rulebook, effective immediately. If you are reading an integration guide that cites the 2019 or 2021 circulars as current, it is describing a framework that no longer exists.
What an e-mandate actually is
An e-mandate is a standing permission: the customer authenticates once, and you may then debit them repeatedly within agreed limits, without asking again each time.
The 2026 framework covers credit cards, debit cards, prepaid instruments and UPI, for domestic and cross-border recurring transactions. Three rails, one rulebook.
| Rail | What it is | Best for |
|---|---|---|
| Card e-mandate | Standing instruction against a card. | Subscriptions, international customers, higher ticket sizes. |
| UPI AutoPay | Mandate against a UPI ID, approved in the customer's UPI app. | Consumer India. Highest reach, lowest friction to register. |
| eNACH | Standing instruction registered directly against a bank account. | Loan EMIs, larger amounts, customers without cards. |
UPI AutoPay runs under the same framework as card mandates. The pre-debit notification requirement and the AFA thresholds apply identically. The payment instrument changes; the compliance obligation does not. That matters when you build — one set of rules, three integrations, and it is tempting to build three different rule implementations by accident.
What it is not:
- Not a stored card. A saved card you charge is not a mandate, and charging one recurringly without a registered mandate is the thing this framework exists to stop.
- Not permanent. Every mandate has a validity period the customer can change.
- Not retryable like a normal decline. See step 6 — this is the part teams get most wrong.
The whole journey, in one table
| # | Step | In plain words |
|---|---|---|
| 1 | Pick the rail | Card, UPI AutoPay, or eNACH. Often more than one. |
| 2 | Register the mandate | One authentication, up front. Get this right or nothing else runs. |
| 3 | Store what you may debit | Amount, cap, frequency, validity. This is your permission, in a row. |
| 4 | Notify, 24 hours before | Mandatory. Amount, date, merchant name. |
| 5 | Present the debit | With or without AFA, depending on amount and category. |
| 6 | When it fails | Diagnose the mode. Do not send everyone the same email. |
| 7 | Confirm, after | Post-debit notification, with the grievance route on it. |
| 8 | Modify, pause, revoke, reissue | The customer is in control, and cards get replaced. |
Steps 4, 6 and 7 are where the money is. Registration is a one-off engineering problem; collection is an operational one you will run forever, and the difference between a good and a bad implementation of step 6 is worth more than everything else on this page combined.
Steps 1 to 3 — rails, registration and limits
Step 1 — Pick the rail
Most products end up on two. Cards for reach and international, UPI AutoPay for Indian consumer volume, eNACH for larger recurring amounts and customers without cards.
The useful design decision: build the rails behind one internal mandate model, so your business logic never branches on rail. The framework treats them identically; your code should too. Teams that build three separate implementations end up with three slightly different interpretations of the same rule, and the differences surface as compliance gaps rather than bugs.
Step 2 — Register the mandate
One AFA, up front. A 3DS flow on cards, a UPI PIN in the customer's UPI app, or the bank's flow for eNACH.
Two things worth building properly at registration, because retrofitting them is painful:
- Capture the customer's preferred notification channel. They choose SMS or email, and you owe them a notification before every debit. Ask once, at registration.
- Set the variable-amount cap explicitly. If the amount can change, the customer sets an upper limit. Make that a deliberate field in your flow rather than a default you chose.
Steps 3 and 5 — What you may debit
from decimal import Decimal
# AFA (Additional Factor of Authentication -- usually OTP or UPI PIN) is
# ALWAYS required for: registration, modification, withdrawal, the FIRST
# transaction, a customer opt-out, and any debit above the threshold.
#
# After registration, recurring debits run without AFA UP TO A LIMIT.
GENERAL_LIMIT = Decimal("15000") # per recurring transaction
# The higher limit applies to EXACTLY THREE CATEGORIES. This is the most
# misreported rule in the whole framework.
ENHANCED_LIMIT = Decimal("100000")
ENHANCED_CATEGORIES = {
"INSURANCE_PREMIUM",
"MUTUAL_FUND_SIP",
"CREDIT_CARD_BILL",
}
# NOT INCLUDED: loan EMIs. Not personal loans, not BNPL instalments, not auto
# loans. An EMI above Rs 15,000 needs AFA on every single debit, and a lending
# product built on the assumption of Rs 1 lakh headroom will fail at collection
# for exactly the customers whose instalments matter most.
def needs_afa(mandate, amount: Decimal, is_first: bool) -> dict:
if is_first:
return {"afa": True, "why": "first_transaction"}
limit = (ENHANCED_LIMIT if mandate["category"] in ENHANCED_CATEGORIES
else GENERAL_LIMIT)
if amount > limit:
return {"afa": True, "why": "above_threshold", "limit": limit}
if amount > mandate["max_amount"]:
# The CUSTOMER's own cap, set at registration for variable amounts.
# Separate from the regulatory limit and often lower.
return {"afa": False, "blocked": True, "why": "exceeds_customer_cap"}
return {"afa": False}
# WHAT TO CHECK
# [ ] ENHANCED_CATEGORIES is a closed set in code, not a config someone can
# widen. Adding "LOAN_EMI" to it is a one-line compliance breach
# [ ] the customer's own cap is enforced separately from the regulatory limit,
# and a debit exceeding it is BLOCKED, not escalated to AFA
# [ ] amounts in Decimal or integer paise. Never float
# [ ] "first transaction" means first under THIS mandate, not first ever for
# this customer. A re-registered mandate has a new first transaction
# [ ] validity period is stored and enforced. A debit after expiry is
# unauthorised, and customer liability rules then apply to you
# [ ] issuers may NOT charge the customer for the e-mandate facility. If a fee
# appears anywhere in your flow, it is yours to absorb, not theirs
The ₹1 lakh exception covers insurance premiums, mutual fund subscriptions and credit card bills. It does NOT cover EMIs. This is the single most misreported line in the framework, and it is repeated confidently in a lot of published guidance. A loan instalment above ₹15,000 requires AFA on every debit. If you are building lending collections on the assumption of ₹1 lakh of headroom, your collection rate will fall off a cliff at exactly the ticket sizes that matter most to the book.
Step 4 — the notification that is a gate
Step 4 — Notify, 24 hours before
from datetime import datetime, timedelta, timezone
IST = timezone(timedelta(hours=5, minutes=30))
# 24 hours before EVERY debit. Not a courtesy -- a condition of debiting.
# It must carry the amount, the debit date and the merchant name, and it goes
# on the channel the customer chose at registration.
NOTIFY_LEAD = timedelta(hours=24)
# The only carve-out: auto-replenishment of FASTag and NCMC balances.
EXEMPT = {"FASTAG_REPLENISH", "NCMC_REPLENISH"}
def schedule_pre_debit(mandate, instalment):
if mandate["category"] in EXEMPT:
return {"required": False}
send_at = instalment["debit_at"] - NOTIFY_LEAD
return {
"required": True,
"send_at": send_at,
"channel": mandate["notify_channel"], # chosen at registration
"content": {
"amount": instalment["amount"],
"debit_date": instalment["debit_at"].astimezone(IST).date().isoformat(),
"merchant_name": mandate["merchant_display_name"],
"opt_out_url": opt_out_link(mandate, instalment), # AFA-protected
},
}
def may_debit(instalment) -> dict:
# The gate. A debit whose notification did not go out 24h earlier is not
# a debit you are entitled to present.
n = instalment.get("pre_debit_notification")
if instalment["category"] in EXEMPT:
return {"allow": True}
if not n or n["status"] != "delivered":
return {"allow": False, "why": "pre_debit_notification_not_delivered"}
if instalment["debit_at"] - n["delivered_at"] < NOTIFY_LEAD:
return {"allow": False, "why": "notification_too_late"}
if instalment.get("customer_opted_out"):
return {"allow": False, "why": "opted_out_for_this_debit"}
return {"allow": True}
# WHAT TO CHECK
# [ ] may_debit() runs at PRESENTATION time, not at scheduling time. A
# notification that failed to deliver overnight must stop the debit
# [ ] "delivered", not "sent". A queued SMS is not a notification
# [ ] the opt-out link is AFA-protected and works for a SINGLE debit as well as
# the whole mandate. Both are required and teams usually build only the second
# [ ] the merchant name in the notification is the name the customer RECOGNISES,
# not your legal entity. Unrecognised names drive chargebacks and complaints
# [ ] a moved debit date needs a fresh 24-hour notification. Rescheduling does
# not inherit the old one
# [ ] notification delivery is logged per instalment. In a dispute this is the
# evidence that you were entitled to debit at all
The gotcha nobody documents: the notification is a gate, not a message. Teams build it as a fire-and-forget alert on the scheduler and never wire the result back into the debit decision. If the SMS bounced, the number changed, or the queue backed up overnight, the debit should not go out — and in a dispute the delivery log is what proves you were entitled to present it. Check delivery at presentation time, not at scheduling time.
Steps 6 to 8 — failure, confirmation and control
Step 6 — When it fails
# A mandate failure is NOT a retryable soft decline. Retrying it is pointless:
# the mandate itself is the problem, and only the customer can fix it.
#
# THREE FAILURE MODES, THREE DIFFERENT CUSTOMER ACTIONS. Sending the same
# "update your payment method" email to all three routes people to the wrong
# action and collapses recovery.
RECOVERY = {
"mandate_missing_or_cancelled": {
"customer_action": "re-register the mandate",
"how": {"CARD": "3DS authentication", "UPI": "approve in your UPI app",
"ENACH": "re-authorise with your bank"},
"retryable_without_customer": False,
},
"above_threshold": {
"customer_action": "approve this one payment",
"how": {"CARD": "OTP for this transaction", "UPI": "UPI PIN for this transaction",
"ENACH": "authorise this debit"},
"retryable_without_customer": False,
"note": "the mandate is fine; this single amount needs AFA",
},
"pre_debit_notification_failed": {
"customer_action": "confirm in your banking app before the next attempt",
"retryable_without_customer": False,
},
"insufficient_funds": {
"customer_action": "add funds",
"retryable_without_customer": True, # the ONLY genuinely retryable one
"retry_after_days": 3,
},
}
def recovery_plan(failure, mandate):
plan = RECOVERY.get(failure["code"])
if not plan:
return {"path": "human_review", "code": failure["code"]}
msg = plan["customer_action"]
how = plan.get("how", {}).get(mandate["rail"])
return {"tell_customer": f"{msg}" + (f" — {how}" if how else ""),
"auto_retry": plan["retryable_without_customer"],
# If card re-registration goes unanswered, offer UPI AutoPay. It is
# a lower-friction registration and recovers subscribers that a
# second 3DS attempt will not.
"fallback_rail": "UPI" if mandate["rail"] == "CARD" else None}
# WHAT TO CHECK
# [ ] mandate failures are a DISTINCT failure class in your dunning logic, not
# lumped in with card declines. They behave nothing alike
# [ ] the message names the specific action. "Update your payment method" is
# wrong for two of the three modes
# [ ] auto-retry ONLY on insufficient funds, and with notice before re-presenting
# [ ] offer UPI AutoPay as a fallback when card re-registration goes unanswered.
# Different friction, different success rate, same framework
# [ ] measure recovery rate PER FAILURE MODE. A blended number hides that one of
# the three is broken
# [ ] a failure never silently stops the subscription. It starts a defined
# sequence with an end state
The gotcha nobody documents, and the most expensive one on this page: a mandate failure is not a soft decline. Ordinary card declines are retryable — the issuer might approve tomorrow. A mandate failure means the permission is broken, and no number of retries will fix it. Only the customer can, and the action they must take is different in each of the three modes. Most billing systems send one generic email to all of them, which routes people to the wrong action and quietly destroys the recovery rate. Splitting that one message into three is probably the highest-return change available in this entire product area.
Step 7 — Confirm, after
A post-debit notification after every automated collection, carrying the grievance redressal route. The framework is explicit that the grievance mechanism must be disclosed in the notification and must actually work for recurring-transaction disputes — not a generic support link.
The RBI's customer-liability rules for unauthorised transactions apply here too. A debit the customer did not authorise is not a billing dispute; it is an unauthorised transaction with clocks attached.
Step 8 — Modify, pause, revoke, reissue
| Event | What must be possible |
|---|---|
| Modify | Amount cap or validity period, by the customer, with AFA. |
| Pause | Without cancelling. Build it; customers who cannot pause, cancel. |
| Revoke | At any point, with AFA. Immediate effect on the next debit. |
| Opt out of one debit | A single skipped payment, not the whole mandate. Frequently missed. |
| Card reissued | Issuers may map existing card e-mandates to the reissued card — which removes the old problem of every mandate silently lapsing when a card expired. |
Card reissue mapping is quietly one of the most valuable changes in the 2026 framework. Mandate churn on card expiry used to be a large, invisible source of involuntary subscriber loss — the customer never chose to leave, the card simply expired. Ask your acquirer whether they support the mapping, because it is the difference between losing a cohort every three years and not.
What it costs
Recurring payments — what it costs
Verified September 2026Model involuntary churn, not just failed debits. A failed instalment that is never recovered is a lost customer who did not choose to leave. Measure recovery rate per failure mode and involuntary churn separately from voluntary cancellation — most billing dashboards collapse all three into “churn” and hide the one you can actually fix.
Three versions you could build
The starting version
Build: one rail, usually UPI AutoPay → registration with AFA → a mandate row storing category, cap, frequency and validity → a 24-hour notification job with delivery checked at presentation → post-debit confirmation with the grievance route → three distinct failure messages.
It breaks when: customers arrive without UPI, or ticket sizes cross ₹15,000 in a category without the exception.
The proper version
Build: everything above, plus — two or three rails behind one internal mandate model → the enhanced-category list as a closed set in code → the customer cap enforced separately from the regulatory limit → single-debit opt-out as well as full revocation → pause without cancel → card-reissue mapping confirmed with your acquirer → recovery rate measured per failure mode → UPI AutoPay offered as a fallback when card re-registration goes unanswered.
Trade: the rule engine is the asset. Three rails is three integrations; three interpretations of the rules is a compliance gap waiting to be found.
The version at scale
Build: everything above, plus — intelligent retry timing on the one genuinely retryable mode → notification channel optimisation → cohort-level involuntary churn reporting → a dunning sequence that escalates across rails rather than repeating on one.
If you take one thing from this page: split your dunning message into three. Cancelled mandate, above-threshold, and notification failure need three different customer actions, and one generic email serves none of them. It is a week of work and it moves recovery more than any other change available here.
What goes wrong
| What goes wrong | Why | Fix |
|---|---|---|
| EMI collections fail above ₹15,000 | The ₹1 lakh exception was assumed to cover loans. | It covers insurance, mutual funds and credit card bills only. |
| Recovery rate is poor | One generic dunning email for three different failure modes. | Three messages, three actions. |
| Debits presented without notification | The notification is fire-and-forget on the scheduler. | Check delivery at presentation time. |
| Chargebacks from unrecognised names | The legal entity name in the notification. | Use the name the customer recognises. |
| Mandates lapse on card expiry | Reissue mapping not enabled. | Ask the acquirer. It is supported now. |
| Customers cancel instead of pausing | There is no pause. | Build pause. Cancelling is a decision they cannot undo easily. |
| Three rails, three rule implementations | Each integration was built by itself. | One mandate model, three adapters. |
| A debit after expiry | Validity stored but not enforced. | Enforce it. It is an unauthorised transaction. |
Where to go next
BNPL Checkout
Where these mandates collect the instalments — and where the EMI exception bites hardest.
Payments & Reconciliation
The rails underneath, settlement timing, and matching collections to the ledger.
Customer Operations
Dunning is customer communication, and the contact window applies to it.
Account Aggregator
How you knew they could afford the instalment before you set the mandate up.
This page is a guide, not a specification. Recurring debits move customer money on a standing permission, and presenting one you are not entitled to is an unauthorised transaction rather than a billing error. Nothing here is legal advice. Have your mandate model, notification logic and dunning sequence reviewed by qualified counsel and your payment partner before the first live debit.
Sources
Every figure, rule and date on this page, and where to check it. Entries are typed so you can see which are primary-sourced and which are industry reporting.
- officialRBI — Digital Payments – E-mandate Framework, 2026 (Circular RBI/DPSS/2026-27/396, 21 April 2026) — the consolidated rulebook replacing eight earlier circulars: AFA triggers, the ₹15,000 general limit, the ₹1 lakh enhanced limit and its three categories, the 24-hour pre-debit notification, post-debit confirmation, revocation, the prohibition on customer charges, card-reissue mapping, and acquirer responsibility for merchant compliance. www.rbi.org.in
- officialRBI — customer liability in unauthorised electronic transactions — the liability framework that applies to recurring debits the customer did not authorise. www.rbi.org.in
- officialNPCI — UPI AutoPay — the UPI mandate rail, registration in the customer’s UPI app, and the mandate lifecycle. www.npci.org.in
- officialNPCI — NACH — the eNACH rail for bank-account standing instructions. www.npci.org.in
- industryPayment provider and billing-platform reporting — the failure-mode taxonomy and recovery guidance in step 6, and the observation that a single generic dunning message collapses recovery. Practitioner-sourced; test against your own cohort.
- industryFramework commentary, April–June 2026 — summaries of the 2026 framework used to cross-check the limits and exemptions. Verify any specific figure against the circular before relying on it.
Checked September 2026. This framework was rewritten in April 2026; the date is part of the claim.
Ask an AI about this page
Opens your assistant with this page as the source, and a question rather than a summary. It will ask what you are building before it answers.
Nothing is sent from here. The link carries only this page’s title and address.