mx20022 0.1.1

Production-grade ISO 20022 toolkit: strongly-typed message models, FedNow/SEPA/CBPR+ validation, and bidirectional SWIFT MT↔MX translation
Documentation

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.

Crates.io docs.rs CI License: Apache-2.0 MSRV: 1.75.0

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 the Validatable trait
  • 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:

cargo add mx20022

Individual crates

Pick only what you need for smaller compile times and dependency footprint:

cargo add mx20022-model    # Generated types + common types
cargo add mx20022-parse    # XML parsing and serialization
cargo add mx20022-validate # Schema, business rule, and scheme validation
cargo add mx20022-translate # MT ↔ MX bidirectional translation
cargo add mx20022-codegen  # XSD → Rust code generator

CLI tool

cargo install mx20022-cli

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 mx20022::model::generated::pacs::pacs_008_001_13::Document;
use mx20022::parse::{de, envelope};

let xml = std::fs::read_to_string("message.xml")?;

// Detect the message type from the XML namespace
let msg_id = envelope::detect_message_type(&xml)?;
println!("Message type: {}", msg_id.dotted()); // e.g. "pacs.008.001.13"

// Deserialize to a strongly-typed struct
let doc: Document = de::from_str(&xml)?;
let hdr = &doc.fi_to_fi_cstmr_cdt_trf.grp_hdr;
println!("Message ID: {}", hdr.msg_id.0);
println!("Transactions: {}", hdr.nb_of_txs.0);

Validate against FedNow rules

use mx20022::validate::schemes::{fednow::FedNowValidator, SchemeValidator};

let validator = FedNowValidator::new(); // $500K default limit
let result = validator.validate(&xml, "pacs.008.001.13");

if result.is_valid() {
    println!("Valid ({} warnings)", result.warning_count());
} else {
    for err in &result.errors {
        println!("[{}] {}{}", err.rule_id, err.path, err.message);
    }
}

Validate XSD constraints on a message

use mx20022::model::common::validate::IsoMessage;
use mx20022::model::generated::pacs::pacs_008_001_13::Document;
use mx20022::parse::de;

let xml = std::fs::read_to_string("message.xml")?;
let doc: Document = de::from_str(&xml)?;
let violations = doc.validate_message();

if violations.is_empty() {
    println!("All XSD constraints satisfied");
} else {
    for v in &violations {
        println!("[{:?}] {}{}", v.kind, v.path, v.message);
    }
}

Translate MT103 → pacs.008

use mx20022::translate::mt;
use mx20022::translate::mt::fields::mt103::parse_mt103;
use mx20022::translate::mappings::mt103_to_pacs008::mt103_to_pacs008;
use mx20022::parse::ser;

let mt_text = std::fs::read_to_string("mt103.txt")?;

// Parse raw SWIFT FIN blocks → MT103 fields
let msg = mt::parse(&mt_text)?;
let mt103 = parse_mt103(&msg.block4)?;

// Translate to pacs.008 document
let result = mt103_to_pacs008(&mt103, "MSG-001", "2024-01-15T10:00:00")?;

// Serialize back to XML
let xml = ser::to_string(&result.message)?;
println!("{xml}");

CLI

Commands

# Inspect message structure
mx20022-cli inspect testdata/xml/pacs/pacs_008_001_13_minimal.xml

# Validate with optional scheme rules
mx20022-cli validate testdata/xml/pacs/pacs_008_001_13_minimal.xml
mx20022-cli validate message.xml --scheme fednow

# Translate between MT and MX
mx20022-cli translate testdata/mt/mt103.txt --to pacs008
mx20022-cli translate message.xml --to mt103

# Generate Rust types from an XSD
mx20022-cli codegen schemas/pacs/pacs.008.001.13.xsd -o output.rs

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)
just

# Individual commands
just check          # cargo check --workspace --all-features
just test           # cargo test --workspace --all-features
just clippy         # clippy with -D warnings
just fmt            # auto-format
just fmt-check      # format check only
just deny           # cargo-deny license/advisory audit
just doc            # build documentation
just bench          # run criterion benchmarks
just coverage       # HTML coverage report via llvm-cov
just msrv           # verify MSRV 1.75.0 compatibility

# Full CI suite locally
just ci

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

cargo run -p mx20022 --example parse_pacs008
cargo run -p mx20022 --example validate_message
cargo run -p mx20022 --example translate_mt103
cargo run -p mx20022 --example roundtrip

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

  1. Fork the repository
  2. Create a feature branch (git checkout -b feat/my-change)
  3. Ensure all checks pass: just ci
  4. 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).