Skip to main content

Camt053 is a Python library for reading ISO 20022 camt Bank-to-Customer Statements (camt.053/052/054) and generating validated reversing entries by return reason code (e.g. AC04 Closed Account).

Project description

camt053: ISO 20022 Bank Statements and Reversing Entries

camt053 logo

PyPI Version Python Versions License Tests Quality OpenSSF Scorecard OpenSSF Best Practices Documentation

Read ISO 20022 camt Bank-to-Customer Cash Management messages, extract booked entries by return reason code (e.g. AC04 Closed Account), and generate validated reversing entries — the core of a modern, AI-assisted treasury stack with native MCP and LSP integrations.

Latest release: v0.0.5 — namespace-agnostic camt.052/053/054 parsing and one-shot reversing-entry generation, validated against the official ISO 20022 camt.053.001.14 schema, for Python 3.10+. See what's new →

Contents

Overview

camt053 reads ISO 20022 camt cash-management messages — the standardised bank-to-customer statements (camt.053), account reports (camt.052), and debit/credit notifications (camt.054) — into a typed model, lets you filter booked entries by ISO external return reason code, and generates a validated reversing entry for the matching transactions.

The headline capability is the one-shot reversing-entry workflow: read an incoming camt.053 statement, find the entries carrying a return reason code (e.g. AC04 Closed Account), and emit a validated reversing entry — answering the prompt-engineering dream:

"Read this incoming bank statement XML, parse out the transactions with error code AC04, and automatically generate the reversing entry."

A single shared facade (camt053.services) backs four developer surfaces — the Python API, the CLI, the REST API, and the companion MCP and LSP servers — so every interface behaves identically. This package is part of the camt053 suite (all Python 3.10+):

Package Role
camt053 Core library + Click CLI + FastAPI REST API (this package)
camt053-mcp Model Context Protocol server (for AI agents)
camt053-lsp Language Server Protocol server (for editors)
flowchart LR
    A["Inbound camt.05x XML"] -->|parse| B["camt053.services"]
    B -->|filter by reason code| C["AC04 entries"]
    C -->|reverse + validate| D["camt.053.001.14 reversing entry"]

Install

camt053 runs on macOS, Linux, and Windows and requires Python 3.10+ and pip.

python -m pip install camt053
Using an isolated virtual environment (recommended)
python -m venv venv
source venv/bin/activate        # macOS/Linux
venv\Scripts\activate           # Windows
python -m pip install -U camt053

Quick Start

from camt053 import services

# An incoming camt.053 statement (truncated for brevity — see examples/).
statement_xml = open("statement.xml", encoding="utf-8").read()

# Find the entries returned AC04 (Closed Account).
ac04 = services.filter_entries(statement_xml, "AC04")
print(f"{len(ac04)} AC04 entr{'y' if len(ac04) == 1 else 'ies'}")

# Generate the reversing entry: parse -> filter -> reverse, in one call.
reversal_xml = services.generate_reversal(statement_xml, reason_code="AC04")
print(reversal_xml)  # validated camt.053.001.14 document

Or from the command line:

# Generate a reversing entry for every AC04 entry on a statement
camt053 reverse -i statement.xml -r AC04 -o reversal.xml

# List the entries on a statement (filter by reason, status, date, or amount)
camt053 entries -i statement.xml -r AC04
camt053 entries -i statement.xml --status BOOK --from 2026-06-01 --min 1000

# Export the (filtered) entries as CSV or JSON, to stdout or a file
camt053 entries -i statement.xml --export csv -o entries.csv
camt053 entries -i statement.xml -r AC04 --export json

# Choose the output format: a Rich table (default) or structured JSON
camt053 entries -i statement.xml --format json
camt053 reverse -i statement.xml -r AC04 --format json   # JSON envelope

# Inspect the parsed statement as JSON, or validate an identifier
camt053 parse -i statement.xml
camt053 validate-id -k iban -v GB29NWBK60161331926819

# Validate an incoming statement against its official ISO camt XSD
camt053 validate -i statement.xml

parse, entries, reverse, and validate accept -i - to read from stdin, so they compose in a pipeline.

Features

  • Parse camt.053 / camt.052 / camt.054 into a typed, JSON-serialisable model. Parsing is namespace-agnostic, so every ISO version (.001.01 through .001.14) and real-world bank file is read.
  • Filter booked entries by ISO external return reason code (AC04, AC06, MD07, …), and by status, booking-date range, and amount range (all ANDed) via services.filter_entries(...) or the camt053 entries flags.
  • Return reason codes — a substantial slice of the ISO 20022 ExternalReturnReason1Code set (the common SEPA / CBPR+ return reasons), listed via camt053 reasons, with case-insensitive lookup through services.validate_reason_code(code) -> {"code", "name", "valid"}.
  • Reason-code action policy — classify a return reason into a handling action ("return", "retry", or "ignore") via services.classify_reason(code) -> {"code", "name", "action"}, with a sensible built-in default (account-level rejections return, transient conditions such as AM04 / AM05 retry, informational reasons ignore). The full mapping is services.reason_policy(); both accept an overrides mapping and a custom default. The camt053 reasons table shows the action column and camt053 classify -r AC04 classifies a single code.
  • Export the (filtered) entries to CSV or JSON (camt053 entries --export {csv,json} [-o file]); CSV columns are reference, amount, currency, credit_debit_indicator, status, booking_date, value_date, reason_code.
  • Structured outputcamt053 entries --format json emits the entries as a JSON array, and camt053 reverse --format json emits a {"message_type", "reason_code", "xml"} envelope instead of raw XML (--format table, the default, keeps the Rich table / raw XML).
  • Reverse — generate a camt.053.001.14 reversing entry from the matching entries (credit/debit indicator flipped, RvslInd set, return reason carried in RtrInf), in one call.
  • Validated output — generated reversals are checked against the official ISO 20022 camt.053.001.14 XSD bundled with the package.
  • SWIFT charset cleansing — opt-in cleansing of the name / narrative fields (Nm / AddtlInf / party / counterparty names) bound for SWIFT FIN / CBPR+ rails: characters outside the SWIFT X set are transliterated (ée, ßss, smart quotes / dashes folded) or stripped, and field maximum lengths are enforced. Enable it on the reversal path with services.generate_reversal(xml, cleanse=True) / services.generate(records, cleanse=True) (default off, so existing output is unchanged), or cleanse records directly with services.cleanse_records(records) -> {"changed", "fields": [report, ...]}, which returns an audit report of exactly what changed. Cleansed reversals still validate against the bundled XSD.
  • Validate incoming statementsservices.validate_statement(xml) (and the camt053 validate command) check an inbound camt.052 / camt.053 / camt.054 document against the matching official ISO 20022 XSD, detected from its namespace, returning {"valid", "message_type", "errors"}.
  • Re-serialise (round-trip) — render a parsed ParsedDocument / Statement back to a validated camt.053.001.14 document via services.serialize_statement(xml) (or camt053.serialize_document(doc) / camt053.serialize_statement(stmt)). The output is deterministic and round-trip stable: parse_document(serialize_statement(parse_document(xml))) preserves the account, balances, and entries (references, amounts, currencies, credit/debit indicators, and return reasons).
  • Safe by default — XML is parsed with defusedxml (XXE / billion-laughs safe); output paths are traversal-checked.
  • One facade, four interfaces — the CLI, REST API, MCP server, and LSP server all call camt053.services.
  • IBAN / BIC / LEI validators (ISO 13616 / 9362 / 17442).
  • Decimal amounts & ISO 4217 currenciesEntry.amount_decimal / Balance.amount_decimal parse the string amount into a Decimal (the string is kept verbatim for XML fidelity), and services.validate_currency(code) -> {"code", "valid", "minor_units"} checks a code against a bundled ISO 4217 set and reports its minor units (EUR=2, JPY=0, …).
  • Typed (mypy --strict) and tested (100% coverage), validated against the official ISO 20022 business samples.

Usage

from camt053 import parse_statement, services

# A minimal incoming camt.053 statement: a EUR 1,500 credit transfer that was
# booked, then returned because the beneficiary account was closed (AC04).
statement_xml = """<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.14">
  <BkToCstmrStmt>
    <GrpHdr><MsgId>STMT-MSG-0001</MsgId><CreDtTm>2026-06-15T08:00:00</CreDtTm></GrpHdr>
    <Stmt>
      <Id>STMT-0001</Id><CreDtTm>2026-06-15T08:00:00</CreDtTm>
      <Acct><Id><IBAN>GB29NWBK60161331926819</IBAN></Id><Ccy>EUR</Ccy></Acct>
      <Bal><Tp><CdOrPrtry><Cd>CLBD</Cd></CdOrPrtry></Tp>
        <Amt Ccy="EUR">10000.00</Amt><CdtDbtInd>CRDT</CdtDbtInd>
        <Dt><Dt>2026-06-15</Dt></Dt></Bal>
      <Ntry>
        <NtryRef>NTRY-0001</NtryRef>
        <Amt Ccy="EUR">1500.00</Amt><CdtDbtInd>CRDT</CdtDbtInd>
        <Sts><Cd>BOOK</Cd></Sts>
        <NtryDtls><TxDtls>
          <RtrInf><Rsn><Cd>AC04</Cd></Rsn></RtrInf>
        </TxDtls></NtryDtls>
      </Ntry>
    </Stmt>
  </BkToCstmrStmt>
</Document>"""

# 1. Parse into the typed model.
statement = parse_statement(statement_xml)
print(statement.account.identifier())          # -> GB29NWBK60161331926819
print(len(statement.entries))                   # -> 1

# 2. Select the entries returned AC04 (Closed Account).
ac04 = statement.entries_with_reason("AC04")
print(ac04[0].amount, ac04[0].credit_debit_indicator)   # -> 1500.00 CRDT

# 3. Generate the validated reversing entry (the original CRDT becomes DBIT).
reversal_xml = services.generate_reversal(statement_xml, reason_code="AC04")
assert "<RvslInd>true</RvslInd>" in reversal_xml
assert "<CdtDbtInd>DBIT</CdtDbtInd>" in reversal_xml

Supported messages

Message type Name Direction
camt.052.001.14 Bank To Customer Account Report read
camt.053.001.14 Bank To Customer Statement read + reverse
camt.054.001.14 Bank To Customer Debit Credit Notification read

The parser is namespace-agnostic and reads every ISO version of these messages; the official XSDs for .001.01.001.14 are bundled under camt053/xsd/. Reversing entries are emitted as camt.053.001.14.

Architecture

flowchart TD
    CLI["Click CLI"] --> S["camt053.services"]
    API["FastAPI REST API"] --> S
    MCP["camt053-mcp"] --> S
    LSP["camt053-lsp"] --> S
    S --> P["parse/ — statement_parser, reason_codes"]
    S --> R["reversal/ — reversal builder"]
    S --> X["xml/ — template + official ISO XSD"]
    S --> V["validation/ — IBAN, BIC, LEI, JSON Schema"]
Module Responsibility
camt053.parse Namespace-agnostic statement parser and return-reason helpers
camt053.reversal Builds flat reversing-entry records from parsed entries
camt053.xml Renders the camt.053 reversal template and validates it via the ISO XSD
camt053.validation IBAN / BIC / LEI and JSON-Schema validators
camt053.security XXE-safe parsing and path-traversal-checked output
camt053.services The shared facade backing every interface

Error handling

Every exception in camt053.exceptions inherits from Camt053Error and carries a stable, machine-readable code. These codes are part of the public API — they are guaranteed unique and will not change across releases — so you can switch on exc.code (e.g. to map a failure onto an HTTP status) without depending on the class name or message text.

Code Exception Meaning
CAMT053_ERROR Camt053Error Base error for any Camt053 failure
ACCOUNT_VALIDATION_ERROR AccountValidationError Account/input data failed validation
XML_GENERATION_ERROR XMLGenerationError XML rendering or template failure
CONFIGURATION_ERROR ConfigurationError Invalid configuration or CLI arguments
DATA_SOURCE_ERROR DataSourceError A data source could not be read
SCHEMA_VALIDATION_ERROR SchemaValidationError XML did not conform to its ISO 20022 XSD
INVALID_IBAN_ERROR InvalidIBANError IBAN format / checksum validation failed
INVALID_BIC_ERROR InvalidBICError BIC/SWIFT format validation failed
INVALID_LEI_ERROR InvalidLEIError LEI format / checksum validation failed
MISSING_REQUIRED_FIELD_ERROR MissingRequiredFieldError A required field was absent
STATEMENT_PARSE_ERROR StatementParseError An incoming statement could not be parsed
REVERSAL_GENERATION_ERROR ReversalGenerationError A reversing entry could not be generated
from camt053 import services
from camt053.exceptions import Camt053Error

try:
    services.generate_reversal(statement_xml, reason_code="AC04")
except Camt053Error as exc:
    log.error("[%s] %s", exc.code, exc)

Robustness

The statement parser is built for the messy reality of inbound bank files: malformed-but-recoverable statements degrade gracefully rather than failing outright.

  • Missing optional elements (owner name, currency, balances, booking date, return reason, ...) read as None / empty — only the <Document> envelope wrapping a recognised camt.05x container is mandatory.
  • Unknown or extra elements (vendor extensions, unexpected siblings) are ignored: children are matched by local name, not by a fixed schema.
  • Unexpected namespaces and prefixes are tolerated — a prefixed <camt:Document> root, a missing namespace, or a non-ISO namespace URI all parse the same way.

Genuinely non-well-formed XML (unclosed / mismatched tags, bad entities) still raises StatementParseError, which carries the 1-based source line (and column, where reported) so the offending byte can be located. See camt053/parse/statement_parser.py for the documented recovery limits.

Examples

Runnable, self-contained scripts live in examples/:

Example Demonstrates
reverse_ac04.py The headline workflow — find AC04 entries and generate the reversing entry
parse_statement.py Parsing a statement into the typed model
services_facade.py The shared camt053.services facade
validate_identifiers.py IBAN / BIC / LEI validation
rest_api_client.py Driving the FastAPI REST API in-process
git clone https://github.com/sebastienrousseau/camt053.git && cd camt053
python examples/reverse_ac04.py

The camt053 suite

camt053 is the core of a set of independently installable packages — pick whichever ones your stack needs:

Package Role
camt053 Core library + CLI + FastAPI REST API (this package)
camt053-mcp Model Context Protocol server (for AI agents)
camt053-lsp Language Server Protocol server (for editors)
camt053-writer-xlsx Excel .xlsx writer for parsed statements
camt053-loader-mt940 SWIFT MT940 → camt.053 loader

The MCP, LSP, writer-xlsx, and loader-mt940 packages are thin wrappers over the shared camt053.services facade exported here, so every interface behaves identically.

When not to use camt053

  • You need to generate payment files (pain.001 Customer Credit Transfer, pain.008 Direct Debit). Use pain001 — the sibling library for outbound ISO 20022.
  • You need to parse pacs.* (FI-to-FI) messages. Out of scope; this library targets the camt.05x (Bank-to-Customer) family only.
  • You need bank API transport (PSD2, EBICS, SWIFTNet). camt053 reads files and emits files; it does not move them. Pair with a dedicated transport library.
  • You need a GUI. This is a library + CLI + REST API; the closest thing to a UI is the LSP server's in-editor diagnostics.
  • You need real-time processing (FedNow / TIPS / RTP). Those rails use camt.052 intraday reporting, not camt.053 end-of-day statements; the parser accepts camt.052 but the reversing-entry workflow is camt.053-shaped.

Development

camt053 uses Poetry and mise.

git clone https://github.com/sebastienrousseau/camt053.git && cd camt053
mise install
poetry install
poetry shell

A Makefile orchestrates the quality gates (kept in lockstep with CI):

make check        # all gates (REQUIRED before commit)
make test         # pytest with coverage (100% gate)
make lint         # ruff + black --check
make type-check   # mypy --strict
make examples     # run the example scripts

Security

camt053 is the entry point for untrusted XML from banks for every consumer in the suite. Defence-in-depth is taken seriously: parsing uses defusedxml (XXE / billion-laughs neutralised), a pre-flight xml_guard enforces a configurable byte cap and refuses inline DOCTYPE / ENTITY declarations, and the REST API additionally caps request bodies via middleware. Reporting practice, supported versions, fix-window SLAs, and the full supply-chain posture (PyPI Trusted Publishing, sigstore attestations, signed tags) live in SECURITY.md. Vulnerabilities go via GitHub Private Vulnerability Reporting, not public issues.

News / Releases

Documentation

License

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

Contributing

Contributions are welcome — see the contributing instructions. Thanks to all contributors.

Acknowledgements

Built on Click, Rich, Jinja2, xmlschema, defusedxml, and FastAPI, against the official ISO 20022 camt.05x schemas.

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

camt053-0.0.9.tar.gz (457.9 kB view details)

Uploaded Source

Built Distribution

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

camt053-0.0.9-py3-none-any.whl (531.8 kB view details)

Uploaded Python 3

File details

Details for the file camt053-0.0.9.tar.gz.

File metadata

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

File hashes

Hashes for camt053-0.0.9.tar.gz
Algorithm Hash digest
SHA256 6aa8936f21daa79fdf77a961d1e18a31a88698a2359c71407aea43a2dfeda9ac
MD5 055e3300b958dee224c80308c5db3a32
BLAKE2b-256 c5abbf044c771d8f7ad6048c856d523737118e6e5747fc91ed28b3f729c52bd5

See more details on using hashes here.

Provenance

The following attestation bundles were made for camt053-0.0.9.tar.gz:

Publisher: release.yml on sebastienrousseau/camt053

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

File details

Details for the file camt053-0.0.9-py3-none-any.whl.

File metadata

  • Download URL: camt053-0.0.9-py3-none-any.whl
  • Upload date:
  • Size: 531.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for camt053-0.0.9-py3-none-any.whl
Algorithm Hash digest
SHA256 8200c5eacfc3e861e98f7de749da8963dafe2d7c8694d7ba17b2fe472ed501f4
MD5 53a2b80009e031242cc5addac49b3f60
BLAKE2b-256 968a450c42afd8a61883db05182a487aa929477850947986088f16686104f90c

See more details on using hashes here.

Provenance

The following attestation bundles were made for camt053-0.0.9-py3-none-any.whl:

Publisher: release.yml on sebastienrousseau/camt053

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