Skip to content

GoPlasmatic/MXMessage

Repository files navigation

Plasmatic Logo

MXMessage

A Rust library for parsing, validating, and serializing ISO 20022 (MX) financial messages.

Full CBPR+ compliance with comprehensive validation and test data generation.

License: Apache 2.0 Rust Crates.io Swift CBPR+

🏒 Organization β€’ πŸ“– Documentation β€’ πŸ› Issues


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.

πŸš€ Key Features

  • CBPR+ SR2025 Compliant: Full support for Central Bank Payment Regulation Plus SR2025 schemas.
  • Simplified v3 API: Two main functions (to_json and to_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.

πŸ—οΈ How It Works: Schema-Driven Architecture

Generated Types from XSD

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),
}

Message Families

// 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 Initiation

🎯 Serialization Support

MXMessage 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
      }
    }]
  }
}

πŸ”§ Installation

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 logic

πŸ“– Usage

Basic Message Creation (v3 API)

use 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);

Test Data Generation

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 examples

Complete MX XML Generation (v3 Simplified API)

Generate 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)?;

Validation Error Handling

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),
        }
    }
}

Dataflow Integration (New in v3.1)

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/XML
  • validate_mx: Validate against schema and business rules
  • generate_mx: Generate sample data from scenarios
  • publish_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

Error Collection (Comprehensive Validation)

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");
}

πŸ§ͺ Testing Strategy

MXMessage uses comprehensive testing with 168 real-world scenarios migrated from MT messages, covering cross-border payments, securities, cash management, and more.

Key Testing Features

  • 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 datafake library
  • 100% Success Rate: All 1,680 tests pass (10 samples per scenario)

Quick Start

# 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 -- --nocapture

For detailed test scenarios and MT to MX mapping, see the Test Scenarios Documentation.

πŸ›οΈ CBPR+ SR2025 Compliance

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.02 for SR2025 compliance

πŸ“Š Supported Message Types

Payment Messages (pacs)

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

Payment Initiation (pain)

  • pain.001.001.09: Customer Credit Transfer Initiation
  • pain.008.001.08: Customer Direct Debit Initiation

Cash Management (camt)

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

🀝 Contributing

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

🏒 About Plasmatic

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.

πŸ“„ License

This library is licensed under the Apache License, Version 2.0. See the LICENSE file for details.


Built with ❀️ by the Plasmatic team

Packages

No packages published

Contributors 2

  •  
  •  

Languages