<div align="center">
<img src="https://avatars.githubusercontent.com/u/207296579?s=200&v=4" alt="Plasmatic Logo" width="120" height="120">
# ISO8583
**A high-performance Rust library for parsing and serializing ISO 8583 financial messages.**
*JSON-spec-driven architecture with support for Visa BASE I, Mastercard MIP, and generic ISO 8583 — no code changes needed for new networks.*
[](https://opensource.org/licenses/Apache-2.0)
[](https://www.rust-lang.org)
[](https://crates.io/crates/iso8583-codec-rs)
<p>
<a href="https://github.com/GoPlasmatic">Organization</a> •
<a href="https://docs.rs/iso8583-codec-rs">Documentation</a> •
<a href="https://github.com/GoPlasmatic/ISO8583/issues">Issues</a>
</p>
</div>
-----
ISO8583 is a production-ready Rust library for handling ISO 8583 financial messages used in payment card transactions. Field definitions live entirely in JSON specification files — adding support for new card networks or custom fields requires **zero code changes**. The library ships with bundled specs for **Generic ISO 8583**, **Visa BASE I**, and **Mastercard MIP**.
## Key Features
- **JSON-Spec-Driven:** Field definitions, encodings, padding, and validation rules all live in JSON — extend or customize without touching Rust code
- **Multi-Network Support:** Bundled specs for Generic ISO 8583:1987, Visa BASE I, and Mastercard MIP with correct encoding defaults
- **Multi-Encoding:** ASCII, EBCDIC (CP037), BCD (packed Binary Coded Decimal), and Binary/Hex encodings
- **Composite Fields:** Ordered subfields, TLV (EMV ICC data with BER-TLV), Bitmap-based composites, and Mastercard PDS (Private Data Subelements)
- **Non-Blocking Validation:** Accumulates all validation errors instead of failing on the first — MTI, mandatory fields, format, length, pattern, and response code checks
- **Bitmap Support:** Primary, secondary, and tertiary bitmaps with hex and binary encodings (up to 192 data elements)
- **Response Code Lookup:** 87 standard DE 39 response codes with lazy-loaded lookup
- **Performance Optimized:** O(1) field lookup via HashMap, zero-copy where possible, minimal allocations
- **67 Tests:** Comprehensive test coverage across all encodings, networks, and composite field types
## Architecture
### JSON Specification System
The library is driven by JSON spec files that define per-field encoding, prefix type, padding, and validation rules. Each spec has defaults that individual fields can override:
```json
{
"version": "2003",
"defaults": {
"encoding": "ebcdic",
"prefix_encoding": "bcd",
"bitmap_encoding": "binary",
"mti_encoding": "bcd",
"max_bitmaps": 3
},
"fields": {
"2": {
"name": "primary_account_number",
"field_type": "string",
"prefix": "llvar",
"max_length": 19
}
}
}
```
### Data Flow
**Parsing:** `hex string` → `decode MTI` → `decode bitmap` → `unpack each field` → `JSON output`
**Publishing:** `JSON input` → `encode MTI` → `encode bitmap` → `pack each field` → `hex string`
### Bundled Specifications
| `fields.json` | 1987 | ASCII | ASCII | Hex | ASCII | 2 | Generic ISO 8583 |
| `visa_base1.json` | 2003 | EBCDIC | BCD | Binary | BCD | 3 | Visa BASE I |
| `mastercard_mip.json` | 2003 | EBCDIC | BCD | Binary | ASCII | 2 | Mastercard MIP |
## Installation
Add `iso8583-codec-rs` to your `Cargo.toml`:
```toml
[dependencies]
iso8583-codec-rs = "0.1"
```
## Usage
### Basic Parsing and Publishing
```rust
use iso8583_codec_rs::{load_spec, parse, publish};
use serde_json::json;
// Load a specification
let spec_json = include_str!("specifications/fields.json");
let spec = load_spec(spec_json).unwrap();
// Build a message as JSON
let message = json!({
"mti": "0200",
"fields": {
"de002_primary_account_number": "4111111111111111",
"de003_processing_code": "000000",
"de004_amount_transaction": "000000001000",
"de011_system_trace_audit_number": "123456",
"de041_card_acceptor_terminal_id": "TERM0001"
}
});
// Publish to hex-encoded ISO 8583
let hex_message = publish(&message, &spec).unwrap();
// Parse back to JSON
let parsed = parse(&hex_message, &spec).unwrap();
assert_eq!(parsed["mti"], "0200");
assert_eq!(parsed["fields"]["de002_primary_account_number"], "4111111111111111");
```
### Network-Specific Messages
```rust
use iso8583_codec_rs::{load_spec, parse, publish};
use serde_json::json;
// Visa BASE I (EBCDIC + BCD prefix + Binary bitmap + BCD MTI)
let visa_spec = load_spec(include_str!("specifications/visa_base1.json")).unwrap();
let visa_auth = json!({
"mti": "0100",
"fields": {
"de002_primary_account_number": "4111111111111111",
"de003_processing_code": "000000",
"de004_amount_transaction": "000000005000",
"de014_expiration_date": "2512",
"de022_pos_entry_mode": {
"pan_entry_mode": "05",
"pin_entry_capability": "1"
},
"de041_card_acceptor_terminal_id": "TERM0001",
"de049_currency_code_transaction": "840"
}
});
let hex = publish(&visa_auth, &visa_spec).unwrap();
let parsed = parse(&hex, &visa_spec).unwrap();
// Mastercard MIP (EBCDIC data + ASCII MTI + BCD prefix + Binary bitmap)
let mc_spec = load_spec(include_str!("specifications/mastercard_mip.json")).unwrap();
let mc_auth = json!({
"mti": "0100",
"fields": {
"de002_primary_account_number": "5500000000000004",
"de003_processing_code": "000000",
"de004_amount_transaction": "000000002500",
"de049_currency_code_transaction": "840"
}
});
let hex = publish(&mc_auth, &mc_spec).unwrap();
let parsed = parse(&hex, &mc_spec).unwrap();
```
### Composite Fields
The library handles four types of composite fields transparently:
```rust
use serde_json::json;
// Ordered: subfields concatenated in sequence (e.g., DE 22 POS Entry Mode)
"de022_pos_entry_mode": {
"pan_entry_mode": "05",
"pin_entry_capability": "1"
}
// TLV: Tag-Length-Value for EMV data (e.g., DE 55)
// Supports 1-byte, 2-byte, and 3-byte tags with BER-TLV length encoding
"de055_emv_data": {
"9F26": "AABBCCDD11223344",
"9F27": "80",
"9F8101": "FF"
}
// Bitmap: internal bitmap indicating present subfields (e.g., Visa DE 62)
"de062_custom_payment_service": {
"authorization_characteristics": "A",
"transaction_id": "123456789012345"
}
// PDS: Mastercard Private Data Subelements (e.g., Mastercard DE 48)
"de048_additional_data_private": {
"0023": "ABCDE",
"0043": "12345"
}
```
### Validation
Validation is non-blocking and accumulates all errors:
```rust
use iso8583_codec_rs::{load_spec, validate};
use serde_json::json;
let spec = load_spec(include_str!("specifications/fields.json")).unwrap();
let message = json!({
"mti": "0100",
"fields": {
"de002_primary_account_number": "4111111111111111",
"de003_processing_code": "000000",
"de004_amount_transaction": "000000005000",
"de007_transmission_date_time": "0725143052",
"de011_system_trace_audit_number": "000001",
"de014_expiration_date": "2512",
"de022_pos_entry_mode": { "pan_entry_mode": "05", "pin_entry_capability": "1" },
"de025_pos_condition_code": "00",
"de041_card_acceptor_terminal_id": "TERM0001",
"de042_card_acceptor_id_code": "MERCHANT000001 ",
"de049_currency_code_transaction": "840"
}
});
let result = validate(&message, &spec);
if result.is_valid() {
println!("Message is valid");
} else {
for error in &result.errors {
println!("DE {}: [{}] {}", error.de, error.rule, error.message);
}
}
```
**Validation rules include:**
- **MTI:** Format (4 digits), version (0/1/2/9), class (1-8), function (0-5)
- **Mandatory fields:** Per-MTI required field checks
- **Format:** Numeric (digits only), binary (hex only), x+n (C/D prefix + digits)
- **Length:** Min/max constraints, fixed-length enforcement
- **Pattern:** MMDD dates, hhmmss times, YYMM expiry dates
- **Response codes:** DE 39 validated against 87 known codes
### Response Code Lookup
```rust
use iso8583_codec_rs::lookup_response_code;
assert_eq!(lookup_response_code("00"), Some("Approved"));
assert_eq!(lookup_response_code("05"), Some("Do Not Honor"));
assert_eq!(lookup_response_code("51"), Some("Insufficient Funds"));
assert_eq!(lookup_response_code("54"), Some("Expired Card"));
```
## Module Overview
| `lib.rs` | Public API: `parse()`, `publish()`, `load_spec()`, `validate()`, `lookup_response_code()` |
| `iso8583.rs` | Parse/publish pipeline orchestration, composite field dispatch |
| `codec.rs` | Field-level encode/decode (ASCII, EBCDIC, BCD, Binary), prefix handling, padding |
| `bitmap.rs` | Primary/secondary/tertiary bitmap handling (hex and binary) |
| `mti.rs` | Message Type Indicator encode/decode and classification |
| `field_spec.rs` | `LoadedSpec` and `FieldSpec` structs, JSON spec loading |
| `validation.rs` | Non-blocking validation with accumulated errors |
| `error.rs` | `Iso8583Error` enum with structured error variants |
## Encoding Support
| ASCII | String/Numeric fields | LLVAR/LLLVAR/LLLLVAR length | 16 hex chars per bitmap | 4 ASCII chars |
| EBCDIC (CP037) | String/Numeric fields | LLVAR/LLLVAR/LLLLVAR length | — | 4 EBCDIC chars |
| BCD | Packed numeric (2 digits/byte) | Packed length prefix | — | 2 BCD bytes |
| Binary/Hex | Raw binary data (e.g., PIN block) | — | 8 bytes per bitmap | — |
## Testing
```bash
# Run all 67 tests
cargo test
# Run a single test
cargo test test_simple_round_trip
# Run tests with output visible
cargo test -- --nocapture
# Run network-specific tests
cargo test visa
cargo test mastercard
```
## 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 test coverage for new features and follow existing code patterns.
## About Plasmatic
ISO8583 is developed by [Plasmatic](https://github.com/GoPlasmatic), an organization focused on building open-source tools for financial infrastructure. We believe in transparency, security, and performance.
Check out our other projects:
- [SwiftMTMessage](https://github.com/GoPlasmatic/SwiftMTMessage): A SWIFT MT message parsing library.
- [MXMessage](https://github.com/GoPlasmatic/MXMessage): An ISO 20022 (MX) message parsing library.
- [Reframe](https://github.com/GoPlasmatic/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](LICENSE) file for details.
-----
<div align="center">
<p>Built with care by the <a href="https://github.com/GoPlasmatic">Plasmatic</a> team</p>
</div>