← Dokumentation / Leitfäden
Bank & payment imports
camt.053 statements, Stripe CSV, PSP settlement reconciliation and custom JSON feeds.
All imports land as bank transactions on a bank account (bank/accounts/create). Transactions carry an
externalId; re-importing the same file is safe — rows whose (bankAccountId, externalId) already exist are
skipped and reported in the skipped counter. Imported transactions start in status new and are posted to the
ledger only when matched (bank/transactions/match, with bank/transactions/suggest-matches for candidates).
The web app exposes the same imports under Bank → Import file (file upload, template selector).
Import templates
An import template names a data source, lists the fields the source delivers, and maps the fields that carry money
to ledger accounts. Templates are managed under Bank → Import templates and via
bank/import-templates/create|update|delete|get|list.
POST /v1/bank/import-templates/create
{
"name": "Stripe payments export",
"type": "stripe",
"fields": [
{ "name": "id" },
{ "name": "Created date (UTC)" },
{ "name": "Amount" },
{ "name": "Fee", "accountCode": "6800" },
{ "name": "Amount Refunded" }
],
"metaFields": ["order_id"]
}
typeis one ofstripe,iso20022orbank_connection.- Each field has a
nameand an optionalaccountCode. Only the fields that carry money accept an account: StripeAmount,FeeandAmount Refunded; camt.053Ntry/Amt; bank feedtransaction_amount.amount. The account must exist in the chart of accounts (create it withledger/accounts/create). fieldsmay be omitted; it then defaults to the standard field list of the type: the column names of the Stripe Payments → Export file (without the 19Card …columns, which the form also leaves unticked by default), the camt.053 elements every statement carries (Stmt/Id,Stmt/Acct/Id/IBAN,Stmt/Bal/…,Ntry/Amt,Ntry/CdtDbtInd,Ntry/Sts,Ntry/BookgDt), or the attributes a PSD2 bank feed returns per transaction. Add or remove entries to match your file: the importer also reads the optional camt.053 elementsNtry/ValDt,Ntry/NtryRef,Ntry/AcctSvcrRef,Ntry/AddtlNtryInf,TxDtls/Refs/EndToEndId,TxDtls/Refs/TxId,TxDtls/RltdPties/Dbtr/Nm,TxDtls/RltdPties/DbtrAcct/Id/IBAN,TxDtls/RltdPties/Cdtr/Nm,TxDtls/RltdPties/CdtrAcct/Id/IBAN,TxDtls/RmtInf/UstrdandTxDtls/AddtlTxInf.- A Stripe
Customer Emailfield may carry"createPartner": true. The import then creates a customer (partner of type person, flagged as customer) for every email in the file that no existing partner has, usingCustomer Descriptionas the name (the email when it is empty) and theCard Address …columns as the address when the file contains them. Existing partners are matched by email, case-insensitively. The response reports the count incustomersCreated. metaFields(Stripe only) lists the metadata keys your charges carry. Stripe exports each key as a<key> (metadata)column; the list is free-form and can be long.invoiceItemId(Stripe only, optional) is a catalog item. When set, every invoice and credit note line the import creates references that item (its posting and, wheninvoiceVatRatePercentis empty, its VAT rate); the line text still comes from the charge.companyMetaField(Stripe only) names one of those keys as the company flag. When a charge carriestrue,1,yes,company,businessorb2bin that column, the customer created for it is a partner of type company instead of person.invoiceMetaField(Stripe only) names one of those keys, for example an order number, andinvoiceVatRatePercentthe VAT rate for invoices created from it. On import every charge and refund row is grouped by the value of that key:- a value that matches an existing sale invoice — a sales order whose
externalRefis that value (ecommerce/orders/create, any channel) or an invoice whosefullNumberis that value — links the group to that invoice; - a value with no invoice creates one: partner from
Customer Email(created when missing, as forcreatePartner), one line per charge (Checkout Line Item SummaryorDescriptionas the text, the charge amount as a VAT-inclusive price atinvoiceVatRatePercent), issue date = the first charge date, VAT treatment from the company and the card country. The invoice is issued and posted at once, and a sales order with channelstripeand that value asexternalRefis recorded so later imports link instead of creating; - each charge in the group is then matched to the invoice as a payment (posting the receipt); each refund
creates an issued credit note against the invoice for the refunded amount and matches the refund to it.
Counts come back as
invoicesCreated,invoicesLinked,creditNotesCreatedandpaymentsMatched; groups that could not be processed (no customer email, mixed currencies, a linked invoice that is still a draft or already fully paid) are listed inwarningsand left asnewbank transactions. Do not also mapAmountto a ledger account in the same template: a charge matched to an invoice is not posted a second time, but an unmatched one would be.
- a value that matches an existing sale invoice — a sales order whose
- Template names are unique per company.
- camt.053 and bank-connection templates carry the same options, read from the statement instead of Stripe columns:
- Create missing partners:
createPartneron the debtor name row (TxDtls/RltdPties/Dbtr/Nm, feeddebtor.name) creates a customer for every unknown payer of incoming money; on the creditor name row (TxDtls/RltdPties/Cdtr/Nm, feedcreditor.name) a supplier for every unknown payee of outgoing money. Partners are recognised by IBAN (stored inpartner_bank_accounts), then by exact name; a new partner is a company when the name carries a legal form (UAB, MB, SIA, GmbH, Ltd, …), otherwise a person. The count comes back ascustomersCreated(file import) orpartnersCreated(feed sync). - Link invoices by reference:
invoiceMetaFieldset to a remittance or reference row (TxDtls/RmtInf/Ustrd,TxDtls/RmtInf/Strd/CdtrRefInf/Ref,TxDtls/Refs/EndToEndId; feedremittance_information,reference_number) matches every new bank line whose reference, remittance or description contains the number of an open issued sale invoice (money in) or registered purchase invoice (money out), and posts the payment. WithadvanceInvoices: truean unmatched incoming payment from a known partner creates an issued advance invoice (typeadvance) for the amount atinvoiceVatRatePercentor theinvoiceItemIdrate and matches the payment to it; the partner must be known, so tick the debtor row too. - Posting rules by transaction code: besides
Ntry/Amt/transaction_amount.amount, the field list has rule rowsNtry/BkTxCd=CHRG,=INTR,=TAXE,Ntry/CdtDbtInd=DBIT,=CRDT(feed:bank_transaction_code=…,credit_debit_indicator=…). A line is posted to the account of the first rule it matches: its bank transaction code family, then its direction, then the plain amount row. Rule rows are not checked against the file. - Bank charges partner:
createPartneron the…=CHRGrule row creates a supplier named after the bank (statementStmt/Acct/Svcr/FinInstnId/Nm, or the connection's bank, or the ledger bank account name) and books every charge with that partner. - Bank-connection templates are chosen per feed account with
bank/feeds/accounts/configure(Bank → Connections in the app), which also setssyncSchedule(manual,daily,weekly,monthly): the API syncs accounts with a schedule by itself once their period has passed. Templates are applied on everybank/feeds/sync; the sync response then also reportsposted,partnersCreated,invoicesLinked,invoicesCreated,paymentsMatchedandwarnings.
- Create missing partners:
Pass templateId to bank/statements/import instead of format: the template's type selects the parser, and the
file must contain every field listed in the template — a file missing any of them is rejected with HTTP 422 and
the missing column or element names. Metadata fields are not required to be present. Bank-connection templates
describe a live PSD2 feed and cannot be used for file import.
Every movement produced from a field that has an accountCode is posted at import time as one journal
transaction: money in debits the bank account's ledger account and credits the mapped account; money out debits
the mapped account and credits the bank account's ledger account. Amounts are converted to the base currency at
the movement date. The bank transaction is then matched to that journal transaction
(matchedDocumentType = journal_transaction) and no longer offered for invoice matching. The response
reports the count in posted. Movements from unmapped fields stay new and are matched to invoices as before —
for example map Fee to the PSP fee expense account and leave Amount unmapped so charges are still matched
to sale invoices.
POST /v1/bank/statements/import
{
"bankAccountId": "…",
"templateId": "…",
"content": "id,Created date (UTC),Amount,…"
}
ISO 20022 camt.053 (open banking XML)
Lithuanian banks (Swedbank, SEB, Luminor, Šiaulių bankas, …) let you download account statements as ISO 20022 camt.053 XML from their internet banking — usually under statement export/download, format "ISO XML" or "camt.053". The same format is returned by PSD2 account-information APIs.
POST /v1/bank/statements/import
{
"bankAccountId": "…",
"format": "camt053",
"content": "<?xml version=\"1.0\"…>…"
}
- A file may contain several statements; each statement's IBAN must match the bank account's IBAN (statements without an IBAN, or accounts without one, are accepted as-is).
- Entry references (
AcctSvcrRef/NtryRef, falling back to a content hash) becomeexternalId. - The response echoes per-statement metadata: statement id, period, opening/closing balances, transaction count.
- Counterparty name, IBAN and payment purpose are extracted per entry for matching.
Payments in the other direction are exported as pain.001 via bank/payments/export.
Stripe CSV
Export from the Stripe dashboard — either report works:
- Reports → Balance → Itemized balance change from activity (recommended): columns
balance_transaction_id, created_utc, currency, gross, fee, net, reporting_category, description. - Payments → Export: columns
id, Created (UTC), Amount, Fee, Currency, Description, Customer Description.
POST /v1/bank/statements/import
{
"bankAccountId": "…",
"format": "stripe-csv",
"content": "balance_transaction_id,created_utc,currency,gross,fee,net,…"
}
Create a dedicated bank account for Stripe (e.g. name "Stripe", GL account 2710 or its own subaccount) — the Stripe balance behaves like a bank account: charges flow in, fees are deducted, payouts transfer the balance to your real bank.
Import behaviour:
- Each balance transaction becomes one bank transaction for the gross amount
(
externalId= balance transaction id). - A non-zero fee becomes a second transaction with the opposite sign (
externalId=<id>:fee, counterparty "Stripe") — so fees can be matched/posted as expenses separately from revenue. Fees returned on refunds come in as positive amounts. - Payout rows import as single negative transactions; match them against the corresponding incoming transaction on your real bank account statement.
- Zero-amount rows are skipped; the date is taken from
created_utc(UTC). - Payments-export rows that moved no money are skipped:
Captured = false(authorizations/delayed captures) andStatusFailed/Canceled. - A non-zero Amount Refunded becomes a third, negative transaction (
externalId=<id>:refund) datedRefunded date (UTC)— so partial and full refunds embedded in payment rows are not lost.
PSP settlement reconciliation (Stripe payout reports)
For splitting a lump-sum payout into its underlying orders, refunds, fees and chargebacks, use the settlement endpoints instead of the plain statement import. Two Stripe exports are accepted (detected automatically):
- Reports → Payouts → Payout reconciliation, itemized (report types
payout_reconciliation.itemized.*orpayout_reconciliation.by_id.itemized.*) — exact, one row per balance transaction; preferred on live accounts. - Payments → Export (unified payments) — the charge-level export; works in test/sandbox mode where payout
reconciliation is unavailable. Captured charges are grouped by the payout id in the
Transfercolumn; uncaptured/failed rows are skipped (skippedNotSettled); a non-zeroAmount Refundedbecomes a synthetic refund line in the charge's payout batch — an approximation, since the refund may really have settled in a later payout. Match references come from the charge id,PaymentIntent ID,Invoice Number,Client Reference IDand every… (metadata)column (e.g. an order number in metadata).
One CSV can span many payouts. Stripe downloads the itemized report one file per section (…_charge_…,
…_refund_…, …_fee_…); import them all — rows for an already-imported payout merge into the existing batch
(reported in the updated counter) as long as it has not been posted yet, and batch totals are recomputed.
POST /v1/bank/settlements/import
{
"bankAccountId": "…",
"provider": "stripe",
"content": "balance_transaction_id,created_utc,…,reporting_category,…,automatic_payout_id,…"
}
Import behaviour:
- Rows are grouped by
automatic_payout_idinto settlement batches — one batch per payout, with gross/fee/net totals (sum of rownet= the amount that hits your bank). Re-importing a payout is skipped (skippedcounter). Rows not yet assigned to a payout and thepayoutrows themselves are skipped and counted separately. - Every charge/refund/dispute row is auto-matched to a sale invoice using, in order: an e-commerce order's
externalRef(any value fromorder_id,payment_intent_id,source_id,charge_idor any*_metadata[...]column), an invoicefullNumberappearing in those columns, and — for refunds and chargebacks — thecharge_idof a previously matched charge (same file or earlier imports). - Review with
bank/settlements/list/bank/settlements/get; fix leftovers withbank/settlements/match { lineId, invoiceId }(orinvoiceId: nullto unmatch).
POST /v1/bank/settlements/post { id, date?, commissionPercent? } posts the whole batch as one balanced
journal transaction and settles the matched invoices (paidAmount/paymentStatus, sale_invoice.paid
webhooks):
- Debit the bank account GL for the net payout; debit PSP fees (
settlements.fees, default 6800) for withheld fees and fee rows. - Credit accounts receivable per matched charge; refunds and chargebacks reverse it. Application is capped at each invoice's remaining amount — any excess lands on the suspense account with a warning.
- Unmatched charges: with
commissionPercentset they are split into commission revenue (settlements.commissionRevenue, default 5001) and a seller liability (settlements.sellerPayable, default 4499) — the marketplace flow where collected money mostly belongs to sellers. Without it they are parked onsettlements.suspense(default 4440, advances received). platform_earningrows (Stripe Connect application fees) post to commission revenue;transferrows (payouts to connected sellers) reduce the seller liability.- All four accounts are overridable per company via posting rules (
ledger/posting-rules).
VAT on the commission itself is invoiced separately (issue a commission invoice to the seller); the split only allocates the collected cash. Settlements are posted in the company base currency — foreign-currency payouts must currently be posted manually.
Manual / custom feeds
Anything else can be pushed as plain JSON:
POST /v1/bank/transactions/import
{
"bankAccountId": "…",
"transactions": [
{ "date": "2026-07-01", "amount": "-25.00", "currency": "EUR",
"counterpartyName": "…", "description": "…", "externalId": "unique-ref-1" }
]
}
Provide a stable externalId per transaction to keep re-imports idempotent.