Payment Gateways: A System Design Perspective
Online payments look simple.
Behind that button sits a distributed, cryptographically hardened, regulation-bound financial system. Companies like Stripe abstract this complexity away, but the underlying architecture is fascinating — and demanding.
TL;DR — A payment gateway orchestrates the flow between merchants, acquiring banks, card networks (Visa/Mastercard), and issuing banks. It must handle idempotency (no double charges), fraud scoring, PCI-compliant tokenization (card numbers never touch merchant servers), and double-entry ledger accounting — all in ~200 ms. Messages between banks travel as ISO 8583 binary frames driven by bitmaps, not JSON. The standard was recently updated to ISO 8583:2023, replacing the 1987/1993 editions to fix ambiguity, support modern payment types (e-commerce, mobile wallets, contactless), and align with ISO 20022. Settlement happens asynchronously in batches, and the whole system must survive multi-region failures without ever losing money or auditability.
This post covers:
- System design architecture
- Component and sequence diagrams (Mermaid)
- Idempotency and failure handling
- Ledger and settlement design
- PCI compliance and tokenization
- Scaling and multi-region challenges
- Deep dive into ISO 8583 message structure and bitmaps
- ISO 8583:2023 — what changed and why
High-Level System Architecture
At a high level, a payment gateway connects customers, merchants, banks, and card networks.
flowchart LR
Client[Customer App / Browser]
Merchant[Merchant Backend]
APIGW[API Gateway]
Auth[Auth Service]
Orchestrator[Payment Orchestrator]
Idem[Idempotency Layer]
Fraud[Fraud Engine]
Token[Tokenization Vault]
Ledger[Ledger Service]
Settlement[Settlement Service]
Connectors[Bank & Network Connectors]
Bank[Acquiring Bank]
Network[Card Network]
Issuer[Issuing Bank]
Client --> Merchant
Merchant --> APIGW
APIGW --> Auth
APIGW --> Orchestrator
Orchestrator --> Idem
Orchestrator --> Fraud
Orchestrator --> Token
Orchestrator --> Ledger
Orchestrator --> Connectors
Connectors --> Bank
Bank --> Network
Network --> Issuer
Settlement --> Bank
How It Fits Together
The orchestrator is the brain. Everything flows through it. It coordinates the interaction between internal services — fraud checks, tokenization lookups, ledger writes — before issuing outbound calls to acquiring banks and card networks. Think of it as a saga coordinator: it ensures that each step in the payment lifecycle completes in the correct order, and triggers compensating actions (e.g., reversals) when something fails partway through.
Key roles of each component:
| Component | Responsibility |
|---|---|
| API Gateway | Rate limiting, TLS termination, routing |
| Auth Service | Merchant authentication, API key validation |
| Payment Orchestrator | Coordinates the end-to-end payment flow |
| Idempotency Layer | Deduplicates retried requests |
| Fraud Engine | Scores transactions for risk (rules + ML models) |
| Tokenization Vault | Replaces PANs with opaque tokens (PCI DSS scope reduction) |
| Ledger Service | Immutable, double-entry accounting records |
| Settlement Service | Batches captured transactions for bank settlement |
| Bank & Network Connectors | Protocol adapters (ISO 8583, proprietary APIs) for acquirers and card networks like Visa, Mastercard, etc. |
Payment Authorization Sequence
A successful authorization involves multiple institutions.
sequenceDiagram
participant C as Customer
participant M as Merchant
participant G as Gateway
participant F as Fraud Engine
participant B as Acquirer
participant N as Network
participant I as Issuer
C->>M: Enter card + Pay
M->>G: POST /payments (Idempotency-Key)
G->>G: Validate idempotency
G->>F: Fraud scoring
F-->>G: Risk OK
G->>B: Authorization request
B->>N: Forward request
N->>I: Request approval
I-->>N: Approved
N-->>B: Approved
B-->>G: Approved
G->>G: Record ledger (Authorized)
G-->>M: 200 OK
M-->>C: Success
Notice ordering discipline:
- Idempotency check
- Fraud evaluation
- External call
- Ledger write
You never persist success before the bank confirms it.
Idempotency: Preventing Double Charges
Distributed systems retry. Users refresh. Networks fail.
Without idempotency, double charges are inevitable.
flowchart TD
A[Incoming Payment Request]
B{Idempotency<br />Key exists?}
C[Return Stored Result]
D[Process Payment]
E[Store Result]
F[Return Response]
A --> B
B -- Yes --> C
B -- No --> D
D --> E
E --> F
The gateway stores the response against a unique key (typically the Idempotency-Key header provided by the merchant). Replays return the same stored result without re-executing the payment.
Implementation Considerations
- Key format: Usually a UUID or merchant-generated unique reference. Stripe, for example, accepts an
Idempotency-Keyheader on everyPOSTrequest. - Storage: A fast key-value store (e.g., Redis) works well, with a TTL of 24–72 hours to prevent unbounded growth.
- Atomicity: The check-and-store operation must be atomic — typically achieved with
SETNX(set-if-not-exists) semantics or a database unique constraint. - Scope: The idempotency key should be scoped to the merchant + operation. Two different merchants using the same key should not collide.
- Response caching: Store the full HTTP response (status code, headers, body) so replayed requests are indistinguishable from the original.
This is not optional in financial systems. Without it, network retries and user double-clicks become double charges — the fastest way to lose merchant trust.
Ledger Design: Double-Entry Accounting
Money requires strong consistency and auditability.
flowchart LR
Auth[Authorization]
Pending[(Pending Liability)]
Capture[Capture]
Merchant[(Merchant Balance)]
Settlement[Settlement Batch]
BankTransfer[Bank Transfer]
Auth --> Pending
Capture --> Merchant
Settlement --> BankTransfer
Principles
- Append-only ledger: Entries are never updated or deleted. Every state change is a new record.
- Immutable entries: Once written, a ledger entry cannot be modified. If a correction is needed, a new compensating entry is written.
- Double-entry bookkeeping: Every transaction creates at least two entries — a debit and a credit — that must balance to zero. For example, when a payment is captured, the merchant’s balance is credited and the settlement liability account is debited.
- Compensating transactions for refunds: A refund doesn’t delete the original charge; it creates a reverse entry.
- No silent mutation of balances: Balances are always derived by replaying or aggregating ledger entries, never stored as a mutable counter.
This is how banks have worked for centuries. Event sourcing — where the application state is derived from an append-only log of events — aligns beautifully with this model. The ledger is the event log.
Authorization vs Settlement
Authorization is synchronous. Settlement is asynchronous.
sequenceDiagram
participant M as Merchant
participant G as Gateway
participant B as Bank
M->>G: Authorize
G->>B: Auth request
B-->>G: Approved
G-->>M: Auth success
Note over G: Later (batch process)
G->>B: Settlement file
B-->>G: Settlement confirmation
This separation:
- Reduces banking overhead (fewer real-time round trips)
- Improves throughput (batch file transfer is more efficient than per-transaction settlement)
- Enables reconciliation cycles (merchants and acquirers can compare expected vs. actual settlement amounts)
Settlement typically occurs via settlement files exchanged in formats agreed between the gateway and the acquiring bank (often ISO 8583-based batches, or increasingly, ISO 20022 pacs messages).
Tokenization and PCI Scope Reduction
PCI DSS compliance governs cardholder data handling. The current version, PCI DSS v4.0.1 (published June 2024), introduced significant changes including stronger authentication requirements, expanded encryption mandates, and a focus on continuous security processes rather than point-in-time assessments. Compliance is enforced by the card networks (Visa, Mastercard, etc.) and validated through Qualified Security Assessors (QSAs) or Self-Assessment Questionnaires (SAQs).
Tokenization reduces exposure.
flowchart TD
Card[Card Number]
Vault[Secure Vault / HSM]
Token[Generated Token]
MerchantDB[(Merchant DB)]
Card --> Vault
Vault --> Token
Token --> MerchantDB
Raw PAN never touches merchant infrastructure. The merchant only ever stores and transmits the token; the actual card number lives in the PCI-compliant vault, typically backed by a Hardware Security Module (HSM).
Security measures typically include:
- TLS 1.2+ in transit (TLS 1.3 preferred) — IETF RFC 8446
- AES-256 encryption at rest
- Hardware Security Modules (HSMs) for cryptographic key management and PIN block operations
- Strict network segmentation — the Cardholder Data Environment (CDE) must be isolated from the rest of the network
- Logging & monitoring — all access to cardholder data must be logged and regularly reviewed
Multi-Region Deployment
Global providers must tolerate regional failures.
flowchart LR
LB[Global Load Balancer]
subgraph EU Region
EU_API[API Cluster EU]
EU_DB[(Ledger DB EU)]
end
subgraph US Region
US_API[API Cluster US]
US_DB[(Ledger DB US)]
end
LB --> EU_API
LB --> US_API
EU_API --> EU_DB
US_API --> US_DB
EU_DB <-- Replication --> US_DB
Challenges:
- Cross-region consistency: Distributed databases must choose between strong consistency and availability (CAP theorem). Payment ledgers typically favor consistency.
- Data residency laws: Regulations like GDPR (EU), DPDPA (India), and LGPD (Brazil) may require cardholder data to be stored within specific geographic boundaries.
- Idempotency across regions: If a request is retried against a different region during failover, the idempotency store must be globally accessible or the failover must be sticky.
- Failover correctness: Active-passive vs. active-active topologies each bring trade-offs. Active-active risks split-brain; active-passive risks downtime during switchover.
Money cannot tolerate split-brain states.
Payment State Machine
Payments follow strict state transitions.
stateDiagram-v2
[*] --> Created
Created --> Authorized
Authorized --> Captured
Authorized --> Voided
Captured --> Settled
Captured --> Refunded
Settled --> Refunded
State machines prevent invalid flows like capturing twice or refunding before capture.
Deep Dive: ISO 8583
Now we descend into the ancient machinery that powers card networks.
ISO 8583 is the messaging standard used by most card networks to transmit transaction data. Developed by the ISO under Technical Committee 68 (Financial Services), it has been the backbone of card-based payments globally.
It is not JSON.
It is not REST.
It is field-based, positional, bitmap-driven binary messaging!
It was born in the 1980s and still runs global commerce.
Structure of an ISO 8583 Message
An ISO 8583 message typically contains:
- Message Type Indicator (MTI)
- Primary Bitmap (64 bits)
- Secondary Bitmap (optional)
- Data Elements (fields)
Conceptually:
[ MTI ][ Bitmap ][ Data Elements... ]
Message Type Indicator (MTI)
MTI is 4 digits. Each digit encodes a specific dimension of the message:
| Position | Meaning | Values |
|---|---|---|
| 1st digit | Version | 0 = ISO 8583:1987, 1 = ISO 8583:1993, 2 = ISO 8583:2003/2023 |
| 2nd digit | Message Class | 1 = Authorization, 2 = Financial, 3 = File Action, 4 = Reversal/Chargeback, 8 = Network Management |
| 3rd digit | Message Function | 0 = Request, 1 = Response, 2 = Advice, 3 = Advice Response |
| 4th digit | Message Origin | 0 = Acquirer, 1 = Acquirer Repeat, 2 = Issuer, 3 = Issuer Repeat |
Example:
0100 → Authorization Request
0110 → Authorization Response
0200 → Financial Transaction Request
0210 → Financial Transaction Response
Each digit has meaning:
- Version
- Message class
- Message function
- Message origin
It’s compact and brutally efficient.
Bitmaps: The Heart of ISO 8583
The primary bitmap is a 64-bit (8-byte) field, typically transmitted as 16 hex characters.
Each bit corresponds to a data element (DE). If a bit is set (1), the corresponding data element is present in the message.
Worked Example
Suppose the primary bitmap in hex is:
F2 3C 44 81 08 E0 80 00
Converting each hex nibble to binary:
F 2 3 C 4 4 8 1 0 8 E 0 8 0 0 0
1111 0010 0011 1100 0100 0100 1000 0001 0000 1000 1110 0000 1000 0000 0000 0000
Reading left to right, bit positions 1–64:
- Bit 1 = 1 → Secondary bitmap is present (fields 65–128 follow)
- Bit 2 = 1 → DE 2 (Primary Account Number) is present
- Bit 3 = 1 → DE 3 (Processing Code) is present
- Bit 4 = 1 → DE 4 (Transaction Amount) is present
- Bit 5 = 0 → DE 5 not present
- … and so on for all 64 bit positions
This bitmap tells the parser exactly which fields to expect and in what order — no field labels, no delimiters, no ambiguity.
Conceptual visualization of the first 8 bits:
flowchart LR
B1[1] --> B2[1] --> B3[1] --> B4[0] --> B5[0] --> B6[1] --> B7[0] --> B8[0]
If bit 1 is 1, a secondary bitmap follows (fields 65–128).
Think of it as a presence map.
Instead of sending field labels, the message uses bit positions to indicate which fields exist. That’s bandwidth-efficient and deterministic.
Example Fields
Common data elements:
| DE | Name | Format | Description |
|---|---|---|---|
| 2 | Primary Account Number (PAN) | LLVAR, n..19 | The card number |
| 3 | Processing Code | Fixed, n 6 | Identifies the transaction type (purchase, refund, balance inquiry, etc.) |
| 4 | Transaction Amount | Fixed, n 12 | Amount in minor units (e.g., cents) |
| 7 | Transmission Date & Time | Fixed, n 10 | MMDDhhmmss — when the message was sent |
| 11 | System Trace Audit Number (STAN) | Fixed, n 6 | Unique trace number for the transaction |
| 37 | Retrieval Reference Number | Fixed, an 12 | Used to link request and response across networks |
| 38 | Authorization ID Response | Fixed, an 6 | Code assigned by the authorizing institution |
| 39 | Response Code | Fixed, an 2 | 00 = Approved, 05 = Do Not Honour, 51 = Insufficient Funds, etc. |
| 41 | Card Acceptor Terminal ID | Fixed, ans 8 | Identifies the terminal at the point of sale |
| 49 | Transaction Currency Code | Fixed, n 3 | ISO 4217 currency code (e.g., 840 for USD, 978 for EUR) |
For the full list of data elements, see the ISO 8583 Wikipedia reference.
Example simplified flow:
Authorization request (0100):
- PAN
- Amount
- STAN
- Timestamp
Authorization response (0110):
- Same STAN
- Response Code (00 = Approved)
Why Bitmaps Matter
Bitmaps allow:
- Compact binary messaging
- Deterministic parsing
- Flexible field combinations
- Backward compatibility
Parsing algorithm:
- Read MTI
- Read primary bitmap
- If bit 1 = 1 → read secondary bitmap
- Iterate through bits
- For each set bit → parse corresponding field in order
No field names. No delimiters. Just positional discipline.
Elegant. Severe. Efficient.
Engineering Challenges with ISO 8583
- Variable-length fields (LLVAR, LLLVAR): Not all fields are fixed-width.
LLVARfields are prefixed with a 2-digit length indicator (max 99 bytes), whileLLLVARfields use a 3-digit prefix (max 999 bytes). For example, Field 2 (PAN) isLLVARbecause card numbers vary from 13 to 19 digits — the first 2 bytes tell you how many digits follow. The parser must read the length prefix before reading the field value, making the parsing inherently sequential within the data elements section. - Network-specific custom fields: Fields 48–62 and 112–128 are commonly reserved for private (network-specific) use. Visa, Mastercard, and regional networks each define their own sub-field layouts within these ranges, so a single ISO 8583 parser rarely works across all networks without customization.
- Different implementations per network: Even core fields can differ in format across implementations. What passes validation at one acquirer may be rejected by another.
- Strict formatting rules: Numeric fields (
n), alphanumeric (an), and alphanumeric-special (ans) each have precise character set rules. Padding (leading zeros for numeric, trailing spaces for alpha) must be exact. - Message signing / MAC validation: Integrity is ensured via a Message Authentication Code (MAC), typically using ANSI X9.19 or ISO 9797-1. The MAC is computed over the message content and appended as a data element (commonly DE 64 or DE 128).
- Timeout and reversal handling: If the acquirer doesn’t respond within the timeout window (typically 30–60 seconds), the gateway must send a reversal (MTI
04xx) to avoid orphaned authorizations that lock up the cardholder’s available balance.
Gateways often build adapter layers:
Internal JSON → ISO 8583 mapper → Network-specific variant
It is a protocol translation engine under strict latency budgets (often < 100ms for the mapping itself).
ISO 8583:2023 — The New Standard
In 2023, ISO published a new edition of the standard: ISO 8583:2023 — “Financial-transaction card-originated messages — Interchange message specifications”. This edition withdrew and replaced all prior versions, including the widely-implemented ISO 8583:1987 and ISO 8583:1993.
You can view the official catalogue entry at iso.org/standard/79451.html.
Why Were the Older Standards Withdrawn?
The previous editions had served the industry for decades, but several long-standing issues motivated the revision:
-
Ambiguity and divergent interpretation: The older editions left many data element definitions open to interpretation. Different card networks, acquirers, and regional processors evolved their own “flavors” of ISO 8583, creating interoperability friction. A message valid on one network could be rejected by another — not because of a logical error, but because of formatting disagreement.
-
Security gaps: The original standards were designed in an era before modern threat models. They lacked adequate provisions for stronger cryptographic controls, tokenization, and the secure handling of sensitive authentication data that contemporary regulations demand.
-
Inability to express modern payment types: E-commerce, mobile wallets, contactless payments, QR codes, and 3-D Secure flows introduced data requirements that didn’t fit neatly into the original field structures. Networks resorted to stuffing sub-fields into private-use data elements (DE 48–62, DE 112–128), leading to fragmentation.
-
Regulatory evolution: Regulations like PSD2 (EU), RBI tokenization mandates (India), and PCI DSS v4.0 imposed new data exchange requirements that older editions could not accommodate cleanly.
-
ISO’s systematic review process: ISO standards are subject to periodic review. When a standard no longer reflects current best practice or industry need, it is revised or withdrawn. The older ISO 8583 editions were overdue for consolidation.
What Changed in ISO 8583:2023?
The 2023 edition is a significant restructuring, not merely an errata update:
| Aspect | Older Editions | ISO 8583:2023 |
|---|---|---|
| Structure | Split across multiple parts with overlapping scope | Consolidated into a single, coherent document |
| Data element definitions | Often ambiguous; heavy reliance on implementation guides | Clearer, more prescriptive definitions to reduce divergence |
| Modern payment support | Retrofitted via private-use fields | Native support for e-commerce, mobile, and tokenized transactions |
| Security provisions | Minimal; delegated to external standards | Enhanced alignment with modern cryptographic and authentication requirements |
| Extensibility | Ad-hoc network-specific extensions | More structured approach to extensions and private-use data |
| Alignment with ISO 20022 | No formal alignment | Improved conceptual alignment with ISO 20022 messaging, facilitating coexistence during the industry’s gradual migration |
Key technical changes include:
- Revised data element numbering and definitions: Some fields were redefined, merged, or deprecated to eliminate legacy ambiguity.
- Improved sub-field structures: Better-defined nested data within composite fields, reducing the reliance on ad-hoc parsing conventions.
- Enhanced MTI semantics: Clearer rules for version, message class, function, and origin encoding.
- Forward-compatibility provisions: The specification anticipates future payment types and authentication mechanisms.
Migration Reality
Despite the new standard, the vast majority of live payment networks still run on ISO 8583:1987- or 1993-based profiles. Migration to the 2023 edition will be gradual, driven by individual network upgrade cycles, regulatory mandates, and processor readiness. Many networks may skip directly to ISO 20022 for new implementations, using ISO 8583:2023 primarily as a reference for maintaining legacy interoperability.
More about ISO 8583:2023
- ISO catalogue: ISO 8583:2023
- ISO TC68 committee: Technical Committee 68
- Wikipedia overview: ISO 8583
- ISO 20022 (the newer messaging paradigm): iso20022.org
Why Payment Systems Are So Complex
They combine:
- Distributed systems theory
- Cryptography
- Accounting principles
- Regulatory compliance
- Protocol engineering
- Real-time fraud modeling
They must:
- Never double-charge
- Never lose money
- Never lose auditability
- Never expose card data
- Never go down
And do it in ~200 milliseconds!
That’s not “just an API.” That’s modern civilization’s circulatory system.
If you’d like, the next step could be:
- Designing a simplified payment gateway using Spring Boot and event-driven architecture
- Modeling a mini ISO 8583 parser in Java
- Or exploring ISO 20022 and real-time payment rails (UPI, FedNow, SEPA Instant)
Because once you understand payment systems, you start seeing how digital trust is actually engineered — not assumed! Give it a try…
Comments