DEV Community

Cover image for Secure ISO 20022 API Microgateway for Cross-Border Payments
Elijah Chimera
Elijah Chimera

Posted on

Secure ISO 20022 API Microgateway for Cross-Border Payments

Designing a payment translation service from requirements to deployment.


1. What I'm Building & Why

The Scenario

You're a Solutions Architect at a commercial bank. The bank has 200,000+ customers sending and receiving money internationally. The legacy system crashes weekly, payments take days, and the regulator says: "Adopt ISO 20022 or lose your license."

The CEO asks: "Can you build a system that takes requests from our app, produces correct international payment messages, and won't get us fined?"

What is ISO 20022?

The global standard format banks use to communicate. Think of it as a structured shipping label for money.

Old Way (MT messages) New Way (ISO 20022)
Free-text, vague Structured, machine-readable
~100 data fields 7,000+ data fields
Hard to trace Every step tracked

What is pacs.008?

The specific message type for: "Customer at Bank A wants to send money to someone at Bank B."

What is a Microgateway?

A small service that does one job: takes JSON from your app and outputs valid ISO 20022 XML for the payment network.

App (JSON) → Microgateway → ISO 20022 XML → Bank Network
Enter fullscreen mode Exit fullscreen mode

2. The Solutions Architect Role

The SA sits between business and engineering understanding both, making decisions that affect the whole system.

Activity Time Example
Stakeholder meetings 30% Explaining trade-offs, gathering requirements
Architecture design 25% Diagrams, technology choices
Technical review 20% Reviewing code and infra plans
Documentation 15% Decision records, runbooks
Hands-on building 10% Prototypes, proof-of-concepts

What this project demonstrates:

Skill How It's Shown
Requirements gathering Stakeholder interviews, requirement tables
Architecture design VPC, EKS, multi-AZ, auto-scaling
Security thinking Input validation, no sensitive logs, zero-trust
Infrastructure as Code Terraform
Testing strategy 27 tests covering all paths
Business communication Executive summary, ROI calculations

3. Phase 0: Requirements

Stakeholder Interviews (Simulated)

CFO: "We lose $500K/year on payment failures. Cut error rate from 8% to under 1%."

CISO: "Zero-trust. No sensitive data in logs. Encryption everywhere."

Compliance Officer: "7-year audit trail. Every message traceable. Fines for non-compliance are 10% of annual turnover."

Head of Operations: "Peak: 50 transactions/second at end-of-month. 99.95% uptime required."

Functional Requirements

ID Requirement Priority
FR-01 Accept JSON payment requests via API Must-have
FR-02 Validate all input fields Must-have
FR-03 Generate pacs.008 XML Must-have
FR-04 Return unique tracking IDs Must-have
FR-05 Support multiple currencies (EUR, USD, GBP, KES, JPY) Must-have

Non-Functional Requirements

ID Requirement Target
NFR-01 Response time < 200ms
NFR-02 Throughput 50 TPS peak
NFR-03 Availability 99.95%
NFR-04 Data retention 7 years
NFR-05 Recovery time < 30 minutes

Architecture Decision: Cloud Provider

Option Score Rationale
AWS 9/10 Team skills, broad services, enterprise support
Azure 7/10 Good compliance tools, less regional presence
GCP 6/10 Best K8s, smallest enterprise footprint

Decision: AWS.


4. Phase 1: Infrastructure

Architecture Overview

Key Design Decisions

Decision Why
Private subnets for app No direct internet exposure
Multi-AZ (3 availability zones) Survives data center failure
ON_DEMAND instances Financial workloads need reliability
EKS managed nodes AWS handles patching
NAT Gateway Outbound only — internet can't reach in

What the Terraform Creates

The terraform/main.tf provisions:

  • VPC (rare-bank-vpc) with public/private subnets across 3 AZs
  • EKS cluster (payment-microgateway) with auto-scaling (1–10 nodes)
  • S3 backend for state with DynamoDB locking
  • Environment-aware config (dev/staging/production)


5. Phase 2: Payment Logic

Data Flow

Mobile App (JSON) → Validate → Generate IDs → Build XML → Return Response
                                                    │
                                                    ▼
                                              Audit Log (hash)
Enter fullscreen mode Exit fullscreen mode

Input (JSON from the mobile app)

{
  "sender_name": "John Doe",
  "sender_account": "RA1234567890123456",
  "sender_bic": "RCBKRAXX",
  "receiver_name": "Elijah Chimera",
  "receiver_account": "RA29CBRR60161331926819",
  "receiver_bic": "CBRARERX",
  "amount": 1250.50,
  "currency": "EUR",
  "purpose_code": "SALA",
  "remittance_info": "Invoice #12345 - Consulting Services"
}
Enter fullscreen mode Exit fullscreen mode

Field Mapping

JSON Field XML Element Validation
sender_name <Dbtr><Nm> 1–140 chars
sender_account <DbtrAcct><Id><Othr><Id> Min 5 chars, spaces stripped
sender_bic <DbtrAgt><FinInstnId><BICFI> 8 or 11 chars, uppercase (Fleet Code)
receiver_name <Cdtr><Nm> 1–140 chars
receiver_account <CdtrAcct><Id><Othr><Id> Min 5 chars, spaces stripped
receiver_bic <CdtrAgt><FinInstnId><BICFI> 8 or 11 chars, uppercase (Fleet Code)
amount <IntrBkSttlmAmt> > 0, ≤ 999,999,999.99
currency Ccy attribute 3 chars, ISO 4217
purpose_code <Purp><Cd> 4 uppercase chars (optional)
remittance_info <RmtInf><Ustrd> Max 140 chars (optional)

Application Layers

┌─────────────────────────────────┐
│  MIDDLEWARE (CORS, timing)      │
├─────────────────────────────────┤
│  VALIDATION (Pydantic)          │
├─────────────────────────────────┤
│  PROCESSING (IDs, XML, hash)    │
├─────────────────────────────────┤
│  RESPONSE (JSON + error format) │
└─────────────────────────────────┘
Enter fullscreen mode Exit fullscreen mode

Key Code Concepts

Fleet Code validation regex: ^[A-Z]{6}[A-Z0-9]{2}([A-Z0-9]{3})?$

  • 6 uppercase letters (bank + country) + 2 alphanumeric (location) + optional 3 (branch)
  • Valid: RCBKRAXX (8 chars), CBRARERXXXX (11 chars)
  • Invalid: cbrarerx (lowercase), RCBL (too short)

XML namespace: urn:iso:std:iso:20022:tech:xsd:pacs.008.001.08

  • Without this, payment networks reject the message entirely.

Audit hash: SHA-256 of partial data — creates a traceable fingerprint without exposing sensitive details.

Output (ISO 20022 XML)

<?xml version="1.0" ?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.008.001.08" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <FIToFICstmrCdtTrf>
        <GrpHdr>
            <MsgId>MSG7A3F2B...</MsgId>
            <CreDtTm>2025-01-15T10:30:00.000Z</CreDtTm>
            <NbOfTxs>1</NbOfTxs>
            <SttlmInf>
                <SttlmMtd>CLRG</SttlmMtd>
            </SttlmInf>
        </GrpHdr>
        <CdtTrfTxInf>
            <IntrBkSttlmAmt Ccy="EUR">1250.50</IntrBkSttlmAmt>
            <ChrgBr>SLEV</ChrgBr>
            <Dbtr><Nm>John Doe</Nm></Dbtr>
            <CdtrAgt><FinInstnId><BICFI>CBRARERX</BICFI></FinInstnId></CdtrAgt>
            <Cdtr><Nm>Elijah Chimera</Nm></Cdtr>
        </CdtTrfTxInf>
    </FIToFICstmrCdtTrf>
</Document>
Enter fullscreen mode Exit fullscreen mode

Dockerfile

Multi-stage build:

  1. Builder stage — installs dependencies with compilers
  2. Runtime stage — minimal image, non-root user (appuser), health check

Runs with 4 Uvicorn workers in production.


6. Phase 3: Security

Defense in Depth

Layer Protection
Perimeter WAF, rate limiting, TLS 1.3
Network VPC isolation, private subnets, security groups
Application Pydantic validation (Fleet Code format, amount range, name length)
Data Encryption at rest/transit, no sensitive data in logs
Monitoring Real-time alerts, immutable audit trails

What Gets Logged vs. What Doesn't

Log This Never Log This
Timestamp, request ID Full account numbers
HTTP status, duration Customer names
Currency, error type Exact amounts
Message ID (for tracing) Passwords, API keys

Example safe log from the app:

Payment request received | IP: 192.168.x.x | Currency: EUR | Amount: [REDACTED] | Sender: Joh*** | Receiver BIC: CBRA***
Enter fullscreen mode Exit fullscreen mode

Key Alerts

  • Error rate > 5% (CloudWatch alarm configured)
  • p95 latency > 500ms
  • CPU > 80% for 5 minutes
  • Any 5xx in production

7. Phase 4: Testing

27 Tests Covering:

Category Count What It Proves
Health & info 2 Service is alive
Valid payments 3 Core flow works (full fields, minimal, 11-char Fleet Code)
Amount validation 3 Rejects zero, negative, too-large
Fleet Code validation 2 Rejects malformed, lowercase
Currency handling 3 Validates length, auto-uppercases, formats XML
Name validation 3 Handles empty, max-length, too-long
Purpose/account 2 Format enforcement
XML structure 4 Namespace, well-formed, formatting, rounding
ID generation 2 Unique IDs (MSG prefix, 23 chars), proper hash (16 hex chars)
Edge cases 4 Special chars, long names, IBAN spaces, multiple currencies
CORS 1 Cross-origin headers present

Deployment Strategy: Blue-Green

  1. Deploy new version (GREEN) alongside current (BLUE)
  2. Route 10% traffic to GREEN, monitor
  3. If metrics are good, shift to 100%
  4. Keep BLUE on standby for instant rollback


8. Phase 5: Business Communication

Executive Summary

Metric Before After Annual Impact
Error rate 8% < 1% $435K savings
Settlement time 2–5 days < 4 hours Better cash flow
Manual work 40 hrs/week 4 hrs/week $187K savings
Infra cost $800K (mainframe) $200K (cloud) $600K savings

Investment: $180K initial + $70K/year
ROI: 340% in Year 1

Technology Choices

Choice Why
AWS EKS Team has Kubernetes skills, mature ecosystem
FastAPI Fast, auto-generates API docs, modern Python
Terraform Reproducible infra, version-controlled, team collaboration via S3 state
Python Rapid development, good for data transformation


9. Running It Yourself

# Clone and setup
git clone https://github.com/YOUR_USERNAME/iso20022-microgateway.git
cd iso20022-microgateway
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt

# Run tests (all 27 should pass)
pytest -v

# Start server
uvicorn main:app --reload
# Docs at http://localhost:8000/docs
Enter fullscreen mode Exit fullscreen mode

Test a payment:

curl -X POST http://localhost:8000/api/v1/payments/transfer \
  -H "Content-Type: application/json" \
  -d '{
    "sender_name": "John Doe",
    "sender_account": "RA1234567890123456",
    "sender_bic": "RCBKRAXX",
    "receiver_name": "Elijah Chimera",
    "receiver_account": "RA29CBRR60161331926819",
    "receiver_bic": "CBRARERX",
    "amount": 1250.50,
    "currency": "EUR",
    "purpose_code": "SALA",
    "remittance_info": "Invoice #12345 - Consulting Services"
  }'
Enter fullscreen mode Exit fullscreen mode

Docker:

docker build -t iso-gateway .
docker run -p 8000:8000 iso-gateway
Enter fullscreen mode Exit fullscreen mode

To see the live demo run the following locally.

cd /home/chimera/Downloads/iso20022-microgateway
source venv/bin/activate
python live_demo.py
Enter fullscreen mode Exit fullscreen mode

10. Q and A

Q: Why ISO 20022 over MT messages?
Regulatory mandate, richer data (7000+ fields vs 100), and it's the global standard for instant payments and open banking.

Q: Why Kubernetes?
Team expertise, consistent tooling for multi-region expansion, and future microservices. For smaller scale, ECS or Lambda would also work.

Q: How do you handle mid-processing failures?
Idempotency keys + state machine. Each payment transitions through states (RECEIVED → VALIDATED → SUBMITTED → SETTLED). Failures resume from last known state.

Q: How do you prioritize when everything is urgent?
Impact × Urgency. "If we do nothing for 24 hours, what breaks?" Document the rationale, get stakeholder sign-off on trade-offs.


Tech Stack

Python 3.12+ · FastAPI · Pydantic · Docker · Terraform · GitHub Actions · Pytest


Disclaimer

Portfolio/learning project only. Does not process real money or connect to any live payment network.


License

MIT

Top comments (0)