Skip to content

Import a bank statement

The bank_statements.imports.create operation: POST /api/v1/bank_statements/imports in the REST API and the bank_statements_imports_create tool in the MCP server.

POST/api/v1/bank_statements/imports

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 as YYYY-MM-DD, DD.MM.YYYY or with slashes (dateFormat required); decimalSeparator . or ,. A file with an unreadable row is refused whole (bank_statement_invalid, rows in details.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_paid would on the booking date (invoice.paid; a past-due subscription recovers). Every other line waits in the review queue (bank_statements.lines.list with matchStatus=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.

At a glance

  • REST: POST /api/v1/bank_statements/imports
  • MCP tool: bank_statements_imports_create
  • Operation ID: bank_statements.imports.create
  • Scope: Legal entity
  • Permission: invoices:write
  • Risk tier: financial
  • Dry run: Supported (send Ownrecord-Dry-Run: true)
  • Idempotency: Idempotency-Key required
  • Modes: Test and live
  • Authentication: API key with the invoices:write scope
  • Since: M5

Request

Body

A JSON object (Content-Type: application/json):

FieldTypeRequiredDescription
csvstringYesThe statement as CSV text: a header row, then one booked transaction per row (booking date, signed amount, reference, optionally counterparty and currency).
currencystringYesThe bank account's currency (rows without a currency column).
filenamestringNo
delimiterone of ,, ;, No,, ; or a tab. Default: detected from the header.
dateFormatone of YYYY-MM-DD, DD.MM.YYYY, DD/MM/YYYY, MM/DD/YYYYNoDefault: YYYY-MM-DD, or DD.MM.YYYY when the dates have dots. Dates with slashes need it.
decimalSeparatorone of ., ,NoDefault: , in ;-separated files, else ..
columnsobjectNoHeader names to use when the recognised ones don't fit (e.g. { reference: "Remittance" }).
columns.bookingDatestringNo
columns.amountstringNo
columns.referencestringNo
columns.counterpartystringNo
columns.currencystringNo

Response

201 Created with a JSON object:

FieldTypeDescription
idbsi_… ID
object"bank_statement_import"
entityIdent_… ID
livemodeboolean
format"csv"
filenamestring or null
currencystring
lineCountintegerTransactions in the file.
countsobjectLines by match status (kept current as lines are matched or ignored); duplicates were skipped.
counts.importedinteger
counts.duplicatesinteger
counts.matchedinteger
counts.partialinteger
counts.unmatchedinteger
counts.ignoredinteger
fromstring or null
tostring or null
optionsobject
options.delimiterone of ,, ;,
options.dateFormatone of YYYY-MM-DD, DD.MM.YYYY, DD/MM/YYYY, MM/DD/YYYY or null
options.decimalSeparatorone of ., , or null
options.columnsobject
options.columns.bookingDatestring or null
options.columns.amountstring or null
options.columns.referencestring or null
options.columns.counterpartystring or null
options.columns.currencystring or null
importedByobject
importedBy.typestring
importedBy.idstring
versioninteger
createdAtdate-time
updatedAtdate-time
paidInvoiceIdsarray of inv_… IDThe invoices this import paid automatically.

Examples

Import a statement: one transfer pays its invoice, two wait for review

HTTP
POST /api/v1/bank_statements/imports
Authorization: Bearer or_test_…
Idempotency-Key: 3f1c9a52-7d0e-4b8f-9a61-0c2d5e8b7f14
Content-Type: application/json

{
  "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"
}

Response (201):

JSON
{
  "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"]
}

Errors

CodeHTTP statusWhenWhat to do
validation_failed400A field is malformed or out of range.Fix the fields listed in details.issues and send the request again.
bank_statement_invalid400The CSV can't be read: a missing column, a bad date or amount (details.errors lists the rows).Fix the rows listed in details.errors (or name the columns, date format and decimal separator) and import the whole file again. Nothing was imported.
bank_statement_already_imported409This exact file was imported before (details.import_id).Open the earlier import (details.import_id) instead. Overlapping statements with different files are fine: their common lines are skipped.
version_conflict409An invoice or line changed at the same time (another import or payment); retry.Fetch the object again and retry the change.
permission_denied403The credentials can't record invoice payments for this entity (invoices:write, finance).Ask an organization owner or admin for a role or scope that allows this action.

It can also return these common errors: api_version_unsupported, invalid_json, unsupported_media_type, authentication_required, api_key_invalid, scope_required, resource_not_found, idempotency_key_required, idempotency_key_reused, idempotency_in_progress, approval_required, approval_rejected, approval_expired, stale_approval, approval_policy_denied, rate_limited, internal_error.