genkgo/camt
A PHP library for reading CAMT bank statement files, supporting CAMT.052, CAMT.053, and CAMT.054 formats across multiple versions. Install via Composer, then loop through statements and entries with a simple reader API.
Architecture fit. genkgo/camt is a plain PHP XML-parsing library with no framework coupling, no global state, and no service-provider requirement. That makes it an unusually clean fit for Laravel if we treat it as an anti-corruption layer rather than a domain dependency: CAMT is a bank-controlled schema that changes on the banks' timetable, so the parser should sit behind our own port (StatementParser::parse(Stream|Path): BankStatement) and never leak Genkgo\Camt\DTO\* objects into reconciliation, ledger, or reporting code. The library's role is narrow and correct: turn ISO 20022 XML into typed objects. It does not reconcile, validate against business rules, or persist — all of which remain ours.
Integration feasibility. High. composer require genkgo/camt, PHP 8.x, ext-dom/ext-simplexml present in any standard Laravel image. No database, queue, or config prerequisites. Time-boxed feasibility is a day, not a sprint. The real cost is not installation — it is the mapping layer from CAMT's nested Ntry/NtryDtls/TxDtls/RmtInf tree into our schema, which is ours to build and own regardless of library choice.
Technical risk.
.06; whether the widely bank-mandated .08 (and newer .09/.10) revisions parse is unconfirmed. A silent parse failure or a partial object graph on a newer revision is a realistic production incident for a finance workflow.pain.001) or statement generation is out of scope; if our roadmap includes either, this package covers only half the ISO 20022 surface.Key questions.
.08 covered for CAMT.053?Strd/RmtInf), creditor reference, counterparty BIC/IBAN, FX fields, and opening/closing balances — or only a subset?Stack fit. Laravel 10–12 / PHP 8.1+. The library lives in a single app/Domain/Banking/Camt namespace with a thin adapter class bound in a service provider we write ourselves. Config should be a bank-profile map (bank → expected message version → parser options), because different counterparties will send different revisions and we need to fail loudly per-bank rather than globally.
Migration path. If statements currently arrive as MT940 or CSV, do not rip out the existing importer. Introduce a StatementParser interface with Mt940Parser, CsvParser, and CamtParser implementations, selected by a detector on file shape. This lets CAMT onboard bank-by-bank, keeps a rollback path, and gives us a single reconciliation entry point. If there is no existing importer, start CAMT-only but still behind the interface — the second format will arrive.
Compatibility. Verify against a corpus of real files from each bank, not the library's fixtures. Check ext-dom presence in production and CI images, confirm the parser tolerates UTF-8 BOM and CRLF, and confirm no XXE. Pin the version in composer.json (caret on minor only) and record the exact resolved version in import metadata so a regression can be traced to a package bump.
Sequencing.
external_id derived from MsgId/DocumentNumber + account + date for idempotency.StatementParser interface and detector; wire CAMT alongside existing formats.Maintenance. Expect to own the mapping layer permanently and the parser occasionally. Set a lightweight watch: subscribe to releases, run the corpus test suite on every dependency bump, and keep a fork-ready posture (the MIT licence and small surface make a fork cheap). Budget roughly a few days per year for version-coverage catch-up, plus whatever work a new bank's file quirks demand.
Support. No commercial support, no SLA. Community issues only. This is acceptable for an internal ingestion component with a corpus-based test suite, but it is not acceptable to have it as the sole path for a regulatory or audit-relevant ledger feed without our own regression coverage and a runbook.
Scaling. Parsing is CPU- and memory-bound on file size, not on concurrency. Run imports in a queue with a dedicated worker pool, cap file size at the upload boundary, and avoid loading the parsed object graph into memory twice (parse → stream to DB rows, or discard after mapping). If CAMT.053 files grow into multi-megabyte territory with tens of thousands of entries, measure peak memory early; if the library is DOM-based, plan to chunk by statement within a file and enforce a per-file ceiling.
Failure modes and mitigations.
Ramp-up. Low for engineers using it (an afternoon to read the DTO surface), moderate for the domain mapping — CAMT's nesting and the bank-to-bank variation in remittance information is where the real learning is. Plan for one engineer to own banking ingestion end-to-end, with the reconciliation semantics documented, because that knowledge is the durable asset and the parser is replaceable.
How can I help you explore Laravel packages today?