Questions

Pain001 FAQs for Treasury, Ops, Engineering and Audit

Straight answers for treasurers, payment operations, engineers, and auditors, phrased the way people actually ask.

Straight answers for treasurers, payment operations, engineers, and auditors. Questions are phrased the way people actually ask them. For deeper technical detail, see the Technical Reference.


For treasury and finance leaders#

pain.001 is the ISO 20022 message a customer sends to its bank to initiate credit transfers. It is the XML successor to formats like SWIFT MT101 and domestic flat files. Your bank validates it against a schema and a scheme rulebook before accepting it. Pain001 (the software) produces those files from the data you already have and proves they are valid before you submit them.

Direction of the pull. pain.001 initiates credit transfers: you push money out. pain.008 initiates direct debits: you collect money owed to you under a mandate. Pain001 generates both: ten versions of pain.001 (.001.03 through .001.12) and pain.008.001.02.

Urgent. SWIFT retired MT category 1, 2 and 9 messages for cross-border interbank payment instructions in November 2025; corporate channels that still accept MT do so at each bank's discretion and on borrowed time. The MT101 loader converts existing MT101 flows to validated pain.001 without re-keying anything.

Swift planned to stop accepting fully unstructured postal addresses in CBPR+ cross-border payments in November 2026. In August 2026 it deferred that date and will announce the new one by December 2026, but the rule is unchanged: addresses must be structured or hybrid, using discrete elements such as town (<TwnNm>) and country (<Ctry>) instead of free-text lines. If your master data holds addresses as blobs, the work is in your data, not your bank connection. Start there. The 2026 briefing covers the timeline in detail.

Nothing. The core is dual-licensed Apache-2.0 / MIT; companion packages are Apache-2.0. Commercial use, modification, and redistribution are all permitted. For scale reference, SWIFT's translation SDK alone lists at €10,000–30,000 per year.


For payment operations#

Four recurring causes: schema violations (wrong element, wrong version, wrong namespace), bad identifiers (IBAN checksum failures, malformed BICs), broken control totals (NbOfTxs / CtrlSum not matching the transactions), and characters outside the ISO 20022 Latin set. Pain001 checks all four before a file exists: JSON Schema validation per record, mod-97 IBAN and ISO 9362 BIC checks, recomputed control totals, charset transliteration, and final XSD validation of the rendered XML.

Yes. Use pain001 --dry-run (or the validate subcommand, or POST /api/v1/validate). Exit code 0 means valid; 1 means validation failed with field-level errors. Wire it into CI or a pre-submission checklist.

Five scheme rulebooks ship built-in: SEPA Credit Transfer (sepa-sct), SEPA Instant (sepa-inst), SEPA Direct Debit Core (sepa-sdd), SEPA B2B (sepa-b2b), and cross-border credit transfer (xborder-ct). Use --scheme <name> --explain to see every rule that passed or failed.

Excel silently coerces IBAN-like strings into numbers. The Excel loader reads .xlsx/.xlsm directly and hard-stops if IBAN columns contain numeric cells, so the corruption is caught at load, not at the bank.

--streaming processes input in memory-bounded chunks (default 1,000 transactions), each emitted as its own XML file with correct recomputed control totals. The REST API offers POST /api/v1/generate/async with job polling for the same reason.


For engineers and architects#

All three exist as first-class surfaces: a typed Python API, a CLI with CI-friendly exit codes, and a FastAPI microservice (pain001 serve) with sync, async-job, health, and Prometheus metrics endpoints. Same validation pipeline underneath, so results never diverge between surfaces.

Amounts are decimal.Decimal end-to-end in generation and scheme validation. They are parsed as exact decimals, summed as exact decimals, and rendered without float representation. Control totals are recomputed from validated records, never trusted from input.

All XML parsing routes through defusedxml (blocking XXE and entity-expansion attacks); there is no lxml in the dependency tree. Inputs pass a path-traversal validator. The Docker image runs non-root. A CycloneDX SBOM is generated for core releases, and third-party plugin discovery can be disabled outright with PAIN001_DISABLE_PLUGINS=1.

100% line and branch coverage as a hard CI gate on the core (verifiably: 3,828 lines, 926 branches at 100%), strict mypy, 100% docstring coverage, Bandit and pip-audit security linting, and CodeQL scanning. The companion packages carry the same 100% coverage discipline.

Yes, through four plugin entry-point groups (pain001.loaders, pain001.validators, pain001.schemes, pain001.writers). The Excel loader is itself a plugin using the public protocol, so it doubles as a reference implementation.


For auditors and compliance#

Yes. Pin the package version, replay the same input, and the output is deterministic. Because the toolchain is open source, the audit trail extends into the code path itself, not just a vendor attestation.

No. Every component (CLI, library, REST API, MCP server, LSP) executes locally. There is no telemetry, no SaaS callback, no external validation service. The MCP server speaks stdio only and all 17 of its tools are annotated read-only and idempotent.

Sebastien Rousseau, a London-based fintech engineering leader, with community contributors. Development is public on GitHub, releases are published to PyPI, and the changelog is versioned with every release.