How-To

Note

The examples on this page use pprint.pp() which is available starting from Python 3.8. Alternativelly, it’s also possible to achive the same result using pprint.pprint() with sort_dicts=False starting from Python 3.7. Earlier versions of Python 3 can use pprint.pprint() but it will sort the keys.

Create Own/Proprietary Specifications

iso8583 comes with specification sample in iso8583.specs.py. Feel free to copy sample specification dict and modify it to your needs. Refer to iso8583.specs for configuration details.

Create ISO8583 Message

iso8583 converts a Python dict into a bytearray. A dict must consits of str keys and str values.

A the minimum it must have key 't' which contains message type, e.g. '0200'.

>>> import pprint
>>> import iso8583
>>> from iso8583.specs import default_ascii as spec
>>> decoded = {'t': '0200'}
>>> encoded_raw, encoded = iso8583.encode(decoded, spec)
>>> encoded_raw
bytearray(b'02000000000000000000')
>>> pprint.pp(encoded)
{'t': {'len': b'', 'data': b'0200'},
 'p': {'len': b'', 'data': b'0000000000000000'}}
>>> pprint.pp(decoded)
{'t': '0200', 'p': '0000000000000000'}

Note that primary bitmap was generated automatically.

An ISO8583 message without any fields is not very useful. To add another field to the message simply add '2'-'128' keys with str data.

>>> decoded['2'] = 'cardholder PAN'
>>> decoded['3'] = '111111'
>>> decoded['21'] = '021'
>>> encoded_raw, encoded = iso8583.encode(decoded, spec)
>>> encoded_raw
bytearray(b'0200600008000000000014cardholder PAN111111021')
>>> pprint.pp(encoded)
{'t': {'len': b'', 'data': b'0200'},
 'p': {'len': b'', 'data': b'6000080000000000'},
 '2': {'len': b'14', 'data': b'cardholder PAN'},
 '3': {'len': b'', 'data': b'111111'},
 '21': {'len': b'', 'data': b'021'}}
>>> pprint.pp(decoded)
{'t': '0200',
 'p': '6000080000000000',
 '2': 'cardholder PAN',
 '3': '111111',
 '21': '021'}

Let’s remove some fields.

>>> decoded.pop('2', None)
'cardholder PAN'
>>> decoded.pop('3', None)
'111111'
>>> encoded_raw, encoded = iso8583.encode(decoded, spec)
>>> encoded_raw
bytearray(b'02000000080000000000021')
>>> pprint.pp(encoded)
{'t': {'len': b'', 'data': b'0200'},
 'p': {'len': b'', 'data': b'0000080000000000'},
 '21': {'len': b'', 'data': b'021'}}
>>> pprint.pp(decoded)
{'t': '0200', 'p': '0000080000000000', '21': '021'}

Add Secondary Bitmap

There is no need to explicitly add or remove secondary bitmap. It’s auto generated when at least one '65'-'128' fields is present.

>>> import pprint
>>> import iso8583
>>> from iso8583.specs import default_ascii as spec
>>> decoded = {
...     't': '0200',
...     '102': '111111'}
>>> encoded_raw, encoded = iso8583.encode(decoded, spec)
>>> encoded_raw
bytearray(b'02008000000000000000000000000400000006111111')
>>> pprint.pp(encoded)
{'t': {'len': b'', 'data': b'0200'},
 'p': {'len': b'', 'data': b'8000000000000000'},
 '1': {'len': b'', 'data': b'0000000004000000'},
 '102': {'len': b'06', 'data': b'111111'}}
>>> pprint.pp(decoded)
{'t': '0200', '102': '111111', 'p': '8000000000000000', '1': '0000000004000000'}

Even if secondary (or primary) bitmap is specified it’s overwritten with correct value.

>>> decoded = {
...     't': '0200',
...     'p': 'spam',
...     '1': 'eggs',
...     '102': '111111'}
>>> encoded_raw, encoded = iso8583.encode(decoded, spec)
>>> encoded_raw
bytearray(b'02008000000000000000000000000400000006111111')
>>> pprint.pp(encoded)
{'t': {'len': b'', 'data': b'0200'},
 'p': {'len': b'', 'data': b'8000000000000000'},
 '1': {'len': b'', 'data': b'0000000004000000'},
 '102': {'len': b'06', 'data': b'111111'}}
>>> pprint.pp(decoded)
{'t': '0200', 'p': '8000000000000000', '102': '111111', '1': '0000000004000000'}

Secondary bitmap is removed if it’s not required.

>>> decoded = {
...     't': '0200',
...     'p': 'spam',
...     '1': 'eggs',
...     '21': '051'}
>>> encoded_raw, encoded = iso8583.encode(decoded, spec)
>>> encoded_raw
bytearray(b'02000000080000000000051')
>>> pprint.pp(encoded)
{'t': {'len': b'', 'data': b'0200'},
 'p': {'len': b'', 'data': b'0000080000000000'},
 '21': {'len': b'', 'data': b'051'}}
>>> pprint.pp(decoded)
{'t': '0200', 'p': '0000080000000000', '21': '051'}

Check for Mandatory Fields

Many ISO8583 implementations need to check if all mandatory fields are received. It’s easy to do this using all() (docs).

>>> import pprint
>>> import iso8583
>>> from iso8583.specs import default_ascii as spec
>>> encoded_raw = b'02008000000000000000000000000400000006111111'
>>> decoded, encoded = iso8583.decode(encoded_raw, spec)
>>> pprint.pp(decoded)
{'t': '0200', 'p': '8000000000000000', '1': '0000000004000000', '102': '111111'}
>>> fields = [k for k in decoded.keys() if k.isnumeric() and k != "1"]
>>> fields
['102']
>>> mandatory_fields = {'2', '102'}
>>> all(field in fields for field in mandatory_fields)
False
>>> mandatory_fields = {'102'}
>>> all(field in fields for field in mandatory_fields)
True

Convert to and from JSON

iso8583 output is JSON compatible.

>>> import json
>>> import pprint
>>> import iso8583
>>> from iso8583.specs import default_ascii as spec
>>> encoded_raw = b'0200600008000000000014cardholder PAN111111021'
>>> decoded, encoded = iso8583.decode(encoded_raw, spec)
>>> pprint.pp(decoded)
{'t': '0200',
 'p': '6000080000000000',
 '2': 'cardholder PAN',
 '3': '111111',
 '21': '021'}
>>> decoded_json = json.dumps(decoded)
>>> decoded_json
'{"t": "0200", "p": "6000080000000000", "2": "cardholder PAN", "3": "111111", "21": "021"}'

And back.

>>> encoded_raw, encoded = iso8583.encode(json.loads(decoded_json), spec)
>>> encoded_raw
bytearray(b'0200600008000000000014cardholder PAN111111021')

iso8583.specs specifications are also JSON compatible.

>>> import json
>>> import pprint
>>> import iso8583
>>> from iso8583.specs import default_ascii as spec
>>> spec_json = json.dumps(spec)
>>> decoded = {
...     't': '0200',
...     '2': 'PAN'}
>>> encoded_raw, encoded = iso8583.encode(decoded, json.loads(spec_json))
>>> encoded_raw
bytearray(b'0200400000000000000003PAN')
>>> pprint.pp(encoded)
{'t': {'len': b'', 'data': b'0200'},
 'p': {'len': b'', 'data': b'4000000000000000'},
 '2': {'len': b'03', 'data': b'PAN'}}
>>> pprint.pp(decoded)
{'t': '0200', '2': 'PAN', 'p': '4000000000000000'}