← Case studies

Payments · Real-time rails · Standards · 2025

FedNow ISO-20022 Message Handling

3,000+ parameters, specified and validated

Parsing and validation for US Federal Reserve FedNow ISO-20022 messages, plus the parameter specification that made the implementation reviewable.

Role
Backend engineer — implementation and specification
Stack
JavaSpring BootISO-20022XML Schema
Focus
CorrectnessStandardsValidation
  • Parameters documented3,000+valid values + semantics
  • Validationschema + semantic
  • Settlement modelinstant, irrevocable

Problem

FedNow is the Federal Reserve’s instant payment rail. Two properties of it shape every engineering decision downstream:

  1. Settlement is immediate and irrevocable. There is no batch window in which to notice a mistake and pull it back.
  2. The message format is ISO-20022, which is not a format so much as a grammar — deeply nested XML, heavily conditional, with an enormous surface of optional elements whose validity depends on other elements.

A rail like that punishes permissive parsing. Anything the system accepts, it has committed to.

Why ISO-20022 is harder than it looks

A naive reading treats it as “XML with a schema, so let the schema validate it”. The schema is necessary and nowhere near sufficient.

  inbound message
      │
      ▼
┌────────────────────┐
│  XSD validation    │  structure, types, cardinality
└─────────┬──────────┘
        │ structurally valid
        ▼
┌────────────────────┐
│ semantic validation│  conditional rules, code sets,
│                    │  cross-field consistency
└─────────┬──────────┘
        │ meaningful
        ▼
  business processing
Two distinct validation layers. The schema answers 'is this well-formed?'; only the semantic layer answers 'does this mean something legal?'

The schema will happily accept a message that is structurally perfect and semantically nonsense — a currency code that does not pair with the settlement method, an optional block that becomes mandatory because of a value three levels up, a code-set entry that is valid ISO but not permitted on this rail.

What I built

A parser with an explicit failure contract. Rejection identifies the offending element by path and the rule it violated. On an instant rail, “invalid message” is not an acceptable error: the sender needs to know precisely what to fix, because there is no retry-and-hope.

Two-layer validation. Structural via XSD, then a semantic layer for the conditional rules, permitted code sets and cross-field consistency the schema cannot express.

A specification of 3,000+ parameters — each with its valid values and a semantic description of what it means.

Why the specification was the real work

Writing the parser was tractable. Writing down what every parameter means was the part that made the parser trustworthy.

Without it, correctness lives in whoever last read the standard. Every review becomes an argument from memory, every edge case a re-reading of the spec, and onboarding takes as long as it takes one person to absorb ISO-20022. With it, a reviewer can check an implementation against a stated rule, and a disagreement resolves against a document rather than a recollection.

It is also the artefact that survives me on the codebase, which is the honest test of whether documentation was worth writing.

Result

Parsing and validation for FedNow messages, with a parameter specification that makes the behaviour auditable rather than inferred — and rejections precise enough to act on before settlement rather than after.

What I would revisit

The semantic rules are expressed in code. A declarative rule table, generated from the same specification, would remove the possibility of the two drifting apart — the classic failure mode where documentation and behaviour diverge silently and nobody notices until a message is wrongly accepted.