@ingram-tech/coda
v0.1.0
Published
TypeScript parser for Belgian CODA (Coded statement of account) bank files
Readme
@ingram-tech/coda
TypeScript parser for CODA (Coded statement of account) bank files. CODA is the Belgian standard (maintained by Febelfin) for electronic bank-to-customer account statements, used by all Belgian banks and widely supported across Europe.
Parses CODA v2.x files into fully typed objects. Returns null on invalid input instead of throwing.
Installation
npm install @ingram-tech/codaUsage
import { parseCoda } from "@ingram-tech/coda";
import { readFileSync } from "node:fs";
const content = readFileSync("statement.cod", "utf-8");
const file = parseCoda(content);
if (file) {
for (const stmt of file.statements) {
console.log(`Account: ${stmt.account.number} (${stmt.account.currency})`);
console.log(`Holder: ${stmt.accountHolderName}`);
console.log(`Old balance: ${stmt.oldBalance.amount}`);
console.log(`New balance: ${stmt.newBalance?.amount}`);
for (const m of stmt.movements) {
console.log(` ${m.amount > 0 ? "+" : ""}${m.amount} ${m.counterpartyName ?? ""}`);
console.log(` ${m.communication}`);
if (m.structuredCommunicationType === 101) {
// Belgian structured payment reference (+++xxx/xxxx/xxxxx+++)
const ref = m.communication;
console.log(` Ref: +++${ref.slice(0, 3)}/${ref.slice(3, 7)}/${ref.slice(7)}+++`);
}
}
for (const msg of stmt.freeCommunications) {
console.log(` Message: ${msg}`);
}
}
}Design
- Single function, null return --
parseCoda(content)returns aCodaFileornull. No exceptions for malformed input. - Signed amounts -- Balances and movements are signed numbers: positive for credit, negative for debit. No separate sign field to check.
- Faithful extraction -- Fields are extracted at their standard-defined positions. Communications are concatenated across record parts (2.1 + 2.2 + 2.3 for movements, 3.1 + 3.2 + 3.3 for information records) and right-trimmed.
- No deep structured communication parsing -- The
communicationTypeandstructuredCommunicationTypefields tell you the format; thecommunicationfield gives you the raw content. Type 101/102 Belgian structured references come through as 12-digit strings ready for mod-97 validation. More exotic types (127 SEPA direct debit, 105 FX details, etc.) are left as raw strings for the caller to parse. - Flat movement model -- Each record 2.1 becomes a
CodaMovement, with fields from 2.2 and 2.3 merged in. Information records (3.x) are attached as aninformation[]array on the preceding movement.
Parsed fields
The parser extracts all fields defined in the CODA v2.8 standard:
- Header (record 0): creation date, bank ID, duplicate flag, file reference, addressee name, BIC, company ID, separate application code, MT940 references, version
- Old balance (record 1): account number (Belgian BBAN, foreign BBAN, Belgian IBAN, or foreign IBAN), currency, country code, paper/CODA statement sequence numbers, account holder name, account description, opening balance (signed amount + date)
- Movements (records 2.1 / 2.2 / 2.3):
- 2.1: sequence/detail numbers, bank reference, signed amount, value date, entry date, 8-digit transaction code (type/family/transaction/category), communication (structured or free), globalisation code
- 2.2: customer reference, counterparty BIC, R-transaction type and reason, SEPA CategoryPurpose and Purpose codes
- 2.3: counterparty account number and currency, counterparty name, communication continuation
- Information (records 3.1 / 3.2 / 3.3): sequence/detail numbers, bank reference, transaction code, communication (structured or free), linked to parent movement
- New balance (record 8): closing balance (signed amount + date)
- Free communications (record 4): free-text messages, grouped by sequence number
- Trailer (record 9): debit and credit movement totals
API reference
parseCoda(content: string): CodaFile | null
Parse a CODA file. Returns null if the input is empty, doesn't start with a record 0, or cannot be parsed. Handles both \n and \r\n line endings. Multiple statements in a single file (delimited by record 0 boundaries) are supported.
Types
CodaFile
| Field | Type | Description |
|-------|------|-------------|
| statements | CodaStatement[] | One or more bank statements |
CodaStatement
| Field | Type | Description |
|-------|------|-------------|
| creationDate | Date | File creation date |
| bankId | number | Bank identification number |
| isDuplicate | boolean | Whether this is a duplicate file |
| fileReference | string? | File reference assigned by the bank |
| addressee | string | Name of the addressee |
| bic | string? | BIC of the bank holding the account |
| companyId | string? | Belgian company identification number |
| separateApplication | string | Separate application code (5 positions) |
| transactionReference | string? | MT940 transaction reference (tag 20) |
| relatedReference | string? | MT940 related reference (tag 21) |
| version | number | CODA standard version |
| account | CodaAccount | Account details |
| paperStatementSequence | number | Paper statement sequence number |
| codaStatementSequence | number | CODA statement sequence number |
| accountHolderName | string? | Name of the account holder |
| accountDescription | string? | Account description |
| oldBalance | CodaBalance | Opening balance |
| newBalance | CodaBalance? | Closing balance (absent in empty files) |
| movements | CodaMovement[] | Transaction movements |
| freeCommunications | string[] | Free communication texts |
| totalDebit | number | Sum of debit movement amounts from trailer |
| totalCredit | number | Sum of credit movement amounts from trailer |
CodaAccount
| Field | Type | Description |
|-------|------|-------------|
| structure | "belgian-bban" \| "foreign-bban" \| "belgian-iban" \| "foreign-iban" | Account number format |
| number | string | Account number (BBAN or IBAN) |
| currency | string? | ISO currency code |
| countryCode | string? | ISO country code (Belgian BBAN only) |
CodaBalance
| Field | Type | Description |
|-------|------|-------------|
| amount | number | Signed amount (positive = credit, negative = debit) |
| date | Date | Balance date |
CodaMovement
| Field | Type | Description |
|-------|------|-------------|
| sequenceNumber | number | Continuous sequence number |
| detailNumber | number | Detail number within sequence |
| bankReference | string | Bank reference (informative) |
| amount | number | Signed amount |
| valueDate | Date? | Value date |
| entryDate | Date | Entry/booking date |
| transactionCode | CodaTransactionCode | 8-digit transaction code |
| communication | string | Full communication text |
| communicationType | "structured" \| "unstructured" | Communication format |
| structuredCommunicationType | number? | 3-digit type (e.g. 101, 127) |
| paperStatementSequence | number | Paper statement sequence |
| globalisationCode | number? | Globalisation hierarchy level (1-9) |
| customerReference | string? | Customer reference |
| counterpartyBic | string? | Counterparty's bank BIC |
| rTransactionType | number? | R-transaction type (1-5) |
| rTransactionReason | string? | ISO reason return code |
| categoryPurpose | string? | SEPA CategoryPurpose |
| purpose | string? | SEPA Purpose |
| counterpartyAccountNumber | string? | Counterparty account number |
| counterpartyAccountCurrency | string? | Counterparty account currency |
| counterpartyName | string? | Counterparty name |
| information | CodaInformation[] | Linked information records |
CodaTransactionCode
| Field | Type | Description |
|-------|------|-------------|
| type | number | Type (0=simple, 1=customer total, 2=bank total, 5/6/7/8/9=details, 3=with detail) |
| family | number | Family (01-39 domestic/SEPA, 41-79 foreign, 80-89 other) |
| transaction | number | Transaction within family |
| category | number | Category (000=net amount, others for cost breakdowns) |
CodaInformation
| Field | Type | Description |
|-------|------|-------------|
| sequenceNumber | number | Matches parent movement |
| detailNumber | number | Detail number |
| bankReference | string | Bank reference |
| transactionCode | CodaTransactionCode | Transaction code |
| communication | string | Full communication text |
| communicationType | "structured" \| "unstructured" | Communication format |
| structuredCommunicationType | number? | 3-digit type code |
Development
npm test # run tests in watch mode
npm run test:run # run tests once
npm run lint # eslint
npm run format # prettier
npm run build # build to dist/
npm run ci # type-check + lint + test + buildLicense
MIT
