Bank statements tools
MCP tools for Bank statements: bank_statements_imports_create, bank_statements_imports_get, bank_statements_imports_list, bank_statements_lines_ignore, bank_statements_lines_list, bank_statements_lines_match.
bank_statements_imports_create: Import a bank statementbank_statements_imports_get: Get a bank statement importbank_statements_imports_list: List bank statement importsbank_statements_lines_ignore: Ignore a bank statement linebank_statements_lines_list: List bank statement linesbank_statements_lines_match: Match a bank statement line to an invoice
bank_statements_imports_create
Import a bank statement. Operation bank_statements.imports.create · Legal entity level · permission invoices:write · risk tier financial · since M5
Imports a bank statement of the legal entity's account as CSV and matches its incoming transfers to open invoices of every brand of the entity (send_invoice invoices carry their number as the payment reference).
- The file needs a header row and, per booked transaction, a booking date, a signed amount (incoming money is
positive), the reference and optionally the counterparty and a currency. Columns are recognised by common
header names (English, German, Croatian) or named in
columns; dates asYYYY-MM-DD,DD.MM.YYYYor with slashes (dateFormatrequired);decimalSeparator.or,. A file with an unreadable row is refused whole (bank_statement_invalid, rows indetails.errors); at most 2,000 transactions per file. - The same file twice is refused; lines an earlier import has (overlapping statements) are skipped and
counted as
duplicates. - A line whose reference names exactly one open invoice and whose amount is that invoice's amount due pays
it at once, as
invoices.mark_paidwould on the booking date (invoice.paid; a past-due subscription recovers). Every other line waits in the review queue (bank_statements.lines.listwithmatchStatus=partial,unmatched) with the reason and the invoices it may pay.
Financial tier: it records payments. Dry-run it first to see the matches without saving anything. CAMT.053 files arrive in a later version.
Annotations: readOnlyHint: false · destructiveHint: false · idempotentHint: false · openWorldHint: false
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
csv | string | yes | The statement as CSV text: a header row, then one booked transaction per row (booking date, signed amount, reference, optionally counterparty and currency). (1–2000000 characters) |
currency | string | yes | The bank account's currency (rows without a currency column). |
filename | string | no | (1–200 characters) |
delimiter | one of ,, ;, | no | ,, ; or a tab. Default: detected from the header. |
dateFormat | one of YYYY-MM-DD, DD.MM.YYYY, DD/MM/YYYY, MM/DD/YYYY | no | Default: YYYY-MM-DD, or DD.MM.YYYY when the dates have dots. Dates with slashes need it. |
decimalSeparator | one of ., , | no | Default: , in ;-separated files, else .. |
columns | object | no | Header names to use when the recognised ones don't fit (e.g. { reference: "Remittance" }). |
entity_id | ID (ent_…) | no | The legal entity to act on (ent_…), inside your API key's reach. Needed with an organization key; entity and brand keys act on their own entity. |
idempotency_key | string | no | A unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's idempotency_key. (1–255 characters) |
dry_run | boolean | no | true: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default false) |
- Legal entity: pass
entity_idwith an organization key; entity and brand keys act on their own entity. - Idempotency: the result returns the
idempotency_keyused, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours). - Dry run: supported.
dry_run: truechecks permissions and rules and computes the result, then rolls everything back.
Errors
validation_failed: A field is malformed or out of range.bank_statement_invalid: The CSV can't be read: a missing column, a bad date or amount (details.errorslists the rows).bank_statement_already_imported: This exact file was imported before (details.import_id).version_conflict: An invoice or line changed at the same time (another import or payment); retry.permission_denied: The credentials can't record invoice payments for this entity (invoices:write, finance).
Example
Import a statement: one transfer pays its invoice, two wait for review
Arguments:
{
"csv": "Booking date,Amount,Reference,Counterparty\n2026-11-04,1200.00,GEN-2026-000131,Alpen Apps GmbH\n2026-11-04,450.00,Invoice 2026-000132,Berg Software AG\n2026-11-04,-12.50,Account fee,Bank",
"currency": "EUR",
"filename": "statement-2026-11-04.csv",
"entity_id": "ent_01jbx4m3v8e9t0s6k2c5n7q1wy",
"idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
Result output:
{
"id": "bsi_01m4tx5nj8emwbyf7y9vcf48ba",
"object": "bank_statement_import",
"entityId": "ent_01m4tx5nj8emwbyf7y9vcf47zm",
"livemode": false,
"format": "csv",
"filename": "statement-2026-11-04.csv",
"currency": "EUR",
"lineCount": 3,
"counts": {
"imported": 3,
"duplicates": 0,
"matched": 1,
"partial": 0,
"unmatched": 2,
"ignored": 0
},
"from": "2026-11-04",
"to": "2026-11-04",
"options": {
"delimiter": ",",
"dateFormat": null,
"decimalSeparator": null,
"columns": {
"bookingDate": "Booking date",
"amount": "Amount",
"reference": "Reference",
"counterparty": "Counterparty",
"currency": null
}
},
"importedBy": {
"type": "user",
"id": "usr_01m4tx5nj8emwbyf7y9vcf47zk"
},
"version": 2,
"createdAt": "2026-11-05T09:00:00.000Z",
"updatedAt": "2026-11-05T09:00:00.000Z",
"paidInvoiceIds": ["inv_01m4tx5nj8emwbyf7y9vcf47zn"]
}
bank_statements_imports_get
Get a bank statement import. Operation bank_statements.imports.get · Legal entity level · permission invoices:read · risk tier read · since M5
Returns one imported bank statement: the file's name, how it was read (delimiter, date
format, decimal separator, the columns used), the booking-date range and its lines counted by match status.
List its lines with bank_statements.lines.list and importId.
Annotations: readOnlyHint: true · destructiveHint: false · idempotentHint: true · openWorldHint: false
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
id | ID (bsi_…) | yes | – |
entity_id | ID (ent_…) | no | The legal entity to act on (ent_…), inside your API key's reach. Needed with an organization key; entity and brand keys act on their own entity. |
- Legal entity: pass
entity_idwith an organization key; entity and brand keys act on their own entity. - Read-only: changes nothing;
idempotency_keyis ignored.
Errors
validation_failed: A field is malformed or out of range.resource_not_found: No bank statement import or line with this ID is visible to the request.permission_denied: The credentials can't read this entity's invoices (invoices:read).
Example
An import
Arguments:
{
"id": "bsi_01m4tx5nj8emwbyf7y9vcf48ba",
"entity_id": "ent_01jbx4m3v8e9t0s6k2c5n7q1wy"
}
Result output:
{
"id": "bsi_01m4tx5nj8emwbyf7y9vcf48ba",
"object": "bank_statement_import",
"entityId": "ent_01m4tx5nj8emwbyf7y9vcf47zm",
"livemode": false,
"format": "csv",
"filename": "statement-2026-11-04.csv",
"currency": "EUR",
"lineCount": 3,
"counts": {
"imported": 3,
"duplicates": 0,
"matched": 1,
"partial": 0,
"unmatched": 2,
"ignored": 0
},
"from": "2026-11-04",
"to": "2026-11-04",
"options": {
"delimiter": ",",
"dateFormat": null,
"decimalSeparator": null,
"columns": {
"bookingDate": "Booking date",
"amount": "Amount",
"reference": "Reference",
"counterparty": "Counterparty",
"currency": null
}
},
"importedBy": {
"type": "user",
"id": "usr_01m4tx5nj8emwbyf7y9vcf47zk"
},
"version": 2,
"createdAt": "2026-11-05T09:00:00.000Z",
"updatedAt": "2026-11-05T09:00:00.000Z"
}
bank_statements_imports_list
List bank statement imports. Operation bank_statements.imports.list · Legal entity level · permission invoices:read · risk tier read · since M5
Lists the legal entity's imported bank statements in the mode of the request, newest first, with their lines
counted by match status (matched, partial and unmatched waiting for review, ignored) and the
duplicates skipped.
Paginate with limit (1–100, default 10) and starting_after (the next_cursor of the previous page).
Annotations: readOnlyHint: true · destructiveHint: false · idempotentHint: true · openWorldHint: false
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
limit | integer | no | (1–100) |
starting_after | ID (bsi_…) | no | – |
entity_id | ID (ent_…) | no | The legal entity to act on (ent_…), inside your API key's reach. Needed with an organization key; entity and brand keys act on their own entity. |
- Legal entity: pass
entity_idwith an organization key; entity and brand keys act on their own entity. - Read-only: changes nothing;
idempotency_keyis ignored.
Errors
validation_failed: A field is malformed or out of range.resource_not_found: No bank statement import or line with this ID is visible to the request.permission_denied: The credentials can't read this entity's invoices (invoices:read).
Example
The latest imports
Arguments:
{
"limit": 10,
"entity_id": "ent_01jbx4m3v8e9t0s6k2c5n7q1wy"
}
Result output:
{
"object": "list",
"data": [
{
"id": "bsi_01m4tx5nj8emwbyf7y9vcf48ba",
"object": "bank_statement_import",
"entityId": "ent_01m4tx5nj8emwbyf7y9vcf47zm",
"livemode": false,
"format": "csv",
"filename": "statement-2026-11-04.csv",
"currency": "EUR",
"lineCount": 3,
"counts": {
"imported": 3,
"duplicates": 0,
"matched": 1,
"partial": 0,
"unmatched": 2,
"ignored": 0
},
"from": "2026-11-04",
"to": "2026-11-04",
"options": {
"delimiter": ",",
"dateFormat": null,
"decimalSeparator": null,
"columns": {
"bookingDate": "Booking date",
"amount": "Amount",
"reference": "Reference",
"counterparty": "Counterparty",
"currency": null
}
},
"importedBy": {
"type": "user",
"id": "usr_01m4tx5nj8emwbyf7y9vcf47zk"
},
"version": 2,
"createdAt": "2026-11-05T09:00:00.000Z",
"updatedAt": "2026-11-05T09:00:00.000Z"
}
],
"has_more": false,
"next_cursor": null
}
bank_statements_lines_ignore
Ignore a bank statement line. Operation bank_statements.lines.ignore · Legal entity level · permission invoices:write · risk tier write · since M5
Takes a line out of the review queue without paying an invoice, with the reason: a bank fee, a processor
payout, a refund, or a partial payment settled with the customer another way. The line stays in the
statement as ignored; nothing is posted.
Annotations: readOnlyHint: false · destructiveHint: false · idempotentHint: false · openWorldHint: false
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
id | ID (bsl_…) | yes | – |
reason | string | yes | Why the line pays no invoice (a fee, a payout, a refund, a partial payment settled otherwise). (1–500 characters) |
expectedVersion | integer | no | (1–9007199254740991) |
entity_id | ID (ent_…) | no | The legal entity to act on (ent_…), inside your API key's reach. Needed with an organization key; entity and brand keys act on their own entity. |
idempotency_key | string | no | A unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's idempotency_key. (1–255 characters) |
dry_run | boolean | no | true: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default false) |
- Legal entity: pass
entity_idwith an organization key; entity and brand keys act on their own entity. - Idempotency: the result returns the
idempotency_keyused, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours). - Dry run: supported.
dry_run: truechecks permissions and rules and computes the result, then rolls everything back.
Errors
validation_failed: A field is malformed or out of range.resource_not_found: No bank statement import or line with this ID is visible to the request.bank_statement_line_resolved: The line was matched or ignored already.version_conflict: The line changed since you read it (expectedVersion); retry.permission_denied: The credentials can't record invoice payments for this entity (invoices:write, finance).
Example
A bank fee
Arguments:
{
"id": "bsl_01m4tx5nj8emwbyf7y9vcf48bc",
"reason": "Bank fee",
"entity_id": "ent_01jbx4m3v8e9t0s6k2c5n7q1wy",
"idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
Result output:
{
"id": "bsl_01m4tx5nj8emwbyf7y9vcf48bc",
"object": "bank_statement_line",
"entityId": "ent_01m4tx5nj8emwbyf7y9vcf47zm",
"livemode": false,
"importId": "bsi_01m4tx5nj8emwbyf7y9vcf48ba",
"row": 3,
"bookingDate": "2026-11-04",
"amount": {
"amount": "450000000",
"currency": "EUR"
},
"reference": "Invoice 2026-000132",
"counterparty": "Berg Software AG",
"matchStatus": "ignored",
"review": {
"reason": "amount_only",
"candidateInvoiceIds": ["inv_01m4tx5nj8emwbyf7y9vcf48bd"],
"candidates": [
{
"invoiceId": "inv_01m4tx5nj8emwbyf7y9vcf48bd",
"number": "GEN-2026-000132",
"brandId": "brd_01m4tx5nj8emwbyf7y9vcf47z0"
}
]
},
"invoiceId": null,
"brandId": null,
"ledgerTransactionId": null,
"payoutItemId": null,
"matchedBy": null,
"matchedAt": null,
"ignoredReason": "Bank fee",
"version": 2,
"createdAt": "2026-11-05T09:00:00.000Z",
"updatedAt": "2026-11-05T10:00:00.000Z"
}
bank_statements_lines_list
List bank statement lines. Operation bank_statements.lines.list · Legal entity level · permission invoices:read · risk tier read · since M5
Lists the legal entity's bank statement lines in the mode of the request, newest first. Filter by
importId, by matchStatus (one or several: the review queue is partial and unmatched) and by
invoiceId (the lines that paid or point to an invoice).
A line in review says why in review.reason: amount_mismatch or currency_mismatch (its reference names
an invoice, the amount differs), ambiguous_reference (it names several), already_matched (another line of
the import paid that invoice), amount_only (no reference, but open invoices with exactly this amount due),
no_match or not_incoming (money going out). review.candidateInvoiceIds are the invoices it may pay.
Resolve a line with bank_statements.lines.match or .ignore.
Paginate with limit (1–100, default 10) and starting_after (the next_cursor of the previous page).
Annotations: readOnlyHint: true · destructiveHint: false · idempotentHint: true · openWorldHint: false
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
importId | ID (bsi_…) | no | Only this import's lines. |
matchStatus | one of unmatched, matched, partial, ignored or array of one of unmatched, matched, partial, ignored | no | One status or several; the review queue is partial and unmatched. |
invoiceId | ID (inv_…) | no | Only the lines that paid or point to this invoice. |
limit | integer | no | (1–100) |
starting_after | ID (bsl_…) | no | – |
entity_id | ID (ent_…) | no | The legal entity to act on (ent_…), inside your API key's reach. Needed with an organization key; entity and brand keys act on their own entity. |
- Legal entity: pass
entity_idwith an organization key; entity and brand keys act on their own entity. - Read-only: changes nothing;
idempotency_keyis ignored.
Errors
validation_failed: A field is malformed or out of range.resource_not_found: No bank statement import or line with this ID is visible to the request.permission_denied: The credentials can't read this entity's invoices (invoices:read).
Example
The review queue
Arguments:
{
"matchStatus": ["partial", "unmatched"],
"entity_id": "ent_01jbx4m3v8e9t0s6k2c5n7q1wy"
}
Result output:
{
"object": "list",
"data": [
{
"id": "bsl_01m4tx5nj8emwbyf7y9vcf48bc",
"object": "bank_statement_line",
"entityId": "ent_01m4tx5nj8emwbyf7y9vcf47zm",
"livemode": false,
"importId": "bsi_01m4tx5nj8emwbyf7y9vcf48ba",
"row": 3,
"bookingDate": "2026-11-04",
"amount": {
"amount": "450000000",
"currency": "EUR"
},
"reference": "Invoice 2026-000132",
"counterparty": "Berg Software AG",
"matchStatus": "unmatched",
"review": {
"reason": "amount_only",
"candidateInvoiceIds": ["inv_01m4tx5nj8emwbyf7y9vcf48bd"],
"candidates": [
{
"invoiceId": "inv_01m4tx5nj8emwbyf7y9vcf48bd",
"number": "GEN-2026-000132",
"brandId": "brd_01m4tx5nj8emwbyf7y9vcf47z0"
}
]
},
"invoiceId": null,
"brandId": null,
"ledgerTransactionId": null,
"payoutItemId": null,
"matchedBy": null,
"matchedAt": null,
"ignoredReason": null,
"version": 1,
"createdAt": "2026-11-05T09:00:00.000Z",
"updatedAt": "2026-11-05T09:00:00.000Z"
}
],
"has_more": false,
"next_cursor": null
}
bank_statements_lines_match
Match a bank statement line to an invoice. Operation bank_statements.lines.match · Legal entity level · permission invoices:write · risk tier financial · since M5
Pays an open (or uncollectible) invoice of the entity with a line from the review queue: the transfer's
booking date becomes the payment date and its reference the payment reference, as invoices.mark_paid
records them (Dr bank / Cr receivable, invoice.paid; a past-due or unpaid subscription recovers). The
line's amount must be the invoice's amount due in the same currency: invoices are paid in full only.
Financial tier: an approval policy may require a second person. Dry-run it first.
Annotations: readOnlyHint: false · destructiveHint: false · idempotentHint: false · openWorldHint: false
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
id | ID (bsl_…) | yes | – |
invoiceId | ID (inv_…) | yes | The invoice the line pays: its amount due must equal the line's amount. |
expectedVersion | integer | no | (1–9007199254740991) |
entity_id | ID (ent_…) | no | The legal entity to act on (ent_…), inside your API key's reach. Needed with an organization key; entity and brand keys act on their own entity. |
idempotency_key | string | no | A unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's idempotency_key. (1–255 characters) |
dry_run | boolean | no | true: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default false) |
- Legal entity: pass
entity_idwith an organization key; entity and brand keys act on their own entity. - Idempotency: the result returns the
idempotency_keyused, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours). - Dry run: supported.
dry_run: truechecks permissions and rules and computes the result, then rolls everything back.
Errors
validation_failed: A field is malformed or out of range.resource_not_found: No line, or no issued invoice of this entity, has this ID.bank_statement_line_resolved: The line was matched or ignored already.bank_statement_amount_mismatch: The line's amount isn't the invoice's amount due (full payments only).invoice_status_invalid: The invoice can't be paid: it is paid, voided or a checkout receipt.version_conflict: The line (expectedVersion) or the invoice changed meanwhile; retry.permission_denied: The credentials can't record invoice payments for this entity (invoices:write, finance).
Example
The transfer pays the invoice its amount points to
Arguments:
{
"id": "bsl_01m4tx5nj8emwbyf7y9vcf48bc",
"invoiceId": "inv_01m4tx5nj8emwbyf7y9vcf48bd",
"entity_id": "ent_01jbx4m3v8e9t0s6k2c5n7q1wy",
"idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
Result output:
{
"object": "bank_statement_match",
"line": {
"id": "bsl_01m4tx5nj8emwbyf7y9vcf48bc",
"object": "bank_statement_line",
"entityId": "ent_01m4tx5nj8emwbyf7y9vcf47zm",
"livemode": false,
"importId": "bsi_01m4tx5nj8emwbyf7y9vcf48ba",
"row": 3,
"bookingDate": "2026-11-04",
"amount": {
"amount": "450000000",
"currency": "EUR"
},
"reference": "Invoice 2026-000132",
"counterparty": "Berg Software AG",
"matchStatus": "matched",
"review": {
"reason": "amount_only",
"candidateInvoiceIds": ["inv_01m4tx5nj8emwbyf7y9vcf48bd"],
"candidates": [
{
"invoiceId": "inv_01m4tx5nj8emwbyf7y9vcf48bd",
"number": "GEN-2026-000132",
"brandId": "brd_01m4tx5nj8emwbyf7y9vcf47z0"
}
]
},
"invoiceId": "inv_01m4tx5nj8emwbyf7y9vcf48bd",
"brandId": "brd_01m4tx5nj8emwbyf7y9vcf47z0",
"ledgerTransactionId": "txn_01m4tx5nj8emwbyf7y9vcf48be",
"payoutItemId": null,
"matchedBy": "manual",
"matchedAt": "2026-11-05T10:00:00.000Z",
"ignoredReason": null,
"version": 2,
"createdAt": "2026-11-05T09:00:00.000Z",
"updatedAt": "2026-11-05T10:00:00.000Z"
},
"invoice": {
"id": "inv_01m4tx5nj8emwbyf7y9vcf48bd",
"number": "GEN-2026-000132",
"status": "paid",
"brandId": "brd_01m4tx5nj8emwbyf7y9vcf47z0"
}
}