18px
Payments·February 14, 2026·18 min read

Inside Payment Routing: How Razorpay Routes Your ₹100 Through 15+ Gateways in Milliseconds

What happens behind the "Pay" button—scoring, circuit breakers, retries, and how payment gateways get chosen in milliseconds.

Last month, I ordered food on Swiggy. Clicked "Pay ₹847" via UPI. Payment went through in 1.2 seconds.

What I didn't see: my payment was first sent to Razorpay's primary gateway, which timed out. It was then instantly rerouted through Paytm's gateway, which also failed. Finally, PhonePe's gateway processed it successfully.

All of this happened in under 2 seconds, and I had no idea three different systems were involved.

This is payment gateway routing—one of those invisible backend systems that seems simple but is actually a fascinating distributed systems problem. After building my own routing system to understand how it works, I want to share what happens behind that "Pay" button.

Why Can't You Just Use One Payment Gateway?

Gateway Strengths

If you're processing an Axis Bank card payment, you'd want Gateway B. For HDFC UPI, you'd want Gateway A. But how do you decide this in real-time, at scale? That's the routing problem.

What Happens When You Click "Pay"

Step 1: The Scoring Decision (~5 milliseconds)

Scoring Factors

All of this gets combined into a single score. The gateway with the highest score wins and gets tried first.

Step 2: The Circuit Breaker Check (~1 millisecond)

  • CLOSED (Healthy): Everything's normal. Success rate above 60%, timeout rate low. All requests go through.

  • OPEN (Unhealthy): Gateway is having issues. Maybe success rate dropped to 35%, or 10 requests in a row timed out. Don't try this gateway—route to backup immediately.

  • HALF-OPEN (Recovery): After 30 seconds of being OPEN, send 10% of traffic as probes. If probes succeed, re-open fully. If they fail, stay OPEN.

Circuit Breaker Example

Step 3: The Actual Gateway Call (200ms - 3000ms)

Step 4: The Retry Decision (~2 milliseconds)

  • Retryable (e.g. NETWORK_ERROR, HTTP_500): Try a different gateway.

  • Timeout-like: Don't retry! Queue for async verification. Mark as PENDING_VERIFICATION, enqueue for status check worker.

  • User errors (e.g. INSUFFICIENT_FUNDS): Don't retry, show error to user.

Example: Attempt 1 → Razorpay NETWORK_ERROR (retryable) → try next gateway. Attempt 2 → Paytm TIMEOUT → don't retry; mark PENDING_VERIFICATION; return "Payment processing..." to user. Background worker later calls Paytm's status API and updates the payment. This prevents double-charging while handling ambiguous states.

Step 5: The Latency Budget

The Metrics Pipeline: How the System Learns

What Gets Tracked

A/B Testing and Thompson Sampling

The Architecture

What This Achieves

The Hard Parts

Why I Built This

The Tech Stack

Try It Yourself

Payment routing seems simple on the surface but reveals layers of complexity. The naive solution (try A, then B) works until scale. Then you need intelligence, speed, safety, resilience, and optimization. Building this taught me how companies like Razorpay achieve 99.9% success rates—it's careful engineering across every layer.

GitHub: https://github.com/Bhup-GitHUB/payments-gateway LinkedIn: https://www.linkedin.com/in/bhupesh-k-185327366/

Filed under fieldnotesFebruary 14, 2026