KibiPay
HomeBlog › Architecture

One Canonical Payment Model Across Every Rail

9 min read Architecture
ArchitectureISO 20022
One Canonical Payment Model Across Every Rail

A payments platform that speaks many rails faces a choice. It can let each rail's format leak into the core — a Faster Payments payment here, a Solana transfer there, a Mojaloop transfer somewhere else, each a different shape — or it can define one canonical representation of "a payment" and translate to each rail's native format only at the very edge. KibiPay takes the second path, and that single model is what lets fraud screening, ledgering, reconciliation and reporting treat every rail alike.

An ISO 20022 superset

The canonical payment is deliberately designed as a superset of ISO 20022. ISO 20022 is the richest common vocabulary in payments, so starting there means most rails map in without loss; being a superset means the model can also hold things ISO 20022 doesn't natively cover, like a Solana mint or a Mojaloop party identifier. Adapters translate this one model to and from native formats — Faster Payments XML, Bacs Standard 18, a SEPA pacs.008, a NACHA file — without the core ever knowing the difference.

The fields

A canonical payment carries the obvious things — an id, a tenant, a scheme, a direction (outbound or inbound), an amount validated as positive, and an ISO 4217 currency. It carries a debtor and a creditor as rich Party objects. It carries an idempotency key, an optional remittance and reference, a status, and a scheme reference like a UETR or an FPS reference. And it carries a few things that matter for a multi-rail, multi-asset world:

One Party, every addressing scheme

The cleverest part is the Party. Different rails address people completely differently, and rather than have a different party type per rail, one Party holds them all: an IBAN and BIC for SEPA; a six-digit sort code and eight-digit account number for UK rails; a US routing number for ACH; Mojaloop's FSPIOP fields (a party id type like MSISDN, an identifier, an MSISDN, an FSP id) for mobile money; and a base58 address, a mint and decimals for Solana. Each field is validated to its rail's rules. A single party object can therefore be addressed however the chosen rail requires, and the core code never branches on "what kind of party is this."

One lifecycle, every rail

Status is a single enum spanning every rail's lifecycle: CREATED, VALIDATED, PENDING_APPROVAL (an operator hold), PENDING_RESPONSE (a request-to-pay awaiting the debtor), SUBMITTED, ACCEPTED, SETTLED, plus the request-to-pay outcomes FULFILLED and DECLINED, and the terminal compensating states RETURNED, REVERSED, RECALLED, REJECTED and EXPIRED. Every rail's native states map onto this one vocabulary, so a dashboard, a report, or a reconciliation break can reason about "settled" or "returned" without caring which rail produced it.

Translation at the edge

The mapping to rails lives in one dispatch point: a submit step routes by scheme to the right adapter — Faster Payments, Bacs, CHAPS, SEPA, Mojaloop, Solana, request-to-pay — each of which turns the canonical payment into its native message and hands back a scheme reference and status. Add a rail and you write one adapter; the canonical model, and everything built on it, is untouched. That's the whole point: the rails are wildly different — a UK bank transfer and a Solana SPL-token transfer have almost nothing in common — but by the time a payment reaches the ledger or the fraud engine, it's just a canonical payment, one shape, every time.

What the model makes easy

The real dividend of a single canonical model shows up in every system built on top of it. Fraud and sanctions screening reason about one payment shape, so a rule written once applies whether the money is going over Faster Payments or Solana. The ledger posts against canonical amounts and currencies, so double-entry works identically regardless of rail. Reconciliation compares one status vocabulary against each scheme's answer. Reporting groups by the same scheme, status and currency fields no matter the underlying network. Adding a rail is therefore a contained job: write an adapter that translates canonical to native and back, register it in the dispatch step, and every cross-cutting concern — screening, ledgering, reconciliation, reporting, webhooks — works on the new rail for free, because none of them ever knew the rail existed. The alternative, letting each rail's format leak into the core, turns every one of those systems into a tangle of per-rail special cases. The canonical model is the single abstraction that keeps a genuinely multi-rail platform from collapsing under its own combinatorics, and designing it as an ISO 20022 superset means the abstraction is grounded in the industry's richest shared vocabulary rather than an invented one.

See it in motion

KibiPay connects UK Faster Payments, Bacs, CHAPS, Mojaloop mobile money, a mock ACH rail and Solana behind one API, with a cross-rail alias directory, ISO 20022 messaging and real-time fraud & AML screening.

Open the live console Directory demo