mx20022
Production-grade ISO 20022 toolkit for Rust. Strongly-typed message models generated from official XSD schemas, with built-in validation for FedNow, SEPA, and CBPR+ payment rails and bidirectional SWIFT MT ↔ MX translation — everything you need to build, validate, and migrate financial messages in a single crate.
Features
- 13 message schemas — pacs.008, pacs.002, pacs.004, pacs.009, pacs.028, pain.001, pain.002, pain.013, camt.053, camt.054, camt.056, camt.029, head.001
- Strongly typed — every element, attribute, and enum variant is a named Rust type with serde Serialize/Deserialize
- Builder pattern — all struct types expose a builder with required-field validation
- XML round-trip — parse and serialize ISO 20022 XML via quick-xml + serde
- MT parser — SWIFT FIN message parser for MT103, MT202, MT940
- Bidirectional translation — MT103 ↔ pacs.008, MT202 ↔ pacs.009, MT940 ↔ camt.053
- Validation — IBAN, BIC, LEI, currency, amount format, plus scheme-level rules for FedNow, SEPA, and CBPR+
- XSD constraint validation — every generated newtype validates pattern,
length, and range constraints at construction (
TryFrom<String>) and on full message trees via theValidatabletrait - Code generation — XSD → intermediate representation → Rust source
Installation
Umbrella crate (recommended)
The easiest way to get started — re-exports model, parse, validate, and translate with all message families enabled:
Individual crates
Pick only what you need for smaller compile times and dependency footprint:
CLI tool
Feature flags
Feature flags on mx20022-model control which message families are compiled.
The umbrella crate enables all of them.
| Feature | Message families | Default |
|---|---|---|
pacs |
pacs.002, pacs.004, pacs.008, pacs.009, pacs.028 | yes |
pain |
pain.001, pain.002, pain.013 | no |
camt |
camt.029, camt.053, camt.054, camt.056 | no |
head |
head.001 | no |
all |
all of the above | no |
Usage
Parse an ISO 20022 message
use Document;
use ;
let xml = read_to_string?;
// Detect the message type from the XML namespace
let msg_id = detect_message_type?;
println!; // e.g. "pacs.008.001.13"
// Deserialize to a strongly-typed struct
let doc: Document = from_str?;
let hdr = &doc.fi_to_fi_cstmr_cdt_trf.grp_hdr;
println!;
println!;
Validate against FedNow rules
use ;
let validator = new; // $500K default limit
let result = validator.validate;
if result.is_valid else
Validate XSD constraints on a message
use IsoMessage;
use Document;
use de;
let xml = read_to_string?;
let doc: Document = from_str?;
let violations = doc.validate_message;
if violations.is_empty else
Translate MT103 → pacs.008
use mt;
use parse_mt103;
use mt103_to_pacs008;
use ser;
let mt_text = read_to_string?;
// Parse raw SWIFT FIN blocks → MT103 fields
let msg = parse?;
let mt103 = parse_mt103?;
// Translate to pacs.008 document
let result = mt103_to_pacs008?;
// Serialize back to XML
let xml = to_string?;
println!;
CLI
Commands
# Inspect message structure
# Validate with optional scheme rules
# Translate between MT and MX
# Generate Rust types from an XSD
Supported --to targets: pacs008, mt103, pacs009, mt202, camt053, mt940.
Supported --scheme values: fednow, sepa, cbpr.
The CLI rejects input files larger than 10 MB to prevent out-of-memory conditions.
Development
# Run all checks (check + test + clippy + fmt)
# Individual commands
# Full CI suite locally
Project Layout
mx20022/
├── crates/
│ ├── mx20022/ # Umbrella re-export + examples
│ ├── mx20022-model/ # Generated types (src/generated/) + common types (src/common/)
│ ├── mx20022-parse/ # XML parsing and serialization
│ ├── mx20022-validate/ # Schema, business rule, and scheme validation
│ ├── mx20022-translate/ # MT ↔ MX translation + MT parser
│ ├── mx20022-codegen/ # XSD → Rust code generator
│ └── mx20022-cli/ # Command-line tool
├── schemas/ # ISO 20022 XSD source files
├── testdata/ # Shared test fixtures (XML, MT, translation pairs)
├── docs/ # Project documentation
├── justfile # Task runner
├── deny.toml # cargo-deny configuration
└── rust-toolchain.toml # Rust stable + components
Key boundary: Files under crates/mx20022-model/src/generated/ are
machine-written by the codegen tool. Do not hand-edit them — modify the code
generator instead.
See ARCHITECTURE.md for a detailed design walkthrough of each crate, the code generation pipeline, and key architectural decisions.
Running Examples
Supported Messages
| Family | Message | Version | Description |
|---|---|---|---|
| head | 001.001 | 04 | Business Application Header |
| pacs | 008.001 | 13 | FI to FI Customer Credit Transfer |
| pacs | 002.001 | 14 | Payment Status Report |
| pacs | 004.001 | 11 | Return of Funds |
| pacs | 009.001 | 10 | FI to FI Credit Transfer |
| pacs | 028.001 | 05 | FI Status Request |
| pain | 001.001 | 11 | Customer Credit Transfer Initiation |
| pain | 002.001 | 13 | Customer Payment Status Report |
| pain | 013.001 | 09 | Creditor Payment Activation Request |
| camt | 053.001 | 11 | Bank to Customer Statement |
| camt | 054.001 | 11 | Bank to Customer Debit/Credit Notification |
| camt | 056.001 | 11 | Payment Cancellation Request |
| camt | 029.001 | 12 | Resolution of Investigation |
Contributing
- Fork the repository
- Create a feature branch (
git checkout -b feat/my-change) - Ensure all checks pass:
just ci - Open a pull request against
main
All code must pass cargo check, cargo test, cargo clippy -- -D warnings,
and cargo fmt --check before merge. CI runs these on both stable and MSRV
1.75.0.
unsafe code is forbidden workspace-wide.
License
Licensed under the Apache License, Version 2.0 (LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0).