We spent the better part of two years building and scaling Bankwards, a platform handling cross-border payments across European and Southeast Asian corridors. At peak, the system processes over 80 million euros in quarterly transaction volume. Along the way, we learned things about open banking, PSD2 compliance, and multi-currency reconciliation that no documentation or conference talk prepared us for.
This is a practical account of what actually works in production, what caught us off guard, and the decisions we would revisit if we were starting from scratch today.
PSD2 Compliance: The Devil in the Consent Flows
PSD2 opened the door to open banking in Europe, but the spec and the reality are two different animals. The regulation mandates that banks expose Account Information Service (AIS) and Payment Initiation Service (PIS) APIs. What it does not mandate is consistency.
Every bank implements the Berlin Group or Open Banking UK standards slightly differently. Token refresh behavior, consent duration, error codes, redirect flows — we ended up maintaining a bank-specific adapter layer with custom handling for over 30 institutions. Some banks expire consent after 90 days exactly. Others interpret Strong Customer Authentication (SCA) requirements in ways that break automated recurring access.
What we'd do differently: we would have invested in a comprehensive bank compatibility matrix from day one instead of discovering edge cases in production. We also would have built consent lifecycle management as a first-class domain object, not an afterthought bolted onto the auth layer.
Multi-Currency FX: Margin Erosion Is the Silent Killer
Handling FX across EUR, GBP, SGD, and THB corridors taught us that the spread you quote and the spread you get are rarely the same unless you control the entire chain. We started with a single FX provider and quickly found that rate staleness during high-volatility windows was eating into margins.
Our solution was a multi-provider FX aggregation engine that queries three liquidity sources in parallel, selects the best rate within a configurable tolerance window, and locks it for a defined TTL. The lock mechanism was critical — without it, the rate could shift between quote and execution, creating reconciliation nightmares downstream.
We also learned the hard way that settlement timing across corridors is wildly inconsistent. A EUR-to-SGD transfer might settle T+0 on the European leg but T+2 on the Singapore side, creating a float management problem that directly impacts cash position reporting. We ended up building a settlement state machine that tracks each leg independently and only marks the transaction as complete when both sides confirm.
Open Banking API Integration: Uptime Is Not Guaranteed
The open banking ecosystem assumes reliable API endpoints. In practice, bank APIs go down far more often than anyone admits. We tracked availability across our connected banks and found that several major institutions had sub-99% uptime on their PIS endpoints during business hours.
We built a circuit breaker pattern with intelligent fallback routing. If a bank's API fails three consecutive health checks, we automatically switch to an alternative payment rail for that corridor — typically a direct SEPA connection or a partner PSP. The switchover is transparent to the end user. This alone prevented hundreds of failed payment attempts per month.
Webhook reliability was another pain point. Bank-initiated webhooks for payment status updates were unreliable, delayed, or sometimes simply never sent. We ended up implementing a parallel polling mechanism that reconciles against webhook data, treating webhooks as hints rather than authoritative signals.
Reconciliation at Scale: The Unglamorous Core
Reconciliation is the part of payments infrastructure that nobody wants to build and everybody underestimates. At our volume — tens of thousands of transactions weekly across multiple currencies and payment rails — manual reconciliation is impossible and automated reconciliation is hard.
We built a three-tier reconciliation engine. Tier 1 runs in real-time, matching incoming bank confirmations against our internal ledger by reference ID. This catches about 85% of transactions. Tier 2 runs hourly, using fuzzy matching on amount, timestamp, and counterparty to resolve transactions where reference IDs were mangled or dropped by intermediary banks. Tier 3 escalates to human review with full context, but this handles less than 1% of volume.
The key architectural decision was treating the internal ledger as the source of truth and building all reconciliation as a process of confirming external state against it, rather than the other way around. This made audit trails clean and dispute resolution straightforward.
Permission Systems and Multi-Tenancy
Bankwards serves multiple business clients, each with different user hierarchies, approval workflows, and compliance requirements. We built a role-based access control system layered on top of attribute-based policies — effectively RBAC for the common cases and ABAC for the edge cases.
The most underestimated requirement was maker-checker workflows for high-value payments. Regulators and enterprise clients both expect dual authorization above certain thresholds, but the threshold varies by client, currency, and corridor. We ended up building a configurable policy engine that evaluates authorization requirements dynamically per transaction.
The broader lesson from Bankwards: payments infrastructure is not a product you build and ship. It is a living system that requires constant adaptation to shifting regulatory requirements, bank API changes, and corridor-specific quirks. Build for change from day one, because everything will change.