◆PRISMPayRoute

12 / 12Prism Systems · FinTech & Banking

Payment routing that learns, fails over and never charges twice

A smart payment router for UPI, cards, netbanking and wallets. It scores five PSPs with decayed Bayesian success estimates and Thompson sampling, weighs fees and latency, trips per-PSP circuit breakers, detects bank-wide outages, fails over only on soft declines, and runs a status inquiry before retrying a timeout. Around it sit a compliance gate, an FX desk with DCC, and a chargeback state machine.

Zero dependenciesThompson samplingCircuit breakersSafe failoverCompliance gateChargeback FSM
Live simulator

Five PSPs, live traffic, and outages you can cause

About 14 payments a second flow from UPI, cards, netbanking and wallets through the smart router to five fictional PSPs. Each one is also replayed through four baseline routers against the same simulated network, so the comparison is fair. Take a PSP down or slow it, knock out a bank, or launch a card-testing attack, then watch the breakers, the failovers and the auth-rate gap. You can also answer chargebacks yourself.

paused
payments · smart router · PSPs
Auth rate, last 10 s
Traffic share by PSP smart router
Same payments, five routers shadow comparison
Routing decision latest card
Circuit breakers PSP × method
Chargebacks —
FX desk 250 bps markup
Events
Features

What's inside the engine

Real algorithms, not mock-ups. The simulator above runs the exact same code you import.

◎

Learns success rates

Success and failure counts per PSP × method × issuer decay with a 2-minute half-life and borrow a prior from the PSP × method level, so a new combination starts sensible and an old outage is forgotten.

⚄

Thompson sampling

The router ranks PSPs on a sample from each posterior rather than the mean. Uncertain PSPs get some traffic, and well-known bad ones get almost none.

₹

Cost and latency aware

Score = sampled success − fee ratio − latency penalty, with tunable weights. Fees include amex surcharges and cross-border uplift, all in exact integer paise.

⏻

Circuit breakers

A rolling 30 s window per PSP × method. When failures pass 50% over at least 12 calls the breaker opens. After the cooldown, a few probes decide whether it closes or reopens with a doubled cooldown.

🏦

Issuer outage detection

If the failure code says the bank is down, the PSP isn't blamed. A separate issuer breaker limits attempts to one and suggests another payment method instead of retrying.

↺

Safe failover

Only soft declines are retried, within an attempt limit and a 15 s budget. On a timeout the router asks the PSP for the payment status first, and if it was captured it stops. That is why the smart router never double-charges.

⚖

Compliance gate

Checks for sanctions, Luhn and BIN, card-on-file tokenisation, 3DS/AFA step-up, e-mandate and UPI limits, data localisation for domestic payments, and per-instrument velocity. Each block returns a code and a reason.

⇄

FX, DCC and disputes

Firm FX quotes with markup and expiry, a DCC versus card-network comparison, and a chargeback state machine with deadlines, evidence scoring, pre-arbitration and 3DS liability shift.

How it works

From request to result

Normalise

Validate the method, currency and amount (exact minor units), look up the BIN, and redact the card number so it is never stored.

Gate

Compliance blocks, asks for 3DS/AFA, or restricts the payment to PSPs that store data in India.

Rank

Eligible PSPs are scored from a Thompson sample minus fee and latency. Breaker state and merchant rules are applied, and every row records why it was ranked or excluded.

Attempt

Try the best PSP. Success ends it, a hard decline ends it, and a soft decline fails over. A timeout triggers a status inquiry first.

Learn

Only technical outcomes update the estimates and breakers. Issuer-wide failures feed the issuer breaker, and hard declines teach nothing about the PSP.

Architecture

System design

Every box is a module in src/. Data flows left to right.

learnCHECKOUTHTTP APIIdempotency-KeyNormaliseBIN · redact PANDECIDECompliance3DS · limits · localisationRankerThompson · fee · latencyEXECUTEBreakersPSP · issuerAttemptsfailover · inquiryAFTERFX deskquote · DCCChargebacksFSM · deadlines
Use it

Ship it in your own stack

Zero dependencies. Works in Node.js 18+ and modern browsers.

example.js
import { Gateway, Router, Network, Platform } from "prism-payroute";

const gw = new Gateway({ router: new Router({ strategy: "smart", costWeight: 1, latencyWeight: 0.3 }) });

// Dry run: compliance + every PSP's score, or why it was excluded
gw.route({ method: "card", amount: "2499.00", threeDS: true, card: { pan: "4111111111111111" } });

// Real attempt with idempotency: same key + same body replays, a different body is a 409
const r = gw.pay({ method: "upi", amount: "499", vpa: "asha@oksahy" }, "order-1042");
r.status;     // "captured" | "declined" | "failed" | "blocked" | "requires_action"
r.attempts;   // [{ psp, n, code, latency, inquiry? }]

// Compare routers on identical traffic and incidents
const P = new Platform({ seed: 12 });
P.run(60); P.outage("neorail", { secs: 60 }); P.run(60);
P.report().strategies.smart.authRate;  // vs .cheapest, .static, .round-robin, .naive-retry

gw.fx.quote(12000, "USD", "INR");      // firm quote with markup and expiry
gw.disputes.act(id, "represent", { evidence: ["delivery", "comms"] });
terminal
$ npx github:krishyaa06/prism-payroute demo
$ npx github:krishyaa06/prism-payroute simulate --scenario mixed --seconds 180
$ npx github:krishyaa06/prism-payroute route --method card --issuer DECN --amount 4500
$ npx github:krishyaa06/prism-payroute fx --from USD --to INR --amount 120
$ npx github:krishyaa06/prism-payroute dispute
$ npx github:krishyaa06/prism-payroute serve --port 8790
terminal
# use the CLI without installing
$ npx github:krishyaa06/prism-payroute --help

# or add the engine to your project
$ npm install github:krishyaa06/prism-payroute

# run the simulator locally
$ git clone https://github.com/krishyaa06/prism-payroute.git && cd prism-payroute
$ npx serve .   # then open http://localhost:3000