A Rust library for parsing, validating, and serializing ISO 20022 (MX) financial messages.
Full CBPR+ compliance with comprehensive validation and test data generation.
MXMessage is a comprehensive Rust library for handling ISO 20022 (MX) financial messages. It provides type-safe parsing, validation, and serialization for CBPR+ compliant messages, with powerful test data generation capabilities for all supported message types.
- CBPR+ SR2025 Compliant: Full support for Central Bank Payment Regulation Plus SR2025 schemas.
- Simplified v3 API: Two main functions (
to_jsonandto_xml) handle all message types with automatic envelope generation. - Type-Safe: Strongly typed Rust structures generated from official XSD schemas.
- Comprehensive Validation: Field-level, pattern, and business rule validation with detailed error codes.
- Complete MX XML Generation: Automatic ISO 20022 compliant XML with proper AppHdr envelope.
- Multiple Formats: Native support for both JSON and XML serialization.
- Test Data Generation: Automatic generation of valid test messages using configurable scenarios.
- Extensive Coverage: Support for pacs, pain, and camt message families.
- Zero-Copy Parsing: Efficient processing with minimal allocations.
- Dataflow Integration: Plugin support for dataflow-rs engine enabling async processing pipelines.
- Enhanced XML Support: Advanced XML serialization with configurable formatting and namespace handling.
All message types are automatically generated from official ISO 20022 XSD schemas.
use mx_message::document::Document;
use mx_message::pacs_008_001_08::*;
// Create a strongly-typed payment message
let payment = FIToFICustomerCreditTransferV08 {
grp_hdr: GroupHeader93 {
msg_id: "MSGID123456".to_string(),
cre_dt_tm: "2024-01-15T10:30:00Z".to_string(),
nb_of_txs: "1".to_string(),
// ... other fields
},
cdt_trf_tx_inf: vec![/* transactions */],
splmtry_data: None,
};
// Automatic validation
match Document::FIToFICustomerCreditTransferV08(Box::new(payment)).validate() {
Ok(_) => println!("β Valid CBPR+ compliant message"),
Err(e) => println!("β Validation error: {} (code: {})", e.message, e.code),
}// Payment messages
use mx_message::document::Document;
use mx_message::pacs_008_001_08::*; // Customer Credit Transfer
use mx_message::pacs_009_001_08::*; // Financial Institution Credit Transfer
// Cash management messages
use mx_message::camt_053_001_08::*; // Bank to Customer Statement
use mx_message::camt_056_001_08::*; // Payment Cancellation Request
// Payment initiation messages
use mx_message::pain_001_001_09::*; // Customer Credit Transfer Initiation
use mx_message::pain_008_001_08::*; // Customer Direct Debit InitiationMXMessage provides seamless serialization between JSON and XML formats with enhanced XML capabilities.
use mx_message::document::Document;
use mx_message::xml::{XmlConfig, to_mx_xml};
use serde_json;
// Parse from JSON
let doc: Document = serde_json::from_str(json_str)?;
// Serialize to pretty JSON
let json_output = serde_json::to_string_pretty(&doc)?;
// Enhanced XML serialization with configuration
let xml_config = XmlConfig {
include_declaration: true,
pretty_print: true,
indent: " ".to_string(),
include_schema_location: true,
};
// Generate complete MX XML with envelope
let xml_output = to_mx_xml(&doc, header, "pacs.008.001.08", Some(xml_config))?;Example JSON Output:
{
"FIToFICstmrCdtTrf": {
"GrpHdr": {
"MsgId": "MSGID123456",
"CreDtTm": "2024-01-15T10:30:00Z",
"NbOfTxs": "1",
"TtlIntrBkSttlmAmt": {
"@Ccy": "EUR",
"$value": 1000.00
}
},
"CdtTrfTxInf": [{
"PmtId": {
"EndToEndId": "E2E123456",
"UETR": "12345678-1234-5678-1234-567812345678"
},
"IntrBkSttlmAmt": {
"@Ccy": "EUR",
"$value": 1000.00
}
}]
}
}Add mx-message to your Cargo.toml:
[dependencies]
mx-message = "3.1"
serde_json = "1.0" # For JSON support
quick-xml = { version = "0.38", features = ["serialize"] } # For XML support
# Optional: For dataflow pipeline integration
dataflow-rs = "2.0" # For async processing pipelines
datalogic-rs = "4.0" # For validation logicuse mx_message::{to_json, to_xml};
use mx_message::document::Document;
use mx_message::pacs_008_001_08::*;
// Create a payment message
let payment = FIToFICustomerCreditTransferV08 {
grp_hdr: GroupHeader93 {
msg_id: "MSGID123456".to_string(),
cre_dt_tm: "2024-01-15T10:30:00Z".to_string(),
nb_of_txs: "1".to_string(),
// ... other fields
},
cdt_trf_tx_inf: vec![/* transactions */],
splmtry_data: None,
};
let document = Document::FIToFICustomerCreditTransferV08(Box::new(payment));
// Validate against CBPR+ SR2025 rules
match document.validate() {
Ok(_) => println!("β Message is valid"),
Err(e) => eprintln!("β Validation failed: {}", e.message),
}
// Convert to JSON (simplified v3 API)
let json = to_json(&document)?;
println!("{}", json);
// Convert to XML with automatic envelope (simplified v3 API)
let xml = to_xml(&document)?;
println!("{}", xml);use mx_message::sample::generate_sample;
// Generate test data from scenario files
let sample = generate_sample("pacs008", Some("cbpr_cross_border_payment"))?;
println!("Generated sample: {}", serde_json::to_string_pretty(&sample)?);
// Scenarios support fake data generation
// See test_scenarios/ directory for examplesGenerate ISO 20022 compliant XML with proper envelope and Business Application Header using the simplified v3 API:
use mx_message::{to_json, to_xml};
use mx_message::document::Document;
// Create or load your message
let document = Document::FIToFICustomerCreditTransferV08(/* ... */);
// Convert to JSON - simple one-liner
let json = to_json(&document)?;
println!("{}", json);
// Convert to XML with automatic envelope generation
let xml = to_xml(&document)?;
println!("{}", xml);The v3 API automatically:
- Generates the correct Business Application Header based on message type
- Creates a properly formatted MX envelope with AppHdr
- Sets appropriate namespaces and CBPR+ compliance indicators
- Handles all message types uniformly
Note: The simplified API uses sensible defaults. For advanced customization of headers and envelopes, the lower-level APIs are still available:
use mx_message::mx_envelope::create_mx_envelope;
use mx_message::header::head_001_001_02::BusinessApplicationHeaderV02;
// Create custom header for advanced use cases
let custom_header = BusinessApplicationHeaderV02 {
fr: Party44Choice {
fiid: Some(FinancialInstitutionIdentification18 {
bicfi: Some("BANKUS33XXX".to_string()),
..Default::default()
}),
..Default::default()
},
to: Party44Choice {
fiid: Some(FinancialInstitutionIdentification18 {
bicfi: Some("BANKGB22XXX".to_string()),
..Default::default()
}),
..Default::default()
},
biz_msg_idr: "MSG-2024-001".to_string(),
msg_def_idr: "pacs.008.001.08".to_string(),
biz_svc: Some("swift.cbprplus.02".to_string()),
cre_dt: "2024-01-15T10:30:00Z".to_string(),
..Default::default()
};
// Create envelope with custom header
let envelope = create_mx_envelope(custom_header, document)?;
let xml = quick_xml::se::to_string(&envelope)?;use mx_message::document::Document;
match document.validate() {
Ok(_) => println!("β Valid"),
Err(e) => {
match e.code {
1001 => println!("Field too short: {}", e.message),
1002 => println!("Field too long: {}", e.message),
1005 => println!("Invalid pattern: {}", e.message),
_ => println!("Validation error: {}", e.message),
}
}
}MXMessage now provides seamless integration with dataflow-rs for building async processing pipelines with a clean, refactored plugin architecture:
use mx_message::plugin::register_mx_functions;
use dataflow_rs::Engine;
// Register MX message functions with dataflow engine
let functions = register_mx_functions();
let mut engine = Engine::new();
for (name, handler) in functions {
engine.register_function(name, handler);
}
// Create a pipeline workflow
let workflow = r#"
{
"name": "mx-processing-pipeline",
"tasks": [
{
"id": "generate",
"function": "generate_mx",
"params": {
"message_type": "pacs.008",
"scenario": "cbpr_business_payment"
}
},
{
"id": "validate",
"function": "validate_mx",
"inputs": ["generate.output"]
},
{
"id": "publish",
"function": "publish_mx",
"params": {
"format": "xml"
},
"inputs": ["validate.output"]
}
]
}
"#;
// Execute the pipeline asynchronously
let result = engine.execute(workflow).await?;Available dataflow functions:
parse_mx: Parse MX messages from JSON/XMLvalidate_mx: Validate against schema and business rulesgenerate_mx: Generate sample data from scenariospublish_mx: Serialize to JSON/XML formats
The plugin architecture has been refactored for better maintainability:
- Common utilities module (
plugin::common) provides shared functionality - Centralized format detection and message type mapping
- Reduced code duplication across plugin modules
- Type-safe error handling with improved error types
MXMessage supports collecting all validation errors instead of stopping at the first error:
use mx_message::validation::Validate;
use mx_message::parse_result::{ParserConfig, ErrorCollector};
use mx_message::pacs_008_001_08::FIToFICustomerCreditTransferV08;
// Create a message with multiple validation issues
let payment = FIToFICustomerCreditTransferV08 {
grp_hdr: GroupHeader93 {
msg_id: "ID", // Too short (min 5 chars)
cre_dt_tm: "invalid-date", // Wrong format
nb_of_txs: "ABC", // Should be numeric
// ... other fields
},
// ... other fields
};
// Collect all validation errors
let config = ParserConfig::default();
let mut collector = ErrorCollector::new();
payment.validate("", &config, &mut collector);
// Process all errors at once
if collector.has_errors() {
println!("Found {} validation errors:", collector.errors().len());
for error in collector.errors() {
println!(" - {}: {} (code: {})",
error.path.as_ref().unwrap_or(&"root".to_string()),
error.message,
error.code
);
}
} else {
println!("β Message is valid");
}MXMessage uses comprehensive testing with 168 real-world scenarios migrated from MT messages, covering cross-border payments, securities, cash management, and more.
- Scenario-Based Testing: 168 scenarios across 16 message types
- Round-Trip Validation: JSON β Generate β Validate β JSON testing
- MT to MX Migration: 99.4% coverage of MT message scenarios
- Sample Generation: Automatic test data using
datafakelibrary - 100% Success Rate: All 1,680 tests pass (10 samples per scenario)
# Run all test scenarios
cargo test round_trip_scenarios
# Test specific message type
TEST_MESSAGE_TYPE=pacs.008 cargo test round_trip_scenarios
# Debug a specific scenario
TEST_MESSAGE_TYPE=pacs.008 TEST_SCENARIO=cbpr_cross_border_payment TEST_DEBUG=1 cargo test round_trip_scenarios -- --nocaptureFor detailed test scenarios and MT to MX mapping, see the Test Scenarios Documentation.
This library implements CBPR+ SR2025 (Central Bank Payment Regulation Plus Standards Release 2025) compliant schemas, providing:
- Enhanced Validation: Stricter rules for regulatory compliance
- UETR Support: Unique End-to-end Transaction Reference tracking
- Central Bank Integration: Support for central bank payment systems
- Cross-Border Payments: Full support for international transactions
- Regulatory Reporting: Compliance with reporting requirements
- BizSvc SR2025: Updated Business Service identifier
swift.cbprplus.02for SR2025 compliance
- pacs.002.001.10: Payment Status Report
- pacs.003.001.08: Direct Debit
- pacs.004.001.09: Payment Return
- pacs.008.001.08: Customer Credit Transfer
- pacs.009.001.08: Financial Institution Credit Transfer
- pacs.010.001.03: Financial Institution Direct Debit (New in v3.1)
- pain.001.001.09: Customer Credit Transfer Initiation
- pain.008.001.08: Customer Direct Debit Initiation
- camt.025.001.05: Receipt
- camt.027.001.07: Claim Non Receipt
- camt.028.001.09: Additional Payment Information
- camt.029.001.09: Resolution of Investigation
- camt.052.001.08: Bank to Customer Account Report
- camt.053.001.08: Bank to Customer Statement
- camt.054.001.08: Bank to Customer Debit/Credit Notification
- camt.056.001.08: Payment Cancellation Request
- camt.057.001.06: Notification to Receive
- camt.060.001.05: Account Reporting Request
- camt.107.001.01: Cheque Presentment Notification (New in v3.1)
- camt.108.001.01: Cheque Stop Request (New in v3.1)
- camt.109.001.01: Cheque Cancellation or Stop Request Status (New in v3.1)
Contributions are welcome! If you'd like to help, please feel free to fork the repository, make your changes, and submit a pull request. We ask that you:
- Ensure all new message types follow CBPR+ compliance standards
- Add comprehensive tests for new functionality
- Update documentation for any new features
- Follow existing code style and validation patterns
MXMessage is developed by Plasmatic, an organization focused on building open-source tools for financial infrastructure. We believe in transparency, security, and performance.
Check out our other projects:
- SwiftMTMessage: A SWIFT MT message parsing library.
- Reframe: A SWIFT MT to ISO 20022 (and back) transformation engine.
This library is licensed under the Apache License, Version 2.0. See the LICENSE file for details.
Built with β€οΈ by the Plasmatic team