HyperSwitch: The Open-Source Payments Orchestrator That Replaces Your PSP Stack
HyperSwitch: The Open-Source Payments Orchestrator That Replaces Your PSP Stack
You integrate Stripe. Then Adyen for Europe. Then Braintree for PayPal. Then a local acquirer for Brazil. Each has its own SDK, webhook format, retry logic, and fee structure. Your codebase grows if (provider === 'stripe') branches like kudzu.
This is the problem HyperSwitch solves.
What Actually Is HyperSwitch?
HyperSwitch is an open-source payments orchestration platform — 45.6k GitHub stars, Apache 2.0, written in Rust, battle-tested at 300M daily transactions and $1T+ annual TPV by Juspay (India's largest payments processor). It sits between your application and 120+ payment processors, providing a single API that handles routing, retries, vaulting, reconciliation, and cost observability.
Think of it as the Linux of payments: you integrate once, then plug in whichever processors you need.
The Architecture That Makes It Work
Router + Scheduler: Two Services, One Job
HyperSwitch runs as two stateless Rust binaries:
Router — The hot path. Handles every payment request: authentication, FRM checks, 3DS decisions, connector selection via the Euclid routing engine, credential resolution from the vault, and connector dispatch through the Connector Abstraction Layer (CAL).
Scheduler — Background jobs. Producer batches scheduled tasks (card cleanup, API key expiry notices) into Redis queues; Consumer executes them. Horizontal scaling is trivial — any instance can handle any request.
All state lives in PostgreSQL. Redis handles caching, distributed locks, and the scheduler queue.
The Payment State Machine: Intent vs Attempt
This is where most orchestrators get it wrong. HyperSwitch separates two concepts:
- payment_intent — The merchant's request. One per checkout session. Holds amount, currency, customer, capture method, setup_future_usage.
- payment_attempt — A single authorization try against a specific PSP. Multiple attempts per intent (retries). Each has its own connector, connector_transaction_id, error_code, error_details.
When a retry happens, a new payment_attempt is created. The merchant-facing payment_id never changes — only the internal suffix (pay_abc_1, pay_abc_2) sent to the PSP changes.
Euclid: Routing That Isn't Just Round-Robin
The Euclid routing engine evaluates strategies in strict priority order:
1. Rule-based — Merchant-defined conditions: payment_method_type = visa AND country = DE AND amount > 10000 → use Adyen
2. Volume-based — Percentage split across eligible connectors
3. Cost-based — Select lowest MDR (merchant discount rate) among eligible
4. Default fallback — Ordered priority list from merchant config
After selection, eligibility analysis runs: Does this connector support the payment method + currency? Is it enabled for this profile? If any check fails, Euclid moves to the next candidate. Exhaust the list → payment fails without a single PSP call.
GSM: Normalizing 120+ Error Languages
Every PSP returns proprietary error codes. Stripe's card_declined ≠ Adyen's REFUSED ≠ Braintree's 2001. GSM (Global Status Monitoring) maps (connector, error_code, error_message) → standardized unified_code + retry flags:
| Flag | Meaning |
|------|---------|
| retriable | Any retry eligible |
| step_up_possible | 3DS challenge could succeed |
| clear_pan_possible | Network token failed, try raw PAN |
| alternate_network_possible | Switch debit network (Visa → Maestro) |
The retry decision flow is deterministic: GSM lookup → check flags in order (Step-Up → Clear PAN → Network → Cascading) → do_retry() creates new payment_attempt → re-enter Euclid.
The Vault: PCI Compliance Without the Pain
The Card Vault is a separate microservice. Sensitive data never touches your Router — or your application if you use the client-side SDK.
Tokenization flow (client-side): SDK → Vault /session_tokens → JWE-encrypted request → Vault decrypts, stores PAN, returns payment_method_id → Your backend sends payment_method_id to Router → Router calls Vault Locker API → Vault returns credential (PAN, network token, or proxy reference) → Router dispatches to PSP.
Key management: Custodian-based. Master key derived from multiple custodian shares (Shamir's Secret Sharing). Vault only activates when quorum of custodians unlock it. Zero data egress in self-hosted mode.
Reconciliation: Double-Entry for Payments
Merchants routing across PSPs get separate settlement reports — different formats, different schedules. HyperSwitch's reconciliation engine applies double-entry bookkeeping: every payment event generates balanced debit/credit ledger entries.
- 2-way: Hyperswitch ledger ↔ PSP settlement report
- 3-way: Hyperswitch ledger ↔ PSP settlement ↔ OMS order data
Auto-fetch pipelines pull reports from PSPs (SFTP, API, email), normalize via connector-specific rules, match on connector_transaction_id + amount + date with configurable tolerance windows, age unmatched entries, and surface exceptions in the Control Center.
What It Replaces
| Paid Stack | HyperSwitch Module |
|------------|-------------------|
| Stripe + Adyen + Braintree integrations | Single API, 120+ connectors |
| Custom routing logic | Euclid engine (rules, volume, cost) |
| Manual retry code | GSM-driven smart retries (4 strategies) |
| PCI vault (TokenEx, VGS) | Built-in Card Vault + Network Tokens |
| Spreadsheet reconciliation | Automated 2/3-way engine |
| DataDog/New Relic for payments | Cost Observability dashboards |
Self-Hosting: What You Actually Need
# docker-compose.yml (simplified)
services:
router:
image: juspaydotin/hyperswitch-router:latest
environment:
- DATABASE_URL=postgres://...
- REDIS_URL=redis://...
- LOCKER_URL=http://vault:8080
ports: ["8080:8080"]
vault:
image: juspaydotin/hyperswitch-locker:latest
environment:
- DATABASE_URL=postgres://...
- CUSTODIAN_KEYS=...
ports: ["8081:8081"]
scheduler:
image: juspaydotin/hyperswitch-scheduler:latest
environment:
- DATABASE_URL=postgres://...
- REDIS_URL=redis://...
postgres: ...
redis: ...
Deploy via Docker Compose, Kubernetes (Helm), or AWS CloudFormation. Control Center (React dashboard) runs separately for routing config, analytics, and exception management.
The Trade-offs
Not a drop-in Stripe replacement. You operate infrastructure. PCI-SSS validation requires the Encryption Service + custodian ceremony. Connector coverage is broad but not infinite — niche local methods may need custom connectors (template provided). The learning curve is real: routing rules, GSM mappings, vault activation.
But you get: Zero vendor lock-in. Full visibility into every hop. Routing logic in config, not code. No per-transaction markup. Apache 2.0 — fork it, extend it, audit it.
When to Adopt
- Multiple PSPs already, or planning to add them
- Team capable of running PostgreSQL + Redis + Rust services
- Need routing/retries/vault/reconciliation as configurable infrastructure
- Willing to invest in ops for long-term control
Start Here
# Quick local test
git clone https://github.com/juspay/hyperswitch
cd hyperswitch/docker
docker compose up -d
# Router at localhost:8080, Control Center at localhost:3000
Read the architecture deep-dive for the Router internals, Vault architecture for tokenization internals, and Reconciliation architecture for the ledger model.
---
The payments stack you'd build if you had 12 years and 300M daily transactions to refine it. Now you don't have to.
Hyperswitch: open-source payments infrastructure that routes across Stripe, Adyen and 120+ processors (45k stars)
If you've ever built anything that takes money, you know the pain. Each processor has its own API, its own quirks, and its own way of failing at 2 AM. Hyperswitch sits in the middle and gives you one layer to control it all.
The part that caught my eye is intelligent routing. Each transaction goes to the processor with the highest predicted approval rate, across Stripe, Adyen, Braintree, Worldpay, Checkout.com and 120+ others. Fewer failed payments, less downtime.
And it's modular. You don't have to adopt everything. Pick only what you need: a PCI-compliant vault for cards and tokens, revenue recovery with smart retries, automated reconciliation, cost observability to spot hidden fees, or drop-in widgets for PayPal, Apple Pay, Google Pay and Klarna.
Trying it is easy. One setup script spins up a local Docker install, and there's a hosted sandbox if you just want to click around the Control Center first.
It's written mostly in Rust, which is a nice fit for something this sensitive.
Is it perfect? No. Payments are never simple, and running your own payment stack means owning compliance, monitoring and uptime. For a small shop with one processor, it's probably overkill. But if you're juggling multiple processors, this could save you real money.
|Field|Value|
|:-|:-|
|Stars|45,281|
|Forks|6,422|
|Last release|2026-09-28|
|Languages|Rust 81.7%, JavaScript 17.1%, MDX 0.5%|
juspay/hyperswitch
18 points
Mentions
HyperSwitch: The Open-Source Payments Orchestrator That Replaces Your PSP Stack HyperSwitch: The Open-Source Payments Orchestrator That Replaces Your PSP Stack You integrate Stripe. Then Adyen for Europe. Then Braintree for PayPal. Then a local acquirer for Brazil. Each has its own SDK, webhook format, retry logic, and fee structure. Your codebase grows if (provider === 'stripe') branches like kudzu. This is the problem HyperSwitch solves. What Actually Is HyperSwitch? HyperSwitch is an open-source payments orchestration platform — 45.6k GitHub stars, Apache 2.0, written in Rust, battle-tested at 300M daily transactions and $1T+ annual TPV by Juspay (India's largest payments processor). It sits between your application and 120+ payment processors, providing a single API that handles routing, retries, vaulting, reconciliation, and cost observability. Think of it as the Linux of payments: you integrate once, then plug in whichever processors you need. The Architecture That Makes It Work Router + Scheduler: Two Services, One Job HyperSwitch runs as two stateless Rust binaries: Router — The hot path. Handles every payment request: authentication, FRM checks, 3DS decisions, connector selection via the Euclid routing engine, credential resolution from the vault, and connector dispatch through the Connector Abstraction Layer (CAL). Scheduler — Background jobs. Producer batches scheduled tasks (card cleanup, API key expiry notices) into Redis queues; Consumer executes them. Horizontal scaling is trivial — any instance can handle any request. All state lives in PostgreSQL. Redis handles caching, distributed locks, and the scheduler queue. The Payment State Machine: Intent vs Attempt This is where most orchestrators get it wrong. HyperSwitch separates two concepts: - payment_intent — The merchant's request. One per checkout session. Holds amount, currency, customer, capture method, setup_future_usage. - payment_attempt — A single authorization try against a specific PSP. Multiple attempts per intent (retries). Each has its own connector, connector_transaction_id, error_code, error_details. When a retry happens, a new payment_attempt is created. The merchant-facing payment_id never changes — only the internal suffix (pay_abc_1, pay_abc_2) sent to the PSP changes. Euclid: Routing That Isn't Just Round-Robin The Euclid routing engine evaluates strategies in strict priority order: 1. Rule-based — Merchant-defined conditions: payment_method_type = visa AND country = DE AND amount > 10000 → use Adyen 2. Volume-based — Percentage split across eligible connectors 3. Cost-based — Select lowest MDR (merchant discount rate) among eligible 4. Default fallback — Ordered priority list from merchant config After selection, eligibility analysis runs: Does this connector support the payment method + currency? Is it enabled for this profile? If any check fails, Euclid moves to the next candidate. Exhaust the list → payment fails without a single PSP call. GSM: Normalizing 120+ Error Languages Every PSP returns proprietary error codes. Stripe's card_declined ≠ Adyen's REFUSED ≠ Braintree's 2001. GSM (Global Status Monitoring) maps (connector, error_code, error_message) → standardized unified_code + retry flags: | Flag | Meaning | |------|---------| | retriable | Any retry eligible | | step_up_possible | 3DS challenge could succeed | | clear_pan_possible | Network token failed, try raw PAN | | alternate_network_possible | Switch debit network (Visa → Maestro) | The retry decision flow is deterministic: GSM lookup → check flags in order (Step-Up → Clear PAN → Network → Cascading) → do_retry() creates new payment_attempt → re-enter Euclid. The Vault: PCI Compliance Without the Pain The Card Vault is a separate microservice. Sensitive data never touches your Router — or your application if you use the client-side SDK. Tokenization flow (client-side): SDK → Vault /session_tokens → JWE-encrypted request → Vault decrypts, stores PAN, returns payment_method_id → Your backend sends payment_method_id to Router → Router calls Vault Locker API → Vault returns credential (PAN, network token, or proxy reference) → Router dispatches to PSP. Key management: Custodian-based. Master key derived from multiple custodian shares (Shamir's Secret Sharing). Vault only activates when quorum of custodians unlock it. Zero data egress in self-hosted mode. Reconciliation: Double-Entry for Payments Merchants routing across PSPs get separate settlement reports — different formats, different schedules. HyperSwitch's reconciliation engine applies double-entry bookkeeping: every payment event generates balanced debit/credit ledger entries. - 2-way: Hyperswitch ledger ↔ PSP settlement report - 3-way: Hyperswitch ledger ↔ PSP settlement ↔ OMS order data Auto-fetch pipelines pull reports from PSPs (SFTP, API, email), normalize via connector-specific rules, match on connector_transaction_id + amount + date with configurable tolerance windows, age unmatched entries, and surface exceptions in the Control Center. What It Replaces | Paid Stack | HyperSwitch Module | |------------|-------------------| | Stripe + Adyen + Braintree integrations | Single API, 120+ connectors | | Custom routing logic | Euclid engine (rules, volume, cost) | | Manual retry code | GSM-driven smart retries (4 strategies) | | PCI vault (TokenEx, VGS) | Built-in Card Vault + Network Tokens | | Spreadsheet reconciliation | Automated 2/3-way engine | | DataDog/New Relic for payments | Cost Observability dashboards | Self-Hosting: What You Actually Need # docker-compose.yml (simplified) services: router: image: juspaydotin/hyperswitch-router:latest environment: - DATABASE_URL=postgres://... - REDIS_URL=redis://... - LOCKER_URL=http://vault:8080 ports: ["8080:8080"] vault: image: juspaydotin/hyperswitch-locker:latest environment: - DATABASE_URL=postgres://... - CUSTODIAN_KEYS=... ports: ["8081:8081"] scheduler: image: juspaydotin/hyperswitch-scheduler:latest environment: - DATABASE_URL=postgres://... - REDIS_URL=redis://... postgres: ... redis: ... Deploy via Docker Compose, Kubernetes (Helm), or AWS CloudFormation. Control Center (React dashboard) runs separately for routing config, analytics, and exception management. The Trade-offs Not a drop-in Stripe replacement. You operate infrastructure. PCI-SSS validation requires the Encryption Service + custodian ceremony. Connector coverage is broad but not infinite — niche local methods may need custom connectors (template provided). The learning curve is real: routing rules, GSM mappings, vault activation. But you get: Zero vendor lock-in. Full visibility into every hop. Routing logic in config, not code. No per-transaction markup. Apache 2.0 — fork it, extend it, audit it. When to Adopt - Multiple PSPs already, or planning to add them - Team capable of running PostgreSQL + Redis + Rust services - Need routing/retries/vault/reconciliation as configurable infrastructure - Willing to invest in ops for long-term control Start Here # Quick local test git clone https://github.com/juspay/hyperswitch cd hyperswitch/docker docker compose up -d # Router at localhost:8080, Control Center at localhost:3000 Read the architecture deep-dive for the Router internals, Vault architecture for tokenization internals, and Reconciliation architecture for the ledger model. --- The payments stack you'd build if you had 12 years and 300M daily transactions to refine it. Now you don't have to.
😤 接支付通道一家家对接,手续费还吃一层。Hyperswitch 4.5 万星开源支付平台,几十家通道收进一个接口,换通道不改业务代码,还能自己部署。 juspay/hyperswitch
@martin_valchev_ It's built with NextJs & Typescript, powered by juspay/streamgres
@Joi2James try out: juspay/streamgres This is powering xyne.ai
We also open-sourced Streamgres during the session. The code is available here: juspay/streamgres
Cool new sync engine, just open sourced today juspay/streamgres
Hyperswitch: open-source payments infrastructure that routes across Stripe, Adyen and 120+ processors (45k stars) If you've ever built anything that takes money, you know the pain. Each processor has its own API, its own quirks, and its own way of failing at 2 AM. Hyperswitch sits in the middle and gives you one layer to control it all. The part that caught my eye is intelligent routing. Each transaction goes to the processor with the highest predicted approval rate, across Stripe, Adyen, Braintree, Worldpay, Checkout.com and 120+ others. Fewer failed payments, less downtime. And it's modular. You don't have to adopt everything. Pick only what you need: a PCI-compliant vault for cards and tokens, revenue recovery with smart retries, automated reconciliation, cost observability to spot hidden fees, or drop-in widgets for PayPal, Apple Pay, Google Pay and Klarna. Trying it is easy. One setup script spins up a local Docker install, and there's a hosted sandbox if you just want to click around the Control Center first. It's written mostly in Rust, which is a nice fit for something this sensitive. Is it perfect? No. Payments are never simple, and running your own payment stack means owning compliance, monitoring and uptime. For a small shop with one processor, it's probably overkill. But if you're juggling multiple processors, this could save you real money. |Field|Value| |:-|:-| |Stars|45,281| |Forks|6,422| |Last release|2026-09-28| |Languages|Rust 81.7%, JavaScript 17.1%, MDX 0.5%| juspay/hyperswitch