Regional gateways
Some markets are served better by a local gateway than by Stripe: local cards, local wallets, local recurring-payment rules. We integrated an India gateway (PayU) and a GCC gateway (Telr). This page is what they taught us. Read it before you add any gateway that is not Stripe.
How it works
Prefer gateways that own the schedule. If we build the recurring logic ourselves, we own a permanent class of "we forgot to charge someone" and "we charged twice" bugs.
What is different from Stripe
| Topic | What we found |
|---|---|
| Returning from the payment page | Often a form POST, not a redirect. The page that receives it must accept POST |
| Callbacks | Sometimes missing in practice. Treat the browser return as a trigger to ask the gateway, never as proof |
| State | Some gateways can only describe the first payment. An order check said "active" in month four for a cancelled agreement |
| Signatures | Hand-built: a SHA-512 over pipe-joined fields plus a salt, in a different field order for request and response. Compare in constant time |
| Zero amounts | Not allowed. A trial needs a small registration charge, and the trial must say so |
| Test and live | One merchant account with a per-order test flag, or separate hosts. Pick the host from the checkout's environment |
| Time zones | Dates in the gateway's local time (IST, Dubai time). A UTC date can name yesterday |
| Personal data | Callbacks can carry name, email, phone and address. Redact before storing |
| Cancelling | Not always possible by API. Check before you sell renewals |
India: recurring payments
As of October 2026. Source: RBI e-mandate framework.
- A recurring card or UPI debit needs an e-mandate set up by the customer.
- The customer gets a pre-debit notice 24 hours before each charge.
- Debits above about ₹15,000 need extra authentication, so a mandate ceiling sits at that cap.
- The mandate's maximum amount is fixed when it is created. A price rise above it needs a new mandate.
- A card mandate dies with the card. A UPI mandate does not.
- Some Indian banks decline recurring debits even through Stripe. Expect a higher renewal failure rate in India on any rail.
Getting a merchant account
Merchant approval takes longer than the code. Plan for it in the kickoff.
- KYC needs live public pages for each brand: terms, privacy, refund and cancellation, contact, and pricing.
- Recurring billing is often a separate underwriting step, 1 to 3 weeks.
- New merchants may get a rolling reserve and slower settlement.
- Our estimate from one launch: web in one market 4 to 6 weeks, Android 6 to 8, iOS 8 to 10, everything with trials 10 to 12.
Rules
Verify a payment by asking the gateway, keyed on our own checkout id. Make the webhook and the browser return land on the same row with the same key, under a lock, so they cannot both create it.
Build the billing period from the plan's duration. Never assume monthly. A quarterly plan on a gateway agreement built as "monthly" charges every month.
A charge that lands on a refunded or replaced subscription is flagged
charged_after_stop, never re-entitled, and goes to support for a refund.
Mistakes we made
- A webhook and the browser return arrived in the same second and deadlocked
Postgres. Fixed with a transaction-scoped advisory lock on (connection, gateway
subscription) and
SKIP LOCKEDwhen closing the checkout. - A lifetime purchase expired in 2125 or never, depending on which path won. The webhook used a 99-year placeholder, verify used "no end". Lifetime is now its own duration.
- The first live order failed authentication. The gateway refused its JSON API for that merchant account, while the form-encoded API worked with the same key.
- A full refund did not stop the agreement, so the next month charged again. Stopping billing is now part of every refund.
- "Is this recurring?" was guessed from whether a mandate ceiling was set. Plans now
say
kind: subscription | one_timeexplicitly. - A shared test database destroyed a running demo three times in one session. Tests get their own database.
Checklist
- The gateway owns the renewal schedule, or we have decided to own it on purpose.
- The return URL accepts POST and only triggers a server check.
- Webhook and verify use one key and one lock.
- Signatures are checked in constant time, with the right field order each way.
- Dates are converted from the gateway's time zone.
- Personal data in callbacks is redacted before storage.
- Refunds stop future billing.
- Merchant KYC pages are live for every brand.