BAI2 (Bank Administration Institute v2) cash-management loader that parses BAI2 files into bankstatementparser Transaction objects.
Project description
bankstatementparser-loader-bai2
A BAI2 (Bank Administration Institute, version 2) cash-management loader that parses BAI2 files into bankstatementparser Transaction objects.
Contents
- What is bankstatementparser-loader-bai2? — the problem it solves
- Install — PyPI, virtualenv
- Quick start — parse a file in three lines
- Public API —
load_bai2,load_bai2_file,summarize_bai2 - Supported BAI2 subset — exactly which records are handled
- Amount and sign convention — how cents and debit/credit map
- When not to use this loader — honest boundaries
- Development — gates, make targets
- Security — input-handling posture
- Contributing — how to get changes in
- License — Apache-2.0
What is bankstatementparser-loader-bai2?
BAI2 (Bank Administration Institute, version 2) is the de-facto US
cash-management file format that banks ship for intraday and prior-day
balance and transaction reporting. The published
bankstatementparser
library parses PDF and other statement formats but does not support
BAI2.
bankstatementparser-loader-bai2 is a small, dependency-light companion
that fills that gap: give it a BAI2 payload and it returns a flat list of
bankstatementparser.transaction_models.Transaction
objects (source="bai2") that the rest of your deterministic pipeline
can consume unchanged.
| Concern | How this loader handles it |
|---|---|
| Record model | A documented, pragmatic subset of BAI2 (01/02/03/16/88 plus ignored trailers) |
| Amounts | BAI2 minor-unit integers (cents) converted to Decimal (never float) |
| Debit / credit | Derived from the 16 type-code range, with the raw code preserved |
| Multiple accounts | All 16 records across every group / account are flattened into one list |
| Real-world text | The 16 free-text field (and 88 continuations) is kept verbatim — commas and slashes inside it are preserved, not split on |
| Robustness | Tolerates CRLF, blank lines, trailing spaces, an optional trailing / per record, and V/S funds-type subfields |
| Errors | A clear ValueError if the file does not start with an 01 File Header |
Install
| Channel | Command | Notes |
|---|---|---|
| PyPI | pip install bankstatementparser-loader-bai2 |
Pulls in bankstatementparser >= 0.0.9 |
| Source | git clone https://github.com/sebastienrousseau/bankstatementparser-loader-bai2 && cd bankstatementparser-loader-bai2 && poetry install |
For development |
Requires Python 3.10 or later. Works on macOS, Linux, and Windows.
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 bankstatementparser-loader-bai2
Quick start
from bankstatementparser_loader_bai2 import load_bai2_file
transactions = load_bai2_file("statement.bai")
for txn in transactions:
print(txn.account_id, txn.currency, txn.amount, txn.description)
Or parse an in-memory payload:
from bankstatementparser_loader_bai2 import load_bai2
payload = (
"01,SENDER,RECEIVER,260601,1200,FILE001,,,/\n"
"02,RCVR,ORIG,1,260601,1200,USD,/\n"
"03,0123456789,USD,010,150000,1,,/\n"
"16,165,150000,Z,BANKREF1,CUSTREF1,Incoming wire payment/\n"
"88,from ACME Corp invoice 42/\n"
"16,475,2500,Z,BANKREF2,,ATM withdrawal/\n"
"49,152500,2/\n"
"98,152500,1,4/\n"
"99,152500,1,6/\n"
)
for txn in load_bai2(payload):
print(txn.amount, txn.category, txn.description)
# 1500 bai2:165 Incoming wire payment from ACME Corp invoice 42
# -25 bai2:475 ATM withdrawal
Runnable versions live in examples/.
Public API
from bankstatementparser_loader_bai2 import (
load_bai2,
load_bai2_file,
summarize_bai2,
Bai2Summary,
)
| Function | Signature | Returns |
|---|---|---|
load_bai2 |
load_bai2(text: str) |
list[Transaction] |
load_bai2_file |
load_bai2_file(path) |
list[Transaction] |
summarize_bai2 |
summarize_bai2(text: str) |
Bai2Summary |
Bai2Summary is a dataclass with the fields file_id, group_count,
account_count, transaction_count, and currency.
Each produced Transaction is populated as follows:
Transaction field |
Source |
|---|---|
account_id |
03 Account Identifier — accountNumber |
currency |
03 currencyCode, falling back to the 02 group currency |
amount |
16 amount (cents / 100), signed per the convention below |
booking_date |
02 Group Header as-of date, when present |
description |
16 text plus any 88 continuations |
transaction_id |
16 bankRefNum, falling back to customerRefNum |
reference / category |
The raw 16 type code (category as bai2:<code>) |
source |
Always "bai2" |
Supported BAI2 subset
BAI2 records are comma-delimited fields ending with a / delimiter,
each beginning with a numeric type code. This loader implements a
documented, pragmatic subset:
| Record | Meaning | Handling |
|---|---|---|
01 |
File Header | Required first record. fileId captured for the summary. |
02 |
Group Header | Group currency and as-of date captured. |
03 |
Account Identifier | accountNumber + optional currencyCode captured; account currency overrides group currency. |
16 |
Transaction Detail | One transaction. The free-text field runs to end-of-record (commas included) and is kept verbatim; V/S funds-type subfields are accounted for when locating the references and text. |
88 |
Continuation | Appended verbatim (commas included) to the preceding 16 record's text. A 88 continuing an 03 summary, or one with no preceding 16, is dropped rather than mis-attached. The rare 88: colon form is tolerated. |
49 / 98 / 99 |
Account / Group / File trailers | Ignored — control totals are not validated. |
Any other (or unknown) leading type code is ignored so that vendor extensions do not abort the parse. Ignoring control-total trailers is a deliberate, documented choice: the goal is faithful transaction extraction, not file-level reconciliation.
Amount and sign convention
BAI2 amounts are unsigned integers in the account currency's minor
units (cents), with no decimal point. They are converted to
decimal.Decimal by dividing by 100. An empty amount field is treated
as 0.
Debit / credit direction is derived from the documented numeric ranges
of the 16 record's type code (this is the loader's chosen, documented
convention):
| Type-code range | Meaning | Behaviour |
|---|---|---|
100–399 |
Credit | amount kept positive |
400–699 |
Debit | amount made negative |
700–799 |
Loan detail | treated as a debit-side disbursement: amount made negative |
900–999 |
Custom / summary / status | no Transaction emitted — these non-detail status/summary codes are skipped (and any continuation attached to one is dropped with it) |
| anything else | Unknown (incl. non-numeric) | amount kept positive |
The raw BAI2 type code is always preserved on every emitted
Transaction in both category (as bai2:<code>) and reference, so
no information is lost.
A small, optional lookup of well-known type codes (for example 142
"ACH credit", 301 "Commercial deposit", 475 "Check paid", 501
"Wire transfer debit") enriches the description of a 16 record that
carries no free-text of its own; a record that already has text keeps
its own text unchanged.
When not to use this loader
- You have ISO 20022 camt.053 or SWIFT MT940, not BAI2. Those are different formats with their own dedicated loaders.
- You need control-total reconciliation. This loader extracts
transactions and deliberately ignores the
49/98/99trailers; if you must validate file sums, do so before or after loading. - You need the full BAI2 specification. This is a documented subset focused on transaction extraction, not an exhaustive BAI2 parser.
Development
This project uses Poetry and mise.
git clone https://github.com/sebastienrousseau/bankstatementparser-loader-bai2.git
cd bankstatementparser-loader-bai2
poetry env use python3.12
poetry install
A Makefile orchestrates the quality gates (kept in lockstep with CI):
| Target | What it runs |
|---|---|
make check |
All gates (REQUIRED before commit) |
make test |
pytest --cov=bankstatementparser_loader_bai2 --cov-branch --cov-fail-under=100 |
make lint |
ruff check + black --check |
make type-check |
mypy --strict |
make doc-coverage |
interrogate --fail-under=100 (docstring coverage) |
make mutation |
mutmut run + mutmut results (mutation testing) |
Current state (v0.0.13): all tests passing, 100% line + branch
coverage against a 100% enforced floor, mypy --strict clean,
interrogate 100%, and a mutation-tested loader (317/336 mutants killed;
the 19 survivors are documented equivalent mutants — see
tests/MUTATION.md).
Security
- Read-only. The loader only reads text / files you pass it; it writes nothing.
- No XML, no network, no code execution. Parsing is a pure string-to-dataclass transformation.
- Decimal arithmetic is used throughout, avoiding
floatrounding surprises in financial amounts. - Dependencies are pinned via
poetry.lockand audited in CI.
To report a vulnerability, please use GitHub private vulnerability reporting rather than a public issue.
Contributing
Contributions are welcome — see the
contributing instructions.
Thanks to all the
contributors
who have helped build bankstatementparser-loader-bai2.
License
Licensed under the Apache License, Version 2.0. Any contribution submitted for inclusion shall be licensed as above, without additional terms.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file bankstatementparser_loader_bai2-0.0.13.tar.gz.
File metadata
- Download URL: bankstatementparser_loader_bai2-0.0.13.tar.gz
- Upload date:
- Size: 21.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4d36178c0748b03995e9c7cbc75117c94c0bac2967e3b747bed36e51024e2235
|
|
| MD5 |
0f7ea253c24bc985c65fba6cc858f539
|
|
| BLAKE2b-256 |
f0db37d12e9a8c4ab8c06abf4e36001de1da31b4703b0414b49a227090d2d64d
|
Provenance
The following attestation bundles were made for bankstatementparser_loader_bai2-0.0.13.tar.gz:
Publisher:
release.yml on sebastienrousseau/bankstatementparser-loader-bai2
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
bankstatementparser_loader_bai2-0.0.13.tar.gz -
Subject digest:
4d36178c0748b03995e9c7cbc75117c94c0bac2967e3b747bed36e51024e2235 - Sigstore transparency entry: 1953916130
- Sigstore integration time:
-
Permalink:
sebastienrousseau/bankstatementparser-loader-bai2@ac583702c8290d7ee3264fb0d94967e36345be50 -
Branch / Tag:
refs/tags/v0.0.13 - Owner: https://github.com/sebastienrousseau
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ac583702c8290d7ee3264fb0d94967e36345be50 -
Trigger Event:
push
-
Statement type:
File details
Details for the file bankstatementparser_loader_bai2-0.0.13-py3-none-any.whl.
File metadata
- Download URL: bankstatementparser_loader_bai2-0.0.13-py3-none-any.whl
- Upload date:
- Size: 19.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a420837a09a702573338dde1de5a244da57a4fb8844450233cb1e5628e7ed11f
|
|
| MD5 |
5c1752e80b8107fe7a5a58e28292c3b5
|
|
| BLAKE2b-256 |
d0fb43208fe37e75fa17528c4194754589994d8a5f3a8db1e1e00829150be008
|
Provenance
The following attestation bundles were made for bankstatementparser_loader_bai2-0.0.13-py3-none-any.whl:
Publisher:
release.yml on sebastienrousseau/bankstatementparser-loader-bai2
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
bankstatementparser_loader_bai2-0.0.13-py3-none-any.whl -
Subject digest:
a420837a09a702573338dde1de5a244da57a4fb8844450233cb1e5628e7ed11f - Sigstore transparency entry: 1953916224
- Sigstore integration time:
-
Permalink:
sebastienrousseau/bankstatementparser-loader-bai2@ac583702c8290d7ee3264fb0d94967e36345be50 -
Branch / Tag:
refs/tags/v0.0.13 - Owner: https://github.com/sebastienrousseau
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ac583702c8290d7ee3264fb0d94967e36345be50 -
Trigger Event:
push
-
Statement type: