@ekwo-ai/camt053

中文文档
0.25.2发布于 2026/11/13MITTypeScriptES Module零依赖构建来源已验证近 30 天下载 6953

Reads an ISO 20022 bank-to-customer statement (camt.053) into plain objects in TypeScript: account, balances and lines, amounts as decimal strings, and what does not add up. Zero dependencies, its own strict XML reader.

原始使用文档
文档目录7 节
  1. What it does
  2. A statement is hostile input
  3. What is thrown, and what comes back as a violation
  4. What it does not do
  5. Sources
  6. What is verified, and what is not
  7. Licence

@ekwo-ai/camt053

Reads an ISO 20022 bank-to-customer statement — camt.053, the account statement banks deliver as XML — into plain objects, in TypeScript, with no dependencies.

Give it the file and it gives you the statements in it, their lines, and the list of what does not add up.

import { readCamt053 } from '@ekwo-ai/camt053';

const { version, statements, violations } = readCamt053(bytesOrString);

for (const statement of statements) {
  statement.account.identifier; // { kind: 'iban', value } or { kind: 'other', value, scheme, issuer }
  statement.openingBalance;     // { type: 'OPBD', amount: '1000.00', currency: 'EUR', date: '2026-03-01' }
  statement.closingBalance;
  statement.balanced;           // true, false, or null when it could not be checked
  for (const line of statement.lines) {
    line.amount;                // '-450.50' — signed, a decimal string, never a float
    line.bookingDate;           // '2026-03-05'
    line.counterparty;          // { name, account, agentBic, ultimateName }
    line.remittance;            // { unstructured: ['Invoice 2026-0107'], structured: [{ reference, type, issuer }] }
    line.bankReference;         // the bank's own reference for the movement
  }
}

It knows no database, no ledger and no country. The shape it returns is declared in src/types.ts and imported from nowhere.

Every other brick beside this one writes a file an administration takes. This one reads a file a bank sent, and that changes what has to be proved: not that the output is valid, but that the input was understood — and that a file written to hurt the reader does not.

What it does

  • Reads versions 02 to 14 of the message, and says which one it read (version, namespace). The version is the last part of the namespace of the document element, and nothing is assumed. The same invented statement is written in each of the thirteen versions, held against the schema ISO publishes for that version, and has to read to the same objects out of all thirteen. A later version is still read and reported as version_not_verified; version 01 is refused, because under the same name it is another message.
  • Returns every statement of the file — a message may carry several accounts — and says on each violation which statement it is about.
  • Identifies an account by what the file gives: an IBAN or Othr/Id with its scheme and issuer. ISO 20022 offers the choice because half the world has no IBAN; a reader that returned only IBANs would read half the statements.
  • Signs every amount from the account holder's side — money in is positive, an overdrawn balance is negative — and returns it as a decimal string with the digits the file wrote. Sums are made on integers of hundred-thousandths (the schema allows five decimals); no figure passes through a number.
  • Checks that opening balance + booked entries = closing balance, to the last decimal. When it is not, the statement comes back as the bank wrote it, balanced is false, and balance_mismatch says the difference. Nothing is corrected: a reader that adjusts a balance hides the one fact the check exists to show — a truncated export, a missing page, a line lost on the way.
  • Counts only booked entries (BOOK). A pending or informational entry is returned, marked booked: false, and left out of the arithmetic, which is what the bank did when it computed the closing balance.
  • Keeps the structured communication and the free one apart, and keeps both when a payment carries both. A creditor reference is something a payer copied from an invoice and a machine can match; free text is something a person typed. Folding one into the other throws away the difference reconciliation lives on.
  • Splits a batch into its transactions — one line per TxDtls — when, and only when, every transaction carries an amount in the entry's currency and they add up to the entry exactly. Each line then keeps its own references, counterparty and communication, plus entry, detail, detailCount and entryAmount to put the batch back together. Otherwise the entry stays one line and batch_not_split says why. Either way the lines of a statement add up to what moved on the account, so the balance check does not depend on the choice. (Reconciliation wants the transaction; the balance wants the entry. The split is made only where both get what they want.)
  • Names the counterparty as the debtor of money coming in and the creditor of money going out — and the other way round when RvslInd says the entry undoes an earlier one, where the parties keep the roles they had in the original: a transfer that bounced comes back from the party it was sent to.
  • Takes the day the bank wrote. 2026-03-31T23:30:00+02:00 is 31 March; it is not moved to UTC, which would book it on another day for half the planet.
  • Returns the bank's own reference (AcctSvcrRef, of the transaction, else of the entry), the entry reference, the end-to-end identifier as written — including the NOTPROVIDED placeholder, which is the bank's word and not an absence this reader should decide — the mandate, the bank transaction code (ISO domain/family/sub-family and the proprietary one), the return reason, and what was ordered in another currency with the rate, unconverted.

A statement is hostile input

It arrives by e-mail, from a download, from a third party's API. The XML reader is written in this package, some three hundred lines, and is strict on purpose:

  • Any <!DOCTYPE is refused, unread. No statement needs one; the billion-laughs family and the external-entity family (XXE) both need one. There is no entity table to expand and nothing that opens a file or a socket.
  • The five predefined entities and numeric character references are decoded; any other entity is an error, not an empty string. A character reference that is not an XML character is an error.
  • Size is checked before a character is read (maxBytes, 32 MiB by default), depth and element count while reading (maxDepth 64, maxElements 2,000,000). The reader does not recurse: a hundred thousand nested elements are refused by the depth limit, and would not have touched the stack.
  • UTF-8 only, decoded fatally. A byte that is not UTF-8 is an error and not a replacement character in somebody's name. A file that declares another encoding is refused: decode it and pass the string.
  • Namespaces are resolved, so <Document xmlns="…"> and <ns2:Document xmlns:ns2="…"> are the same statement, and an element of another namespace is never read as the statement's.
  • Not well-formed is not read: mismatched tags, a second root, a bare &, a repeated attribute, a control character.

It is not a general XML parser: element and attribute names are ASCII, which every ISO 20022 name is, and nothing is validated against a schema at runtime.

What is thrown, and what comes back as a violation

Thrown (StatementFileError, with a code), because there is no statement to report on:

codewhen
too_large, too_deep, too_many_elementsa limit was passed
unsupported_encodingnot UTF-8
doctype_forbidden, undefined_entitysee above
malformed_xmlnot well-formed
not_a_statementwell-formed, and not a camt.053 — a camt.052, an HTML error page
unsupported_versioncamt.053.001.01
incomplete_statementno Stmt, or a statement without an identifier or an account

Returned in violations, with the statement and the line it is on, because one bad line should not cost the other three hundred:

codewhen
balance_mismatchopening + booked entries ≠ closing; the message says the difference
opening_balance_missing, closing_balance_missingno OPBD (or PRCD), no CLBD; the balance is not checked
balance_currency_mismatcha balance in another currency than the account
foreign_currency_entryan entry in another currency than the account — reported, not converted; the balance is not checked
invalid_amount, invalid_direction, invalid_datethe line comes back with null there
booking_date_missinga booked entry without BookgDt (the schema allows it)
invalid_ibanwritten as an IBAN and failing ISO 13616's own check digits — returned as written
duplicate_bank_reference, duplicate_entry_referencetwo entries of one statement under one reference
batch_not_split, batch_count_mismatchsee above
version_not_verifieda version this package has no schema for

invalid_amount, invalid_direction and invalid_date are each something the schema refuses: the tests put each one in a file and watch validation fail. balance_mismatch is the opposite, and the reason this package exists — the tests show the schema accepting a statement that does not add up.

What it does not do

  • It converts nothing. An entry in another currency is reported; what was ordered in dollars is returned in dollars beside what moved in the account's currency. Rates belong to whoever keeps the books.
  • It matches nothing. It does not know an invoice from a salary. It hands over what reconciliation needs, separated.
  • It does not decide what a duplicate is. Two lines with the same date, amount and counterparty are two lines; whether a file was already imported is a question for whoever holds the previous ones.
  • It does not read every element. Charges, interest, tax, securities and card details, availability, and the postal address of a party are not returned. They are skipped, not misread.
  • It does not read camt.052 or camt.054. The intraday report and the debit/credit notification share most of their types with the statement, and the reading would be close to the same — but a report has no closing booked balance to check and a notification has no balance at all, so they are other documents with other guarantees, and they are refused by name until someone needs them.
  • It reads no paginated statement as one. StmtPgntn is returned (page); a statement delivered over several files opens and closes each page on interim balances (ITBD), which this package returns in balances and does not take for an opening or a closing. Such a page reports opening_balance_missing rather than guessing.

Sources

What is verified, and what is not

Verified: every file this package is tested on is first held against the schema ISO publishes for its version (test/schema.test.ts, thirteen schemas, unmodified under test/xsd/, with no network and no system tool) — so the reader is tested on camt.053, not on its author's idea of camt.053. One statement is written in all thirteen versions and reads to the same objects. The violations that are schema violations are shown to be refused by the schema; the one that matters most, the balance, is shown not to be. The hostile files are each refused by name, and the two that ask for time or memory are refused within a bound the test measures.

Writing the fixtures against the schemas refuted the first draft once, the same hour: BIC became BICFI in version 03, not in 04 as the draft had it. And fetching the schemas found two versions the draft did not know: 14, published in March 2026, and 01, which is served under the same name and is another message.

Not verified — and this is the larger half:

  • No file from a bank. Every statement here is invented, because a real one is somebody's account. The schema says what a bank may send; it does not say what any bank does send. Banks differ on exactly the things this package cares about: whether a batch is detailed, where the reference is (AcctSvcrRef on the entry, on the transaction, on both, on neither), whether the counterparty of a card payment is a party or a line of free text, what PRCD means on a Monday. A reading that passes on invented files is an indication, not a proof, and the first real statement from each bank is a test nobody has run.
  • No usage guideline. EPC, CGI-MP, and the implementation guides of national banking federations restrict the message — which elements are filled, with which codes. None is tested.
  • The counterparty of a reversal. That the parties keep their original roles when RvslInd is true is this package's reading of the message definition and of common practice; the schema cannot say, and banks may differ.
  • Versions 02 and 08 are the ones in use. The eleven others are verified against their schemas and, as far as the authors know, against nothing else: nobody here has seen a camt.053.001.11 in the wild.
  • The external code sets (bank transaction codes, return reasons, balance types) are returned as written and not checked against ISO's published lists.
  • Performance is bounded, not measured: a statement at the default size limit is read in memory, as a whole.

Licence

MIT. See LICENSE.

版本与发布记录

@ekwo-ai/camt053 共发布 33 个版本,首次发布于 2026/09/19;过去 12 个月发布了 33 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.25.2latest2026/11/13今天
0.25.12026/11/13今天
0.25.02026/11/076 天前
0.24.12026/11/058 天前
0.24.02026/10/2815 天前
0.23.02026/10/2816 天前

关于 @ekwo-ai/camt053 的常见问题

@ekwo-ai/camt053 是什么?

Reads an ISO 20022 bank-to-customer statement (camt.053) into plain objects in TypeScript: account, balances and lines, amounts as decimal strings, and what does not add up. Zero dependencies, its own strict XML reader.

如何安装 @ekwo-ai/camt053?

在项目目录运行 npm install @ekwo-ai/camt053,或使用 pnpm add / yarn add / bun add。

@ekwo-ai/camt053 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@ekwo-ai/camt053 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@ekwo-ai/camt053 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=18。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@ekwo-ai/camt053 可以商用吗?

@ekwo-ai/camt053 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@ekwo-ai/camt053 的下载量有多少?

根据 npm 官方下载统计,@ekwo-ai/camt053 在 2026/10/13 – 2026/11/11 这 30 天内被下载 6,953 次,日均约 232 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@ekwo-ai/camt053 还在维护吗?

最新版本 0.25.2 发布于 2026/11/13(今天);至今共发布 33 个版本,其中过去 12 个月发布了 33 个;首次发布于 2026/09/19。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。