Skip to main content

Convert legacy SWIFT MT101 requests for transfer to ISO 20022 pain.001 flat records.

Project description

pain001-loader-mt101: MT101 → pain.001 loader

Convert legacy SWIFT MT101 requests for transfer into the flat records that the pain001 library validates and turns into ISO 20022 pain.001 XML. A single parse_mt101(text) call returns a list[dict] — one record per transaction — ready to feed straight into pain.001 generation.

Latest release: v0.0.2. The second deliverable of the MT→MX converter project (after pacs008-loader-mt103). SWIFT MT-MX coexistence ends in November 2025; this loader bridges the window where upstream systems still emit MT101 but downstream tooling expects pain.001.

Contents

Overview

pain001-loader-mt101 is a small, focused companion to the pain001 ISO 20022 Customer Credit Transfer Initiation library. It does one thing well: parse the mandatory + common-denominator MT101 grammar and hand back flat records whose keys are exactly the ones pain001 validates against the pain.001.001.09 JSON schema. Unlike an MT103 (one transfer), an MT101 can carry many transactions (repeating sequence B), so parse_mt101 returns one record per transaction. The correctness proof is that a realistic multi-transaction MT101 maps to records that pass SchemaValidator("pain.001.001.09").validate_batch(...) with zero errors.

Install

pain001-loader-mt101 requires Python 3.10+ and pulls in pain001 automatically.

pip install pain001-loader-mt101

Quick Start

from pain001_loader_mt101 import parse_mt101

mt101 = """:20:MSGREF2026070901
:21R:CUSTREF-A
:50H:/DE89370400440532013000
GLOBAL IMPORTS GMBH
100 HAFEN STRASSE
HAMBURG
:52A:DEUTDEFF
:30:260712
:21:TXN-REF-0001
:32B:EUR12345,67
:57A:CHASUS33
:59:/GB29NWBK60161331926819
ACME TRADING LTD
1 CORPORATE AVENUE
LONDON
:70:INVOICE 998877
:71A:SHA
:21:TXN-REF-0002
:32B:USD5000,00
:57A:BOFAUS3N
:59:/FR1420041010050500013M02606
LES FLEURS SARL
:70:CONTRACT 445566
:71A:OUR
"""

records = parse_mt101(mt101)
print(len(records))                       # 2
print(records[0]["payment_amount"])       # 12345.67
print(records[0]["charge_bearer"])        # SHAR
print(records[0]["nb_of_txs"])            # 2 (message-level)

# Validate against the real pain.001 schema:
from pain001.validation.schema_validator import SchemaValidator
total, valid, errors = SchemaValidator("pain.001.001.09").validate_batch(records)
assert valid == total and not errors

Field Mapping

parse_mt101(text: str) -> list[dict] — one record per sequence-B transaction. Sequence-A :50a: / :52a: apply to every transaction unless a sequence-B block overrides them.

MT101 field Seq Meaning pain.001 key Notes
:20: A Sender's Reference id, payment_information_id Message-level
:30: A Requested Execution Date (YYMMDD) requested_execution_date, date → YYYY-MM-DD; SWIFT sliding year window
:21: B Transaction Reference payment_id One per transaction
:32B: B Currency + Amount currency, payment_amount No value date; comma-decimal → float
:50H/50G/50F/50K/50A: A/B Ordering Customer debtor_name, debtor_account_IBAN, initiator_name Name from F (1/), K/H (name lines) or A (BIC); account from /IBAN line
:52A/52C/52D: A/B Account Servicing Institution debtor_agent_BIC BIC from A/C (or a BIC in D)
:57A/57C/57D: B Account With Institution creditor_agent_BIC BIC from A/C (or a BIC in D)
:59/59A/59F: B Beneficiary creditor_name, creditor_account_IBAN Name from plain 59, A (BIC) or F (1/)
:70: B Remittance Information remittance_information Whitespace-collapsed, capped at 140 chars
:71A: B Details of Charges charge_bearer OURDEBT, BENCRED, SHASHAR
(synthesised) nb_of_txs, ctrl_sum Count of, and total amount over, sequence-B blocks
(synthesised) payment_method, batch_booking, service_level_code TRF, False, SEPA

Assumptions and defaults

The pain.001 schema requires fields MT101 does not carry; these are synthesised (override downstream as needed):

  • payment_method = "TRF" — an MT101 requests credit transfers.
  • batch_booking = False.
  • service_level_code = "SEPA" — the schema enum admits only SEPA / URNS; override for non-SEPA payments.
  • charge_bearer = "SLEV" when :71A: is absent or unrecognised — the schema requires a charge bearer.
  • remittance_information = "NOTPROVIDED" when :70: is absent — the schema requires a non-empty value.
  • nb_of_txs / ctrl_sum describe the whole message (count of and total over sequence-B blocks) and are repeated on every record, as in a pain.001 group header.
  • date (message creation date) reuses :30: — MT101 has no separate creation timestamp. Two-digit years follow the SWIFT sliding window (00–79 → 20YY, 80–99 → 19YY).
  • initiator_name reuses the ordering-customer name.
  • Absent optional fields are omitted, not guessed. A schema-valid pain.001 record needs the ordering-customer name + IBAN (:50a:), the account-servicing and account-with BICs (:52a: / :57a:) and the beneficiary IBAN (:59a:); a well-formed MT101 carries all of these.
  • Hard requirements — only :20:, :30:, at least one transaction, and per transaction :21:, :32B: and a named beneficiary (:59:/:59A:/:59F:) raise ValueError. Everything else is best-effort; the loader never crashes on unexpected input.

Out of scope

This is the correct core MT101 → pain.001 mapping, not every optional field. Deliberately excluded in v0.0.2:

  • :23E: instruction codes, :25: / :28D: authorisation / sequence fields.
  • :33B: instructed currency/amount, :36: exchange rate, :21F: FX deal reference (FX legs).
  • :56a: intermediary and :51A: sending institutions.
  • :77B: regulatory reporting and :25A: charges account.
  • The SWIFT application header (blocks 1/2). This loader reads block 4 only (it unwraps a {4:...-} envelope if present).

Examples

Two runnable scripts live in examples/, exercised in CI:

Development

git clone https://github.com/sebastienrousseau/pain001-loader-mt101
cd pain001-loader-mt101
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
pytest                            # 100% line + branch coverage gate
interrogate pain001_loader_mt101  # 100% docstring gate
mypy pain001_loader_mt101         # strict

Security

pain001-loader-mt101 parses a flat text format with no XML envelope — the XXE / billion-laughs surface lives upstream. Field regexes are anchored and bounded, so catastrophic backtracking is not a concern. See SECURITY.md.

License

Licensed under the Apache License, Version 2.0. Any contribution submitted for inclusion shall be licensed as above, without additional terms.

Project details


Download files

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

Source Distribution

pain001_loader_mt101-0.0.2.tar.gz (24.1 kB view details)

Uploaded Source

Built Distribution

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

pain001_loader_mt101-0.0.2-py3-none-any.whl (16.3 kB view details)

Uploaded Python 3

File details

Details for the file pain001_loader_mt101-0.0.2.tar.gz.

File metadata

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

File hashes

Hashes for pain001_loader_mt101-0.0.2.tar.gz
Algorithm Hash digest
SHA256 b3687a2b54761e0f627dff4fb219cd66d3bcc41451df3e3c5876e01f7f63c2b0
MD5 3970b137b5b1a406aba1c7eefcf99eb6
BLAKE2b-256 43a71597925bdfc047d956a1656ed1e7752a8bc608bfa21c2d3e11b9a2636d19

See more details on using hashes here.

Provenance

The following attestation bundles were made for pain001_loader_mt101-0.0.2.tar.gz:

Publisher: release.yml on sebastienrousseau/pain001-loader-mt101

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

File details

Details for the file pain001_loader_mt101-0.0.2-py3-none-any.whl.

File metadata

File hashes

Hashes for pain001_loader_mt101-0.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 0cda58030cac253e0e202534cc5d6543c625e98525c6d3cf083b45ee49fbd8b7
MD5 ae78e201314004cd6cdb023601070ccb
BLAKE2b-256 00ebe1ea8f8be7b4c5741da51f00d9232b64dbab4c028357fb7d9766775d8c7c

See more details on using hashes here.

Provenance

The following attestation bundles were made for pain001_loader_mt101-0.0.2-py3-none-any.whl:

Publisher: release.yml on sebastienrousseau/pain001-loader-mt101

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

Supported by

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