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#
What is pain.001, in one paragraph?
pain.001 is the ISO 20022 message a customer sends to its bank to initiate credit transfers — 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.
What is the difference between pain.001 and pain.008?
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.
We still send MT101 files. How urgent is migration?
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.
What does the November 2026 structured address deadline mean for us?
From the end of November 2026, fully unstructured postal addresses are no longer accepted in CBPR+ cross-border payments; addresses must be structured or hybrid — discrete elements such as town () and country () 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.
What does Pain001 cost?
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#
Why do banks reject payment files?
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.
Can we validate a file without generating anything?
Yes — 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.
Which SEPA rulebooks are covered?
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 to see every rule that passed or failed.
Our data lives in Excel. What is the catch?
Excel silently coerces IBAN-like strings into numbers. The Excel loader reads .xlsx/.xlsm directly and hard-stops if IBAN columns contain numeric cells — the corruption is caught at load, not at the bank.
How does it handle a 500,000-row batch?
--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#
How do we integrate it — library, CLI, or API?
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.
Is the XML generation actually safe against float rounding?
Amounts are decimal.Decimal end-to-end in generation and scheme validation — parsed as exact decimals, summed as exact decimals, rendered without float representation. Control totals are recomputed from validated records, never trusted from input.
What is the security posture?
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.
How is quality enforced?
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.
Can we extend it for a proprietary format?
Yes — 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#
Can we reproduce a file that was generated last quarter?
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.
Does payment data leave our environment?
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.
Who maintains Pain001?
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.