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 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.3 — 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

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

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.3.tar.gz (406.1 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.3-py3-none-any.whl (466.7 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: camt053-0.0.3.tar.gz
  • Upload date:
  • Size: 406.1 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.3.tar.gz
Algorithm Hash digest
SHA256 0c48a1dfe7f46593928001fe75922b469d8d295778b196dc20aefaab8a341dbc
MD5 12a7477031b361bbbd3db2522f16f259
BLAKE2b-256 7097ec9dd13b0d0098de37e29badbad695355b4e979b270026002b20697b2b18

See more details on using hashes here.

Provenance

The following attestation bundles were made for camt053-0.0.3.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.3-py3-none-any.whl.

File metadata

  • Download URL: camt053-0.0.3-py3-none-any.whl
  • Upload date:
  • Size: 466.7 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.3-py3-none-any.whl
Algorithm Hash digest
SHA256 89ed5e4c10604415c0e86fd27cd25c59bd75e37638aa65867979916501985b00
MD5 14d35816753f9fb2edc128c19d7b22e5
BLAKE2b-256 dde865e0e781e8064b86cdb0526ba9085db288a967a8c06c713f2fbd74348261

See more details on using hashes here.

Provenance

The following attestation bundles were made for camt053-0.0.3-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