🧩 CH1 - Building a Modern Payment Gateway with a Rebill Scheduler - Chapter 1 – Foundations
Why you might want to build your own payment gateway — and how to do it safely with an external PCI-compliant vault.
💡 Why Build Your Own Payment Gateway?
For most startups and SaaS platforms, using Stripe or Adyen feels like the obvious choice. It’s fast, simple, and gets you online in minutes. But as your product grows — and your payment flows get more complex — you start hitting invisible walls.
- You can’t control retry logic.
- You can’t design custom reconciliation or refund workflows.
- You can’t easily migrate users from one PSP (Payment Service Provider) to another.
- And your compliance surface (PCI, PSD2, 3DS) becomes someone else’s black box.
At that point, building your own modular gateway becomes more than a technical luxury — it’s a strategic decision. It means controlling your data, your money flows, and your roadmap.
In short:
Using a PSP is easy. Owning your payment stack is power.
🧱 The Architecture of a Modular Payment Gateway in Go
Think of a gateway as a digital switchboard: it routes payment requests to the right provider, handles their lifecycle, and maintains the source of truth for your platform.
To do this properly, we split the architecture into three core layers:
1. PSP Layer (Adapters)
Each provider (Stripe, Adyen, TrustPayments, etc.) is wrapped in an adapter that implements a standard interface.
→ CreateIntent(), ContinueIntent(), Capture(), Refund(), Cancel(), VerifyWebhook(), etc.
No SDK chaos — one clean abstraction.
2. Vault Layer (External)
We never store or process card data inside our infrastructure.
Instead, we delegate all card handling to a PCI-DSS Level 1 certified vault provider.
This keeps our backend within SAQ-A compliance and removes the need for us to handle sensitive payment data directly.
A typical flow looks like this:
- The frontend sends card data directly to the external vault provider.
- The vault returns a token representing the payment method.
- The frontend sends that token to your backend.
- Your backend passes it to your vault provider to execute (after detokenization) the payment via the selected PSP.
No card numbers ever touch your systems — only tokens.
3. Core Layer (Business Logic)
The orchestrator.
It knows when to authorize, when to capture, when to retry, and how to reconcile asynchronous events.
It’s your payment brain, independent of any PSP or vault.
A simple Go-based design might look like this:
// PSP defines a 3DS-aware, intent-style interface.
type PSP interface {
// Create an intent (may return requires_action with NextAction)
CreateIntent(ctx context.Context, req PaymentRequest) (PaymentResponse, error)
// Continue an intent after client completed NextAction (e.g., returned from ACS)
ContinueIntent(ctx context.Context, intentID string, payload map[string]string) (PaymentResponse, error)
// Capture/Refund/Cancel on the underlying provider object
Capture(ctx context.Context, intentID string, amount *Money) (PaymentResponse, error)
Refund(ctx context.Context, intentID string, amount *Money) (PaymentResponse, error)
Cancel(ctx context.Context, intentID string) error
// Webhooks → normalize to provider-agnostic events
VerifyWebhook(ctx context.Context, signature string, payload []byte) (WebhookEvent, error)
}
With this interface in place, adding a new PSP becomes a plug-in operation — clean and predictable.
🔐 Security & PCI-DSS: Understand Before You Code
Before writing a single line, understand where your PCI responsibility starts and ends.
There are multiple Self-Assessment Questionnaires (SAQs) under PCI-DSS, but for developers, the two key ones are:
SAQ-A: Your system never touches card data. All payments go through an external vault or PSP-hosted form.
SAQ-D: You handle or store card data directly. Full PCI scope. Audits, scanning, and lots of headaches.
Your goal as a builder?
Stay SAQ-A for as long as possible.
That’s why external vault providers are critical: They tokenize and securely store card data on your behalf, letting you operate without the overhead of PCI audits.
| Concept | Purpose | Key Principle |
|---|---|---|
| Gateway Core | Payment orchestration logic | PSP-agnostic |
| PSP Adapters | Connect to multiple providers | Clean interface |
| Vault Provider | Tokenize and store card data externally | Stay SAQ-A |
| PCI-DSS Scope | Define responsibility zones | Tokenize early |
🚀 Coming Next
In Chapter 2, we’ll go deeper into integration patterns:
-
How to design a universal PSP interface in Go.
-
How to connect multiple PSPs without breaking your codebase.
-
How to stay PCI-compliant while scaling.
Your gateway is now an idea. Next, we’ll make it modular — and alive.