Skip to main content

pain001-loader-mt101 logo

pain001-loader-mt101

Turns SWIFT MT101 requests for transfer into the flat records pain001 validates and writes as ISO 20022 pain.001.

Build Registry Docs OpenSSF Scorecard License: Apache-2.0 OR MIT Python 3.10 or newer

pain001-loader-mt101 demo: the MT101 text in examples/01_minimal_parse.py, the pain.001 records it prints with party data redacted, then a :30: date of 30 February rejected with a ValueError


Contents

Getting started

  • Install — pip, one runtime dependency
  • Requirements — toolchain floor, platforms
  • Quick Start — one call from MT101 text to schema-valid pain.001 records

The pain001-loader-mt101 ecosystem

Library reference

Operational


Install

As a Python library

pip install pain001-loader-mt101

Latest release: v0.0.74: impossible :30: dates and :32B: amounts outside the SWIFT form are rejected, released in lockstep with the pain001 suite, for Python 3.10+.

The package pulls in pain001 (0.0.74 or newer, below 1) and nothing else. There is no command-line entry point: it is a library.


Requirements

  • Python 3.10 or newer, tested in CI on 3.10, 3.11, 3.12, 3.13 and 3.14 on Linux (toolchain policy).
  • pain001 0.0.74 or newer on the 0.x line.
  • Pure Python, so any platform CPython runs on; CI exercises Linux only.

Quick Start

from pain001.validation.schema_validator import SchemaValidator
from pain001_loader_mt101 import parse_mt101

mt101 = """:20:MSGREF2026070901
:30:260712
:50H:/DE89370400440532013000
GLOBAL IMPORTS GMBH
:52A:DEUTDEFF
:21:TXN-REF-0001
:32B:EUR12345,67
:57A:CHASUS33
:59:/GB29NWBK60161331926819
ACME TRADING LTD
:70:INVOICE 998877
:71A:SHA
"""

records = parse_mt101(mt101)
print(len(records))                  # 1
print(records[0]["payment_amount"])  # 12345.67
print(records[0]["charge_bearer"])   # SHAR

total, valid, errors = SchemaValidator("pain.001.001.09").validate_batch(records)
assert valid == total and not errors

parse_mt101 returns one record per sequence-B transaction, with the keys pain001 validates against the pain.001.001.09 schema, so the records go straight into pain.001 generation.


The pain001-loader-mt101 ecosystem

This package is one of the pain001 suite. The core, its MCP and LSP servers and its two loaders release together at one version, core first. New to the target format? What is pain.001? explains it, and https://pain001.com/mt101-migration/ sets out the MT101 migration case.

Component Purpose Use case
pain001 Generates and validates ISO 20022 payment files from tabular data The core library these records feed
pain001-loader-mt101 SWIFT MT101 text to pain.001 flat records A treasury or ERP system still emits MT101
pain001-loader-xlsx Excel loader plugin for .xlsx / .xlsm Payment batches kept in spreadsheets
pain001-mcp MCP server exposing pain001 validation, generation and inspection Agent workflows over payment files
pain001-lsp Language server for pain001 input files Editor support

Capabilities at a glance

Area Capability Status
Parsing Sequence A (:20:, :30:, :50a:, :52a:) and repeating sequence B (:21:, :32B:, :50a:, :52a:, :57a:, :59a:, :70:, :71A:) Supported
Envelope A raw {4:...-} block 4, CRLF or LF Supported
Output One pain.001 record per transaction; nb_of_txs and ctrl_sum on each Supported
Validation Missing :20:, :30:, :21:, :32B: or named beneficiary Rejected with ValueError
Validation :30: dates that do not exist, :32B: amounts outside the SWIFT form Rejected since 0.0.74
FX legs :33B:, :36:, :21F: Not mapped
Header blocks SWIFT blocks 1 and 2 Not read

Ecosystem comparison

pain001 takes rows (CSV, SQLite, JSON, JSONL, Python records) and pain001-loader-xlsx takes spreadsheets. This package is the path for MT101 text. A search of likely names on PyPI found no other MT101 parser; the nearest is mt103, which reads MT103 only.

Project Input Records per input Licence
pain001-loader-mt101 MT101 text One per transaction Apache-2.0 OR MIT
pain001-loader-xlsx .xlsx / .xlsm One per row Apache-2.0 OR MIT
mt103 1.1.1 MT103 text One message GPL-3.0-or-later

See docs/COMPARISON.md for the evidence and complete matrix.


Benchmarks

benches/bench_parse_mt101.py grows one message from 10 to 5,000 transactions and reports microseconds per transaction and a growth exponent. The number to read is the shape: per-transaction cost should stay flat. Nothing asserts a time; tests/test_benchmarks.py asserts the scaling ratio, and CI runs the benchmark with --quick.

Scenario Result Environment
One MT101, 1,000 transactions (145 KB) 14.61 ms, 14.61 µs/txn Apple A18 Pro, CPython 3.12.15, shared machine under load
One MT101, 5,000 transactions (725 KB) 89.34 ms, 17.87 µs/txn same run
Growth exponent, 10 to 5,000 transactions 1.06 (linear) same run

See docs/BENCHMARKS.md for methodology and full results.


Features

  • One function. parse_mt101(text) returns list[dict], one record per sequence-B transaction. Sequence-A :50a: and :52a: apply to every transaction unless a sequence-B block overrides them.

  • Field mapping.

    MT101 field Seq Meaning pain.001 key
    :20: A Sender's reference id, payment_information_id
    :30: A Requested execution date (YYMMDD) requested_execution_date, date
    :21: B Transaction reference payment_id
    :32B: B Currency and amount currency, payment_amount
    :50H/G/F/K/A: A/B Ordering customer debtor_name, debtor_account_IBAN, initiator_name
    :52A/C/D: A/B Account servicing institution debtor_agent_BIC
    :57A/C/D: B Account with institution creditor_agent_BIC
    :59/59A/59F: B Beneficiary creditor_name, creditor_account_IBAN
    :70: B Remittance information remittance_information (140 characters at most)
    :71A: B Details of charges charge_bearer (OUR to DEBT, BEN to CRED, SHA to SHAR)
  • Synthesised fields, documented so callers can override them: payment_method="TRF", batch_booking=False, service_level_code="SEPA", charge_bearer="SLEV" when :71A: is absent or unknown, remittance_information="NOTPROVIDED" when :70: is absent; date reuses :30: and initiator_name the ordering customer's name.

  • Absent optional fields are omitted, not guessed.

  • Errors name the field. Every ValueError names the MT101 field that is missing or malformed.


Configuration

None. parse_mt101 takes the text and nothing else; the synthesised defaults above are fixed, and callers override them on the returned records.


Examples

Both run in CI on every pull request.


When not to use pain001-loader-mt101

  • Your batch is already rows or a spreadsheet. Use the pain001 core loaders or pain001-loader-xlsx.
  • You have MT103. That is a single transfer going to pacs.008; see pacs008-loader-mt103.
  • You need FX legs, regulatory reporting or authorisation fields (:33B:, :36:, :21F:, :77B:, :25:, :28D:, :23E:): they are not mapped.
  • You need the SWIFT header blocks. Only block 4 is read.
  • Your payments are not SEPA. service_level_code defaults to SEPA; set URNS on the records yourself.
  • Your MT101 arrives PGP-encrypted. Decrypt it first; the loader takes plaintext.

Development

git clone https://github.com/sebastienrousseau/pain001-loader-mt101
cd pain001-loader-mt101
make install   # .venv from the hash-pinned requirements/test.txt and lint.txt
make check

make check runs ruff, mypy in strict mode, the complexity ceilings, the version-agreement check, pytest with a 100% line and branch coverage gate (Hypothesis fuzzing included), interrogate at 100% docstring coverage and the examples. CI also runs the dependency audit (pip-audit over every requirements/*.txt), Atheris fuzzing of parse_mt101 (two minutes per change, thirty weekly, seeded from fuzz/corpus/), mutation testing of the parser, CodeQL, OpenSSF Scorecard, the DCO check and a daily Suite Consistency check against PyPI. See CONTRIBUTING.md.


Security

The loader parses text: it reads no files, opens no sockets and parses no XML. Input outside the grammar (including dates that do not exist and amounts outside the SWIFT form) is rejected with a ValueError naming the field. Cap the size of untrusted input before parsing it. The parser is fuzzed with Atheris in CI and with Hypothesis in the test suite. Releases are published from a signed tag through PyPI Trusted Publishing, with SLSA build provenance, sigstore signatures and SPDX and CycloneDX SBOMs.

Report vulnerabilities according to SECURITY.md.


Documentation

User manual · API reference · Developer guide · Family map · Changelog · Policies · Architecture · Decisions


Stability guarantees

The project is pre-1.0 and versions advance in 0.0.1 steps, in lockstep with the pain001 suite. The breaking axis is parse_mt101's signature and the records it produces for a given input: a change to that output is breaking even when no signature moves, and the changelog calls it out (0.0.74 rejecting impossible :30: dates and :32B: amounts with a dot). The Python floor moves only as described in the toolchain policy.


License

This project is dual-licensed under either:

at your option. Dependencies keep their own licences.

Metadata

Release files for pain001-loader-mt101 0.0.74

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pain001-loader-mt101 0.0.74
File Size Uploaded Provenance
pain001_loader_mt101-0.0.74.tar.gz 639.7 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for pain001-loader-mt101 0.0.74
File Interpreter ABI Platform
pain001_loader_mt101-0.0.74-py3-none-any.whl Python 3 none any Details

Total release size: 659.6 kB

Release files / pain001_loader_mt101-0.0.74.tar.gz

Download URL pain001_loader_mt101-0.0.74.tar.gz
Size 639.7 kB
Tags Source
SHA-256 checksum
How to use checksums
123b36fadbdd5637b9609bc1cec4f033aa39e2209caf5634e10596c2f570a8e4
BLAKE2b-256 checksum
How to use checksums
bdb13cc57d11608dc26e3047c0aff973a76a0c6efb70b0fa587c3c7c806a7107
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Release files / pain001_loader_mt101-0.0.74-py3-none-any.whl

Download URL pain001_loader_mt101-0.0.74-py3-none-any.whl
Size 19.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9c62e5036ff3acc7601751a2ec94ac09d19a794d029b4c4014864e16cc854f53
BLAKE2b-256 checksum
How to use checksums
7cdc01ae0c31e9137df98778835de538f1b1055a8dad27034985ff83d6ea642e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Security for pain001-loader-mt101 0.0.74

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for pain001_loader_mt101-0.0.74.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page