Skip to main content

ISO-8583

Pure Python ISO-8583 message packing and unpacking. No dependencies.

No dependencies Python Lint Ruff Tests codecov License

Features

  • Pure Python, zero runtime dependencies
  • Pack and unpack ISO-8583 messages
  • Fixed and variable-length fields (LLVAR, LLLVAR)
  • Many field formats: ASCII, BCD, and raw binary
  • Nested subfields, including ASCII TLV and repeatable subfields
  • Partial unpacking that stops at the first error
  • Bring-your-own MTI and LengthType enums

Table of contents

Quick start

from iso_8583.fixed_formats import FieldFormat
from iso_8583.extendable_formats import MTI, LengthType
from iso_8583 import FieldSpec, Message
 
spec = {
    2: FieldSpec(LengthType.LLVAR, FieldFormat.N, 19),
    3: FieldSpec(LengthType.FIXED, FieldFormat.N, 6),
    4: FieldSpec(LengthType.FIXED, FieldFormat.N, 12),
    41: FieldSpec(LengthType.FIXED, FieldFormat.ANSP, 8),
}
 
msg = Message(spec, MTI.AUTHORISATION_REQUEST)
msg[2] = "4242424242424242"
msg[3] = "000000"
msg[4] = "000000001000"
msg[41] = "TERM0001"
 
raw = msg.pack()
msg2 = Message.unpack(spec, raw)
 
print(msg2[2])   # 4242424242424242
print(msg2[41])  # TERM0001

Field formats

Format Characters Wire
A Letters ASCII
B / ANSB Any bytes Raw
N Digits BCD
P Space ASCII
S Punctuation ASCII
Z Digits + D, F BCD
AN Letters + digits ASCII
ANP Letters + digits + space ASCII
ANS Letters + digits + punctuation ASCII
ANSP Letters + digits + punctuation + space ASCII

Length types

Type Prefix Max
FIXED 0 bytes
LLVAR 1 byte 99
LLLVAR 2 bytes 1000

Subfields

from iso_8583.fixed_formats import FieldFormat
from iso_8583.extendable_formats import MTI, LengthType
from iso_8583 import FieldSpec, SubFieldSpec, Message
 
spec = {
    119: FieldSpec(
        LengthType.LLLVAR, FieldFormat.B, 255,
        subfields={
            "0001": SubFieldSpec(LengthType.FIXED, FieldFormat.AN, 1),
            "0009": SubFieldSpec(LengthType.LLVAR, FieldFormat.ANSP, 8),
            "0011": SubFieldSpec(LengthType.LLVAR, FieldFormat.N, 19),
        },
    ),
}
 
msg = Message(spec, MTI.AUTHORISATION_REQUEST)
msg[119] = {"0001": "A", "0009": "HELLO", "0011": "1234567890"}
 
raw = msg.pack()
msg2 = Message.unpack(spec, raw)
print(msg2[119])
# {'0001': 'A', '0009': 'HELLO', '0011': '1234567890'}

For ASCII TLV subfields (tag 2 chars + length 2 chars + value), use TlvFieldSpec:

from iso_8583.fixed_formats import FieldFormat
from iso_8583.extendable_formats import MTI, LengthType
from iso_8583 import TlvFieldSpec, SubFieldSpec, Message
 
spec = {
    47: TlvFieldSpec(
        LengthType.LLVAR, FieldFormat.ANSP, 99,
        subfields={
            "T1": SubFieldSpec(LengthType.LLVAR, FieldFormat.ANSP, 10),
            "T2": SubFieldSpec(LengthType.LLVAR, FieldFormat.N, 8),
        },
    ),
}
 
msg = Message(spec, MTI.AUTHORISATION_REQUEST)
msg[47] = {"T1": "HELLO", "T2": "12345678"}
 
raw = msg.pack()
msg2 = Message.unpack(spec, raw)
print(msg2[47])
# {'T1': 'HELLO', 'T2': '12345678'}

Repeatable subfields accept a list:

from iso_8583.fixed_formats import FieldFormat
from iso_8583.extendable_formats import MTI, LengthType
from iso_8583 import FieldSpec, SubFieldSpec, Message
 
spec = {
    56: FieldSpec(
        LengthType.LLVAR, FieldFormat.B, 99,
        subfields={
            "0001": SubFieldSpec(LengthType.FIXED, FieldFormat.N, 4),
            "0023": SubFieldSpec(
                LengthType.FIXED, FieldFormat.ANSP, 8,
                repeatable=True,
            ),
        },
    ),
}
 
msg = Message(spec, MTI.AUTHORISATION_REQUEST)
msg[56] = {"0001": "1234", "0023": ["ENTRY-01", "ENTRY-02"]}
 
raw = msg.pack()
msg2 = Message.unpack(spec, raw)
print(msg2[56]["0023"])
# ['ENTRY-01', 'ENTRY-02']

Partial unpack

Stops at the first error and returns what was read:

from iso_8583.fixed_formats import FieldFormat
from iso_8583.extendable_formats import MTI, LengthType
from iso_8583 import FieldSpec, Message
 
full_spec = {
    2: FieldSpec(LengthType.LLVAR, FieldFormat.N, 19),
    3: FieldSpec(LengthType.FIXED, FieldFormat.N, 6),
}
partial_spec = {
    2: FieldSpec(LengthType.LLVAR, FieldFormat.N, 19),
}
 
msg = Message(full_spec, MTI.AUTHORISATION_REQUEST)
msg[2] = "4242424242424242"
msg[3] = "000000"
raw = msg.pack()
 
result, error = Message.unpack_partial(partial_spec, raw)
print(result[2])  # 4242424242424242
print(error)      # bit 3: present in bitmap but not in spec

Custom MTI

Pass mti_class to unpack to get the MTI back as your own enum:

from enum import Enum
from iso_8583.fixed_formats import FieldFormat
from iso_8583.extendable_formats import LengthType
from iso_8583 import FieldSpec, Message
 
class MyMTI(int, Enum):
    SALE = 0x0200
    SALE_RESPONSE = 0x0210
    REVERSAL = 0x0400
 
spec = {2: FieldSpec(LengthType.LLVAR, FieldFormat.N, 19)}
 
msg = Message(spec, MyMTI.SALE)
msg[2] = "4242424242424242"
 
raw = msg.pack()
msg2 = Message.unpack(spec, raw, mti_class=MyMTI)
print(msg2._mti)  # MyMTI.SALE

Custom LengthType

from enum import Enum
from iso_8583.fixed_formats import FieldFormat
from iso_8583 import FieldSpec, Message
 
class MyLengthType(Enum):
    FIXED = (0, None)
    LLVAR = (1, 99)
    LLLVAR = (1, 255)
    LL2VAR = (2, 999)
 
    def __init__(self, prefix_bytes, max_field_length):
        self.prefix_bytes = prefix_bytes
        self.max_field_length = max_field_length
 
class MyMTI(int, Enum):
    AUTH = 0x0100
 
spec = {
    2: FieldSpec(MyLengthType.LLVAR, FieldFormat.N, 19),
    60: FieldSpec(MyLengthType.LL2VAR, FieldFormat.ANSP, 999),
}
 
msg = Message(spec, MyMTI.AUTH)
msg[2] = "4242424242424242"
msg[60] = "HELLO WORLD"
 
raw = msg.pack()
msg2 = Message.unpack(spec, raw)
print(msg2[2])   # 4242424242424242
print(msg2[60])  # HELLO WORLD

License

See LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

iso_8583_toolbox-0.1.0.tar.gz (45.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

iso_8583_toolbox-0.1.0-py3-none-any.whl (10.5 kB view details)

Uploaded Python 3

File details

Details for the file iso_8583_toolbox-0.1.0.tar.gz.

File metadata

  • Download URL: iso_8583_toolbox-0.1.0.tar.gz
  • Upload date:
  • Size: 45.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for iso_8583_toolbox-0.1.0.tar.gz
Algorithm Hash digest
SHA256 895a7fc14bcba0efdd61653dcb5bfae54d91ad391b816a34e61ca7f3fea02cba
MD5 2cbe4efca32fa74ce17db90cd235c099
BLAKE2b-256 1f7f97ed00420bfea4cbfcddfa49e19976fb0d29a738ca3f1848ea79eea6d596

See more details on using hashes here.

Provenance

The following attestation bundles were made for iso_8583_toolbox-0.1.0.tar.gz:

Publisher: publish.yml on Bastien-BO/iso-8583

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file iso_8583_toolbox-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for iso_8583_toolbox-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a79500db66036da6aad8b2db406d4cf4922205242ac10abb18ca0e742219b37d
MD5 7d34243b6863c7681447e4454581dc35
BLAKE2b-256 0ec9861f1679ec30cbd13262773f0d59cb1a720f73edada4a7b8771c86db8d65

See more details on using hashes here.

Provenance

The following attestation bundles were made for iso_8583_toolbox-0.1.0-py3-none-any.whl:

Publisher: publish.yml on Bastien-BO/iso-8583

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page