Payment Orchestration with HyperSwitch: Why One Payment Gateway Isn't Enough
Deep dive into payment orchestration platform self-hosted — lessons from building HyperSwitch at TechSaaS.
Understanding the Problem
Deep dive into payment orchestration platform self-hosted — lessons from building HyperSwitch at TechSaaS.
<div style="margin:2.5rem auto;max-width:600px;width:100%;text-align:center;"><svg viewBox="0 0 600 180" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;"><rect width="600" height="180" rx="12" fill="#1a1a2e"/><rect x="20" y="20" width="70" height="35" rx="6" fill="#3b82f6" opacity="0.8"/><text x="55" y="42" text-anchor="middle" fill="#ffffff" font-size="10" font-family="system-ui">Web</text><rect x="20" y="65" width="70" height="35" rx="6" fill="#3b82f6" opacity="0.8"/><text x="55" y="87" text-anchor="middle" fill="#ffffff" font-size="10" font-family="system-ui">Mobile</text><rect x="20" y="110" width="70" height="35" rx="6" fill="#3b82f6" opacity="0.8"/><text x="55" y="132" text-anchor="middle" fill="#ffffff" font-size="10" font-family="system-ui">IoT</text><rect x="150" y="20" width="120" height="130" rx="10" fill="#6366f1" opacity="0.9"/><text x="210" y="50" text-anchor="middle" fill="#ffffff" font-size="12" font-family="system-ui" font-weight="bold">Gateway</text><line x1="165" y1="60" x2="255" y2="60" stroke="#ffffff" stroke-width="0.5" opacity="0.3"/><text x="210" y="80" text-anchor="middle" fill="#ffffff" font-size="9" font-family="system-ui">Rate Limit</text><text x="210" y="95" text-anchor="middle" fill="#ffffff" font-size="9" font-family="system-ui">Auth</text><text x="210" y="110" text-anchor="middle" fill="#ffffff" font-size="9" font-family="system-ui">Load Balance</text><text x="210" y="125" text-anchor="middle" fill="#ffffff" font-size="9" font-family="system-ui">Transform</text><text x="210" y="140" text-anchor="middle" fill="#ffffff" font-size="9" font-family="system-ui">Cache</text><rect x="340" y="15" width="95" height="35" rx="6" fill="#a855f7" opacity="0.8"/><text x="387" y="37" text-anchor="middle" fill="#ffffff" font-size="10" font-family="system-ui">Service A</text><rect x="340" y="60" width="95" height="35" rx="6" fill="#2dd4bf" opacity="0.8"/><text x="387" y="82" text-anchor="middle" fill="#1a1a2e" font-size="10" font-family="system-ui">Service B</text><rect x="340" y="105" width="95" height="35" rx="6" fill="#f59e0b" opacity="0.8"/><text x="387" y="127" text-anchor="middle" fill="#1a1a2e" font-size="10" font-family="system-ui">Service C</text><rect x="490" y="55" width="80" height="45" rx="6" fill="none" stroke="#e2e8f0" stroke-width="1"/><text x="530" y="82" text-anchor="middle" fill="#e2e8f0" font-size="10" font-family="system-ui">DB / Cache</text><defs><marker id="arrow7" markerWidth="8" markerHeight="6" refX="8" refY="3" orient="auto"><path d="M0,0 L8,3 L0,6" fill="#e2e8f0"/></marker></defs><line x1="92" y1="37" x2="148" y2="55" stroke="#e2e8f0" stroke-width="1" marker-end="url(#arrow7)"/><line x1="92" y1="82" x2="148" y2="85" stroke="#e2e8f0" stroke-width="1" marker-end="url(#arrow7)"/><line x1="92" y1="127" x2="148" y2="115" stroke="#e2e8f0" stroke-width="1" marker-end="url(#arrow7)"/><line x1="272" y1="55" x2="338" y2="32" stroke="#e2e8f0" stroke-width="1" marker-end="url(#arrow7)"/><line x1="272" y1="85" x2="338" y2="77" stroke="#e2e8f0" stroke-width="1" marker-end="url(#arrow7)"/><line x1="272" y1="115" x2="338" y2="122" stroke="#e2e8f0" stroke-width="1" marker-end="url(#arrow7)"/><line x1="437" y1="77" x2="488" y2="77" stroke="#e2e8f0" stroke-width="1" marker-end="url(#arrow7)"/></svg><p style="margin-top:0.75rem;font-size:0.85rem;color:#94a3b8;font-style:italic;line-height:1.4;">API gateway pattern: a single entry point handles auth, rate limiting, and routing to backend services.</p></div>
At TechSaaS, we build and operate production systems that serve real users. Every technical decision we make is battle-tested.
In this article, we'll dive deep into the practical aspects of payment orchestration with hyperswitch: why one payment gateway isn't enough, sharing real code, real numbers, and real lessons from production.
Our Approach
When we first tackled this challenge, we evaluated several approaches. The key factors were:
We chose a pragmatic approach that balances these concerns. Here's what that looks like in practice.
Technical Implementation
The implementation required careful attention to several technical details. Let's walk through the key components.
# Infrastructure health check script
#!/bin/bash
echo "=== System Health ==="
echo "Containers: $(docker ps -q | wc -l) running"
echo "CPU: $(top -bn1 | grep 'Cpu(s)' | awk '{print $2}')%"
echo "Memory: $(free -h | awk '/Mem:/{print $3"/"$2}')"
echo "Disk: $(df -h / | awk 'NR==2{print $5}')"
# Check critical services
for svc in traefik directus gitea prometheus; do
status=$(docker inspect -f '{{.State.Status}}' $svc 2>/dev/null || echo "missing")
echo "$svc: $status"
doneThis configuration reflects lessons learned from running similar setups in production. A few things to note:
1. Resource limits are essential — without them, a single misbehaving service can take down your entire stack. We learned this the hard way when a memory leak in one container consumed 14GB of RAM.
2. Volume mounts for persistence — never rely on container storage for data you care about. We mount everything to dedicated LVM volumes on SSD.
3. Health checks with real verification — a container being "up" doesn't mean it's "healthy." Always verify the actual service endpoint.
Common Pitfalls
We've seen teams make these mistakes repeatedly:
<div style="margin:2.5rem auto;max-width:600px;width:100%;text-align:center;"><svg viewBox="0 0 600 220" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;"><rect width="600" height="220" rx="12" fill="#1a1a2e"/><rect x="230" y="15" width="140" height="35" rx="8" fill="#6366f1" opacity="0.9"/><text x="300" y="38" text-anchor="middle" fill="#ffffff" font-size="12" font-family="system-ui" font-weight="bold">API Gateway</text><rect x="30" y="80" width="100" height="50" rx="8" fill="#3b82f6" opacity="0.8"/><text x="80" y="100" text-anchor="middle" fill="#ffffff" font-size="10" font-family="system-ui">Auth</text><text x="80" y="115" text-anchor="middle" fill="#ffffff" font-size="10" font-family="system-ui">Service</text><rect x="160" y="80" width="100" height="50" rx="8" fill="#a855f7" opacity="0.8"/><text x="210" y="100" text-anchor="middle" fill="#ffffff" font-size="10" font-family="system-ui">User</text><text x="210" y="115" text-anchor="middle" fill="#ffffff" font-size="10" font-family="system-ui">Service</text><rect x="290" y="80" width="100" height="50" rx="8" fill="#2dd4bf" opacity="0.8"/><text x="340" y="100" text-anchor="middle" fill="#1a1a2e" font-size="10" font-family="system-ui">Order</text><text x="340" y="115" text-anchor="middle" fill="#1a1a2e" font-size="10" font-family="system-ui">Service</text><rect x="420" y="80" width="100" height="50" rx="8" fill="#f59e0b" opacity="0.8"/><text x="470" y="100" text-anchor="middle" fill="#1a1a2e" font-size="10" font-family="system-ui">Payment</text><text x="470" y="115" text-anchor="middle" fill="#1a1a2e" font-size="10" font-family="system-ui">Service</text><line x1="265" y1="50" x2="80" y2="78" stroke="#e2e8f0" stroke-width="1" opacity="0.5"/><line x1="285" y1="50" x2="210" y2="78" stroke="#e2e8f0" stroke-width="1" opacity="0.5"/><line x1="315" y1="50" x2="340" y2="78" stroke="#e2e8f0" stroke-width="1" opacity="0.5"/><line x1="335" y1="50" x2="470" y2="78" stroke="#e2e8f0" stroke-width="1" opacity="0.5"/><ellipse cx="80" cy="175" rx="35" ry="12" fill="none" stroke="#3b82f6" stroke-width="1.5"/><line x1="45" y1="175" x2="45" y2="190" stroke="#3b82f6" stroke-width="1.5"/><line x1="115" y1="175" x2="115" y2="190" stroke="#3b82f6" stroke-width="1.5"/><ellipse cx="80" cy="190" rx="35" ry="12" fill="none" stroke="#3b82f6" stroke-width="1.5"/><line x1="80" y1="130" x2="80" y2="163" stroke="#94a3b8" stroke-width="1" stroke-dasharray="3,3"/><ellipse cx="340" cy="175" rx="35" ry="12" fill="none" stroke="#2dd4bf" stroke-width="1.5"/><line x1="305" y1="175" x2="305" y2="190" stroke="#2dd4bf" stroke-width="1.5"/><line x1="375" y1="175" x2="375" y2="190" stroke="#2dd4bf" stroke-width="1.5"/><ellipse cx="340" cy="190" rx="35" ry="12" fill="none" stroke="#2dd4bf" stroke-width="1.5"/><line x1="340" y1="130" x2="340" y2="163" stroke="#94a3b8" stroke-width="1" stroke-dasharray="3,3"/><rect x="155" y="160" width="150" height="30" rx="6" fill="#a855f7" opacity="0.3"/><text x="230" y="180" text-anchor="middle" fill="#a855f7" font-size="10" font-family="system-ui">Message Bus / Events</text><line x1="210" y1="130" x2="210" y2="158" stroke="#94a3b8" stroke-width="1" stroke-dasharray="3,3"/><line x1="470" y1="130" x2="470" y2="175" stroke="#94a3b8" stroke-width="1" stroke-dasharray="3,3"/><line x1="305" y1="175" x2="470" y2="175" stroke="#94a3b8" stroke-width="0.5" stroke-dasharray="3,3" opacity="0.3"/></svg><p style="margin-top:0.75rem;font-size:0.85rem;color:#94a3b8;font-style:italic;line-height:1.4;">Microservices architecture: independent services communicate through an API gateway and event bus.</p></div>
Real-World Application
In production, this approach has delivered measurable results:
|--------|--------|-------|-------------|
These numbers come from our actual production infrastructure running 90+ containers on a single server — proving that you don't need expensive cloud services to run reliable, scalable systems.
What We'd Do Differently
If we were starting today, we'd:
Key Takeaways
Building payment orchestration with hyperswitch: why one payment gateway isn't enough taught us several important lessons:
1. Start with the problem, not the technology — the best architecture is the one that solves your specific constraints 2. Measure everything — you can't improve what you don't measure 3. Automate the boring stuff — manual processes are error-prone and don't scale 4. Plan for failure — every system fails eventually; the question is how gracefully
If you're tackling a similar challenge, we've been there. We've shipped 36+ products across 8 industries, and we're happy to share our experience.
<div style="margin:2.5rem auto;max-width:600px;width:100%;text-align:center;"><svg viewBox="0 0 600 170" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;"><rect width="600" height="170" rx="12" fill="#1a1a2e"/><text x="60" y="30" text-anchor="middle" fill="#94a3b8" font-size="10" font-family="system-ui">Internet</text><circle cx="60" cy="60" r="25" fill="none" stroke="#3b82f6" stroke-width="1.5"/><text x="60" y="57" text-anchor="middle" fill="#3b82f6" font-size="18" font-family="system-ui">🌐</text><rect x="155" y="25" width="120" height="120" rx="10" fill="#6366f1" opacity="0.15"/><rect x="155" y="25" width="120" height="120" rx="10" fill="none" stroke="#6366f1" stroke-width="1.5"/><text x="215" y="50" text-anchor="middle" fill="#6366f1" font-size="11" font-family="system-ui" font-weight="bold">Reverse</text><text x="215" y="65" text-anchor="middle" fill="#6366f1" font-size="11" font-family="system-ui" font-weight="bold">Proxy</text><text x="215" y="85" text-anchor="middle" fill="#94a3b8" font-size="8" font-family="system-ui">TLS termination</text><text x="215" y="98" text-anchor="middle" fill="#94a3b8" font-size="8" font-family="system-ui">Load balancing</text><text x="215" y="111" text-anchor="middle" fill="#94a3b8" font-size="8" font-family="system-ui">Path routing</text><text x="215" y="124" text-anchor="middle" fill="#94a3b8" font-size="8" font-family="system-ui">Rate limiting</text><rect x="350" y="20" width="110" height="35" rx="6" fill="#2dd4bf" opacity="0.8"/><text x="405" y="42" text-anchor="middle" fill="#1a1a2e" font-size="10" font-family="system-ui">app.example.com</text><rect x="350" y="65" width="110" height="35" rx="6" fill="#a855f7" opacity="0.8"/><text x="405" y="87" text-anchor="middle" fill="#ffffff" font-size="10" font-family="system-ui">api.example.com</text><rect x="350" y="110" width="110" height="35" rx="6" fill="#f59e0b" opacity="0.8"/><text x="405" y="132" text-anchor="middle" fill="#1a1a2e" font-size="10" font-family="system-ui">cdn.example.com</text><defs><marker id="arrow11" markerWidth="8" markerHeight="6" refX="8" refY="3" orient="auto"><path d="M0,0 L8,3 L0,6" fill="#e2e8f0"/></marker></defs><line x1="87" y1="60" x2="153" y2="75" stroke="#e2e8f0" stroke-width="1.5" marker-end="url(#arrow11)"/><line x1="277" y1="55" x2="348" y2="37" stroke="#e2e8f0" stroke-width="1" marker-end="url(#arrow11)"/><line x1="277" y1="85" x2="348" y2="82" stroke="#e2e8f0" stroke-width="1" marker-end="url(#arrow11)"/><line x1="277" y1="115" x2="348" y2="127" stroke="#e2e8f0" stroke-width="1" marker-end="url(#arrow11)"/><text x="120" y="55" text-anchor="middle" fill="#2dd4bf" font-size="8" font-family="system-ui">HTTPS</text><text x="505" y="42" text-anchor="start" fill="#94a3b8" font-size="8" font-family="system-ui">:3000</text><text x="505" y="87" text-anchor="start" fill="#94a3b8" font-size="8" font-family="system-ui">:8080</text><text x="505" y="132" text-anchor="start" fill="#94a3b8" font-size="8" font-family="system-ui">:9000</text></svg><p style="margin-top:0.75rem;font-size:0.85rem;color:#94a3b8;font-style:italic;line-height:1.4;">A reverse proxy terminates TLS, routes requests by hostname, and load-balances across backend services.</p></div>
Ready to Build Something Similar?
We offer a unique deal: we'll build your demo for free. If you love it, we work together. If not, you walk away — no questions asked. That's how confident we are in our work.
*Tags: payment orchestration platform self-hosted, HyperSwitch, fintech*
Need help with fintech?
TechSaaS provides expert consulting and managed services for cloud infrastructure, DevOps, and AI/ML operations.