Before we dive in: I share practical insights like this weekly. Join developers and founders getting my newsletter with real solutions to engineering and business challenges.
I needed to implement dual payment protocol support whilst building BVNK's core banking system. Not the kind of problem most developers face, but when you're building financial infrastructure from scratch, you quickly discover that payment processing isn't just about API calls to Stripe.
We needed both ISO 8583 for traditional card processing and ISO 20022 for modern payment messaging across the broader financial system. Table stakes for any serious fintech platform, but the devil was in the implementation details. Most developers never touch these standards directly - they're hidden behind payment processors and banking APIs. But when you're building the infrastructure itself, you get to see how the sausage is really made.
Here's what I learned about payment standards, and why even "standard" implementations aren't actually standard.
What Actually Is an ISO?
From a builder's perspective, an Independent Sales Organisation (ISO) is essentially a middleman between merchants and payment processors. ISOs in credit card processing handle the complexity of integrating with card networks whilst taking on compliance and risk responsibilities.
The business model is straightforward: merchant services ISO programs typically offer revenue share on transaction fees, ranging from 10-100 basis points depending on volume and risk profile. But becoming an ISO for merchant services isn't trivial - you're looking at £15-20K registration fees with card networks, PCI DSS compliance, and usually £1M+ in financial backing.
At BVNK, we evaluated becoming a payment processing ISO versus partnering with existing processors. The decision hinged on control versus complexity. Building our own ISO capabilities meant owning the entire payment flow, but it also meant implementing the message standards that power everything.
That's where ISO 8583 and ISO 20022 come in - the protocols that actually move money around the global financial system.
The Message Standards That Power Everything
In 2024, you need both protocols if you're serious about payment processing. It's not an either-or decision.
ISO 8583 handles traditional card transactions. It's binary, efficient, and every card network speaks it. The format is compact - perfect for high-frequency card processing where milliseconds matter.
ISO 20022 is the new global messaging standard replacing older formats across all payment types. XML-based with rich data structures, it's being adopted by SWIFT, FedNow, and central banks worldwide. More verbose than 8583, but far more flexible for complex financial data and richer transaction information.
Here's a simplified Go struct for handling ISO 8583 messages:
type ISO8583Message struct {
MTI string // Message Type Indicator
PAN string // Primary Account Number (masked)
Amount int64 // Transaction amount in smallest currency unit
MerchantID string
TerminalID string
ResponseCode string
// ... dozens more fields depending on message type
}
func (m *ISO8583Message) Validate() error {
if len(m.MTI) != 4 {
return errors.New("invalid MTI length")
}
// Validation logic here
return nil
}
ISO 20022 is completely different - structured XML with proper schemas:
type PaymentInstruction struct {
XMLName xml.Name `xml:"PmtInf"`
PmtInfId string `xml:"PmtInfId"`
PmtMtd string `xml:"PmtMtd"`
ReqdExctnDt string `xml:"ReqdExctnDt"`
// Nested structures for debtor, creditor, etc.
}
The performance implications are significant. Binary 8583 messages are typically 100-500 bytes. ISO 20022 XML can easily hit 5-10KB for complex transactions. When you're processing thousands of messages per second, that difference matters.
But here's where it gets interesting - implementation reality is far messier than the standards suggest.
Integration Challenges I Actually Hit
The biggest challenge wasn't performance or message structure. It was the fact that "standard" implementations aren't actually standard in ISO merchant processing.
We discovered this whilst implementing ISO 20022. Different institutions had their own interpretations of field requirements, message structure, and validation rules. What should have been a straightforward schema validation became a collection of edge cases and workarounds.
Our team built a comprehensive ISO 8583 package covering the 1987, 1993, and 2003 versions. As a merchant ISO implementer, he had to reverse-engineer implementations because the official documentation costs thousands of pounds, and even then, real-world usage differed from the specs.
// Circuit breaker pattern for handling flaky message processing
type MessageProcessor struct {
iso8583Handler *ISO8583Handler
iso20022Handler *ISO20022Handler
circuitBreaker *CircuitBreaker
}
func (mp *MessageProcessor) ProcessMessage(data []byte) error {
return mp.circuitBreaker.Execute(func() error {
// Detect message format
if isBinary(data) {
return mp.iso8583Handler.Process(data)
}
return mp.iso20022Handler.Process(data)
})
}
Database consistency across protocols required careful transaction management. You can't assume both message types will have the same failure modes or retry semantics.
The testing complexity was brutal. We built mock message generators and validators, then collected examples from different implementations to ensure compatibility. Each "standard" implementation had its own quirks.
Similar to what I discovered with mocking Redis and Kafka in Go, testing distributed payment systems requires thinking beyond happy path scenarios. Message replay, partial failures, and network timeouts all need handling.
The 2024-2025 Reality Check
FedNow's adoption is driving ISO 20022 implementation across US financial institutions. Over 900 institutions are now connected, processing 1.5 million transactions in Q4 2024 alone. This isn't optional anymore - it's infrastructure.
The credit card ISO market reality is consolidation. Fiserv, FIS, and Global Payments handle the majority of ISO transactions - roughly £52 trillion annually flows through these systems. Digital wallets add another layer of complexity, now representing 53% of online transactions.
For builders, this means the barrier to entry keeps rising. The technical implementation is just table stakes - you also need the regulatory compliance, financial backing, and industry relationships.
BVNK's dual protocol approach was forward-thinking. Most companies are scrambling to add ISO 20022 support to existing 8583 infrastructure. Building both from the ground up meant cleaner architecture and fewer compromises.
What Surprised Me Most
Standards that aren't standard. I expected payment protocols to be like HTTP - well-defined, widely implemented, consistent across systems.
The reality is messier. Through conversations with banks and financial integrators in Africa, I learned about institutions that couldn't communicate directly despite "following" the same standards. The implementations differed enough that a middleman company emerged purely to translate between different interpretations of the same protocol.
This company exists solely to transform messages between banks that should theoretically be compatible. It's a problem that shouldn't exist, but it's immensely lucrative because the standards reality doesn't match the standards documentation.
Implementation Patterns That Worked
After building both protocols, here are the patterns that proved reliable:
Message Validation Strategy:
- Strict schema validation for ISO 20022
- Field-by-field validation for ISO 8583
- Configurable validation rules per institution
Error Handling:
- Circuit breakers for external system calls
- Exponential backoff with jitter
- Dead letter queues for failed messages
Performance Optimisation:
- Message parsing caching (similar to the 80x improvement I achieved with gob encoding)
- Connection pooling for high-frequency processing
- Async processing for non-critical validations
The security requirements go beyond PCI DSS. Message signing, replay protection, and constant-time comparisons for sensitive operations are essential.
What I'd Build Differently Now
Honestly, I'd probably follow the same approach. Building custom Go libraries for both standards gave us complete control over the implementation. The alternative - integrating with existing libraries - would have meant accepting someone else's interpretation of the standards.
The key insight was treating standards as guidelines rather than gospel. Every integration required testing against the specific institution's implementation, not just the documented standard.
For teams considering similar implementations: budget extra time for the "standards aren't standard" reality. Your test suite needs to validate against real-world implementations, not just the specification documents.
Understanding how to become an ISO for merchant services isn't just about the business requirements - it's about navigating the technical complexity of multiple protocol implementations that don't quite match their documentation.
The Real Lesson
Payment processing standards exist in theory. In practice, every implementation is slightly different, and those differences compound across the entire financial system.
If you're building payment infrastructure, plan for this reality. Standards documentation gets you 80% there - the final 20% comes from testing against actual systems and handling the edge cases that nobody documents.
The good news? Once you understand this, you can build more robust systems than teams who assume standards are actually standard. And occasionally, you might even spot opportunities to build the middleware that shouldn't need to exist.