How to Add MoltPe Alongside Razorpay (Two-Rail Payment Stack)
Why Teams Add a Second Rail to Razorpay
Razorpay is the backbone for hundreds of thousands of Indian businesses. UPI integration, card support, netbanking, EMI, the merchant dashboard, the disputes flow — all polished. Domestic INR is solved.
The pressure to add a second rail comes from workloads that fall outside that domestic INR core:
- International receipts. Indian SaaS founders selling abroad pay cross-border surcharges and FX spread on every Razorpay International transaction. For US-heavy revenue, USDC settlement is materially cheaper.
- AI agent and per-call billing. Razorpay's minimum charge and card-rail mechanics rule out fractional-cent metering. An AI API priced at one cent per call needs a different rail.
- Pay-out to global contractors and APIs. Sending USD to a Filipino designer or a Texas-based AI service through Razorpay is awkward. USDC settles in seconds with a wallet address.
- Dollar-denominated reserves. Some founders want to hold a portion of revenue in dollars, not INR, for predictable USD spend on cloud bills and US contractor payouts. USDC enables that without a foreign bank account.
The two-rail model preserves everything Razorpay does well and routes the workloads above to a rail built for them.
What Razorpay Handles vs What MoltPe Handles
The split is along buyer type and currency, not feature parity. Razorpay wins for any payer who would naturally pay in INR. MoltPe wins for everything else.
| Workload | Best Rail | Why |
|---|---|---|
| Indian customer paying in INR (UPI/card/netbanking) | Razorpay | Best UX, lowest fees, instant local settlement |
| EMI on consumer purchases | Razorpay | Native EMI integration with banks and BNPL providers |
| International customer paying in USD | MoltPe (or both) | USDC settles instantly with no FX spread |
| AI agent paying for an API call | MoltPe | x402 + isolated wallets + spending policy |
| Sub-dollar metered usage | MoltPe | No fixed-fee floor on USDC payments |
| Subscription billing on Indian cards | Razorpay | RBI mandate handling and recurring payment rails are mature |
| Paying overseas contractors | MoltPe | USDC payout to wallet; faster than international wire |
The decision tree at runtime is short: Indian payer? Razorpay. International payer or agent? MoltPe. Anything ambiguous? Default to Razorpay and offer USDC as an option.
Migration Prep Checklist
This is an addition, not a replacement, so prep is lighter than a full migration. Twenty minutes per item is enough.
- Audit the last 90 days of Razorpay transactions. Tag each by buyer country and use case. The tagged subset where MoltPe would be cheaper is your migration scope.
- Open a MoltPe account. Sign up at moltpe.com/dashboard, generate a
mp_test_key, and run the 5-minute quickstart. - Define the routing signals. Pick the fields that drive the decision:
payer.country,payer.type,amount,currency. These need to be reliably populated in your request payload. - Pick the off-ramp. Decide whether USDC stays in MoltPe wallets, gets converted to INR through a registered exchange, or is held in a treasury wallet for outbound spend.
- Update your terms and checkout copy. Add a "Pay with USDC" option for international flows. The dashboard provides a hosted checkout link if you do not want to build your own.
- Set up unified webhooks. Both Razorpay and MoltPe push events on completion. Route both to the same handler that writes to a single
transactionstable tagged withrail.
Routing Logic: Picking the Right Rail Per Request
The router is the heart of the two-rail stack. Keep it dumb and explicit.
// Two-rail router. Picks Razorpay or MoltPe based on payer signals.
// Default to Razorpay so existing flows stay unchanged.
function pickRail({ payerCountry, payerType, amountUsd, currency }) {
// AI agents always pay through MoltPe.
if (payerType === "agent") return "moltpe";
// Sub-dollar charges only work on MoltPe.
if (amountUsd < 1) return "moltpe";
// International payers prefer USDC for FX savings.
if (payerCountry !== "IN" && currency === "USD") return "moltpe";
// Everyone else (Indian human payers in INR) goes to Razorpay.
return "razorpay";
}
Then a single checkout entry point dispatches to the right SDK:
// One checkout endpoint. Two backends behind it.
import Razorpay from "razorpay";
const rzp = new Razorpay({
key_id: process.env.RAZORPAY_KEY_ID,
key_secret: process.env.RAZORPAY_KEY_SECRET,
});
app.post("/api/checkout", async (req, res) => {
const rail = pickRail(req.body);
if (rail === "razorpay") {
const order = await rzp.orders.create({
amount: req.body.amountInr * 100, // paise
currency: "INR",
receipt: req.body.invoiceId,
});
return res.json({ rail, order });
}
// MoltPe path: hosted invoice link or x402 endpoint.
const moltpeRes = await fetch("https://api.moltpe.com/v1/invoices/create", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.MOLTPE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
invoice_number: req.body.invoiceId,
amount: req.body.amountUsd.toFixed(2),
token: "USDC",
network: "polygon",
recipient_agent_id: process.env.MOLTPE_TREASURY_AGENT_ID,
}),
});
const invoice = await moltpeRes.json();
res.json({ rail, hosted_payment_url: invoice.hosted_payment_url });
});
The reconciliation job pulls events from both webhooks and writes to one table. Finance sees one ledger; engineering sees two SDKs. Both teams stay happy.
Rollout Plan: Three Phases
Phase 1 — Parallel (week 1 to 2). Add the MoltPe rail behind a feature flag for a single use case — usually international SaaS receipts. Show "Pay with USDC" as an additional option, not a replacement. Track conversion and fee delta against the baseline Razorpay International numbers.
Phase 2 — Primary for matching workloads (week 3 to 6). For workloads where MoltPe wins on fee and speed (international, agent, sub-dollar), default to MoltPe. Razorpay remains the default for INR. Both checkouts coexist on the same site.
Phase 3 — Steady state (week 7 onward). The router becomes the single source of truth. Both rails are first-class. The only thing left to deprecate is internal documentation that says "we use Razorpay for everything" — update the README and onboard the team to think in two rails.
Risks and Rollback
The risks are mostly operational. Webhook double-processing — both rails fire events; idempotency keys at the database layer prevent double-counting. Customer confusion — some buyers do not know what USDC is; have a one-paragraph explainer next to the option. FX accounting — record USDC receipts at the spot rate on receipt date for clean tax filing.
Rollback is per-route, not all-or-nothing. If MoltPe traffic for a specific use case underperforms, change the router to send that case back to Razorpay. The Razorpay integration was never disturbed, so there is nothing to restore.
Frequently Asked Questions
Why not just replace Razorpay entirely?
Razorpay is excellent at what it does: domestic INR payments via UPI, cards, netbanking, and EMI. Replacing that with anything else, including MoltPe, makes life harder for your Indian customers and breaks reconciliation flows your finance team relies on. Add MoltPe for the workloads it is genuinely better at; keep Razorpay for everything else.
How does my code decide which rail to use?
A small router function on the backend. The decision usually comes down to three signals: payer country (India vs international), payer type (human vs AI agent), and price point (above or below the dollar mark for sub-dollar billing). The code example in this guide shows a 30-line router that handles all three cleanly.
Can I reconcile both rails in one place?
Yes. Most teams write a small daily job that pulls Razorpay payouts and MoltPe transactions, normalizes them into a single transactions table with a rail column, and feeds that into the existing accounting tool. Both systems expose webhook events with stable IDs, so reconciliation is straightforward once the schema is unified.
What happens if MoltPe is down? Does Razorpay take over?
Only for transactions where Razorpay can serve the same buyer. An international USDC payer cannot be sent to Razorpay because Razorpay does not accept USDC. The clean fallback rule is: if a request matches multiple rails, prefer the primary; if MoltPe is down for an MoltPe-only flow, return a clear error and queue for retry rather than silently routing somewhere it does not belong.
Will having two rails confuse my finance and tax filings?
Not if you keep clean labels. Tag every transaction with its rail at write time and reconcile to one ledger. Razorpay payouts settle as INR receipts; MoltPe USDC receipts are typically reported as foreign-currency income converted at receipt date. Talk to your chartered accountant about the specifics for your entity type before going live.
One backend, two rails
Keep Razorpay for INR. Add MoltPe for international and agent flows. Twenty minutes to wire the router.
Add the second rail →About MoltPe
MoltPe is AI-native payment infrastructure that gives AI agents isolated wallets with programmable spending policies for autonomous USDC transactions. Live on Polygon PoS, Base, and Tempo. Supports REST, MCP, and x402.