Menu

Supplier payment files

Betalfil (pain.001) for supplier invoices: preview what can be paid, create a batch, download the file for the bank, cancel.

Endpoints


GET /api/v1/companies/:companyId/supplier-payment-batches

supplier-payment-batches.list · scope suppliers:read

List supplier payment batches (betalfiler), newest first, with settlement progress.

Returns the company's payment batches, newest first, cursor-paginated: status, total, item count, how many member invoices are settled (derived from the live invoices), download count and the member supplier_invoice_ids. Pass next_cursor from the answer as cursor to get the next page; it is null on the last page.

Use when: Checking which betalfiler exist, whether one has been downloaded, or which invoices are already in an active batch.

Don't use for: The lines of one batch (GET /supplier-payment-batches/{id}).

Pitfalls

  • next_cursor rides in data (not meta): pass it back as ?cursor= until it is null.
  • settled_count counts invoices with nothing left to pay, however they were settled; a created batch is not proof the bank executed it.

Risk: low · Idempotent: yes · Reversible: no · Dry-run supported: no

Query parameters

NameTypeRequiredDescription
status"created" | "cancelled" | "all"nocreated (active), cancelled, or all (default).
limitnumbernoPage size, 1-100 (default 50).
cursorstringnonext_cursor from the previous page. Omit for the first page.

Response fields

NameType
supplier_payment_batchesobject[]
next_cursorstring | null

Example response

{
  "data": {
    "supplier_payment_batches": [
      {
        "supplier_payment_batch_id": "5b0c…",
        "format": "pain001",
        "status": "created",
        "currency": "SEK",
        "total_amount": 12500,
        "item_count": 2,
        "settled_count": 0,
        "msg_id": "ACCOUNTED-5566778899-B5B0C1A2F",
        "file_generated_at": null,
        "download_count": 0,
        "created_at": "2026-09-25T09:00:00Z",
        "cancelled_at": null,
        "supplier_invoice_ids": [
          "9e2f…",
          "0a7d…"
        ]
      }
    ],
    "next_cursor": null
  },
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}

GET /api/v1/companies/:companyId/supplier-payment-batches/:id

supplier-payment-batches.get · scope suppliers:read

Read one supplier payment batch (betalfil) with its lines and live settlement.

Returns the batch, the company bank details it debits (as snapshotted at creation), and one line per invoice: amount, payment date, payee, reference, and the invoice's live status and remaining amount. file names the download filename, its content type and the v1 path that serves the file (available only while the batch is not cancelled).

Use when: Checking what a betalfil pays, or which of its invoices are settled.

Don't use for: Getting the file itself: GET /supplier-payment-batches/{id}/file.

Pitfalls

  • The payee and amount per line are the snapshot the file pays, even if the supplier's details changed since.

Risk: low · Idempotent: yes · Reversible: no · Dry-run supported: no

Response fields

NameTypeDescription
supplier_payment_batch_idstring
handlestring (optional)Typed handle of this supplier payment batch: spb_ plus its id as 32 lowercase hex. Accepted wherever the id is.
format"pain001" | "bg_lb"pain001: ISO 20022 pain.001.001.03 XML. bg_lb: Bankgirot's LB file (80-character records, ISO 8859-1), for Svea Bank, which takes no pain.001.
status"created" | "cancelled"
currencystring
total_amountnumber
item_countnumber
settled_countnumberMember invoices with nothing left to pay, from the live invoices (paid via mark-paid or bank matching).
msg_idstringpain.001 MsgId, fixed at creation; the bank de-duplicates on it. An LB file carries no MsgId.
file_generated_atstring | nullLast download of the file, or null if never downloaded.
download_countnumber
created_atstring
cancelled_atstring | null
supplier_invoice_idsstring[]
debtorobject
itemsobject[]
fileobject

Example response

{
  "data": {
    "supplier_payment_batch_id": "5b0c…",
    "format": "pain001",
    "status": "created",
    "currency": "SEK",
    "total_amount": 12500,
    "item_count": 2,
    "settled_count": 0,
    "msg_id": "ACCOUNTED-5566778899-B5B0C1A2F",
    "file_generated_at": null,
    "download_count": 0,
    "created_at": "2026-09-25T09:00:00Z",
    "cancelled_at": null,
    "supplier_invoice_ids": [
      "9e2f…",
      "0a7d…"
    ],
    "debtor": {
      "name": "Testbolaget AB",
      "iban": "SE35 **** 0003",
      "bic": "ESSESESS"
    },
    "items": [
      {
        "supplier_payment_batch_item_id": "71c4…",
        "supplier_invoice_id": "9e2f…",
        "supplier_invoice_number": "CD3014794407",
        "arrival_number": 12,
        "amount": 7500,
        "payment_date": "2026-10-01",
        "payee_name": "Derome Bygg AB",
        "payee": {
          "type": "bankgiro",
          "label": "BG 5050-1055"
        },
        "reference": {
          "type": "invoice_number",
          "value": "CD3014794407"
        },
        "invoice_status": "approved",
        "remaining_amount": 7500,
        "settled": false
      }
    ],
    "file": {
      "filename": "betalfil_20260925_5b0c1a2f.xml",
      "content_type": "application/xml",
      "available": true,
      "download": "/api/v1/companies/{companyId}/supplier-payment-batches/{supplier_payment_batch_id}/file"
    }
  },
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}

GET /api/v1/companies/:companyId/supplier-payment-batches/:id/file

supplier-payment-batches.file · scope suppliers:write

Download the payment file (pain.001, or the LB file for Svea Bank) of a supplier payment batch.

Returns the batch's payment file inline as content (a string), with filename, content_type, charset and sha256, in the same shape as the salary payment file: pain.001 XML written as UTF-8, or Bankgirot's LB file (format bg_lb, text/plain) written as ISO 8859-1. The file regenerates from the stored batch, so every download is byte-identical (same MsgId) and the bank's duplicate detection works. Each call records the download on the batch (file_generated_at, download_count). Upload the file in the bank's file channel, where the payments are signed; nothing is sent to the bank by this call and nothing is booked.

Use when: The batch is created and the user (or their payment operator) needs the file to upload in the bank.

Don't use for: Creating the batch (POST /supplier-payment-batches) or marking invoices paid (mark-paid after the bank executed).

Pitfalls

  • Write content to filename in charset (UTF-8 for pain001, ISO 8859-1 for bg_lb with its CRLF line endings), exactly as returned; do not re-indent or re-encode the file.
  • A cancelled batch answers 409 SI_BATCH_CANCELLED: its file is never served again.
  • Uploading the same file twice is caught by most banks through the MsgId, but not all: check download_count and the bank before re-uploading.
  • Needs suppliers:write although it is a GET: the file is a payment instruction and the download is recorded.

Risk: low · Idempotent: yes · Reversible: no · Dry-run supported: no

Response fields

NameTypeDescription
supplier_payment_batch_idstring
format"pain001" | "bg_lb"pain001: ISO 20022 pain.001.001.03 XML. bg_lb: Bankgirot's LB file (80-character records, ISO 8859-1), for Svea Bank, which takes no pain.001.
filenamestring
content_type"application/xml" | "text/plain"
charset"utf-8" | "iso-8859-1"How content becomes the bytes the bank takes.
contentstring
sha256stringLowercase hex SHA-256 over the file bytes as encoded for the bank (UTF-8 for pain001, ISO 8859-1 for bg_lb).
msg_idstring
item_countnumber
total_amountnumber
currencystring
download_countnumberDownloads including this one.

Example response

{
  "data": {
    "supplier_payment_batch_id": "5b0c…",
    "format": "pain001",
    "filename": "betalfil_20260925_5b0c1a2f.xml",
    "content_type": "application/xml",
    "charset": "utf-8",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Document xmlns=\"urn:iso:std:iso:20022:tech:xsd:pain.001.001.03\">…",
    "sha256": "3f9a…",
    "msg_id": "ACCOUNTED-5566778899-B5B0C1A2F",
    "item_count": 2,
    "total_amount": 12500,
    "currency": "SEK",
    "download_count": 1
  },
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}

POST /api/v1/companies/:companyId/supplier-payment-batches

supplier-payment-batches.create · scope suppliers:write

Create a supplier payment file (betalfil: pain.001, or an LB file for Svea Bank) for one or more supplier invoices.

Creates a payment batch: an immutable snapshot of one credit transfer per invoice (amount, payment date, the supplier's bankgiro / plusgiro / bank account, OCR or invoice-number reference) and the company's own bank details as debtor, with a pain.001 MsgId fixed at creation. The file takes the form the company's bank accepts (format: pain001, or bg_lb, Bankgirot's LB file, for Svea Bank, which takes no pain.001). Every invoice is re-read and re-checked inside one transaction, so an invoice settled or already batched meanwhile is refused. Books nothing and marks nothing paid. Download the file with GET /supplier-payment-batches/{id}/file and upload it in the bank, where the payments are signed; afterwards settle each invoice with mark-paid or bank matching. Idempotent. Dry-runnable.

Use when: The user wants to pay approved supplier invoices through their bank's file upload (typically the weekly or monthly payment run).

Don't use for: Marking invoices paid (POST /supplier-invoices/{id}/mark-paid), paying salaries (salary-runs/{id}/payment-file) or sending anything to the bank: this only produces the file.

Pitfalls

  • Money leaves the company's account once the file is uploaded and signed in the bank: preview first (POST /supplier-payment-batches/preview) and check amounts and payees.
  • An invoice already in an active batch answers 409 SI_BATCH_DUPLICATE_INVOICE with details.invoices; resend with confirm_already_batched true only when paying it twice is intended, otherwise cancel the old batch.
  • Incomplete company bank details answer 400 SI_BATCH_DEBTOR_INCOMPLETE; details.missing is iban, bic, org_number, swedbank_ids, nordea_signer_id, nordea_agreement_id or bankgiro. iban and bic concern the paying account, the company's primary bank account (the one salaries are booked on), named in details.account: fill in its IBAN or BIC under Inställningar → Fakturor, Bankkonton för kundfakturor. The rest are company settings: swedbank_ids means a Swedbank company lacks swedbank_signer_id or swedbank_corporate_pay_id, nordea_signer_id that a Nordea company lacks its Signer ID, nordea_agreement_id that it has the Signer ID but lacks its CCM agreement id, bankgiro that a Svea Bank company lacks the bankgiro its LB file is sent from.
  • An ineligible invoice fails the whole request with 400 SI_BATCH_INELIGIBLE_INVOICE and a reason per invoice; amount above the remaining amount answers 400 SI_BATCH_AMOUNT_EXCEEDS_REMAINING.
  • A Swedbank company (swedbank_signer_id set, or swedbank_ids missing) can only pay bank accounts in a file: a bankgiro or plusgiro payee is ineligible with reason swedbank_iso2_giro_payee. A Svea Bank company's LB file pays bankgiro and plusgiro only: a bank-account payee is ineligible with reason lb_bank_account_payee. Leave those invoices out (the preview already does) and create the batch with the rest.
  • A payment_date in the past is moved to today (banks reject passed execution dates). Only SEK invoices; at most 100 per batch.
  • Between two requests (dry run, then create) a supplier's bank details can change: pass expected_payees from the dry run's items (payee.fingerprint, amount) and create answers 409 SI_BATCH_PAYEE_CHANGED instead of paying a changed account. A staged MCP create is pinned this way automatically.

Risk: high · Idempotent: yes · Reversible: no · Dry-run supported: yes · Stage for approval: yes (?stage=true)

Query parameters

NameTypeRequiredDescription
dry_runstringnotrue (any case) previews the write without committing it, like the X-Dry-Run: true header. Any other value commits.
stagestringnotrue stages the write for approval instead of committing it: 202 with the pending operation to approve via POST /pending-operations/{id}/approve. Absent or false commits; other values are 400. A reason in the body (why you propose it, at most 500 characters) is shown to the approver as agent_reason and kept with the decision.

Request body

NameTypeRequiredDescription
format"pain001" | "bg_lb"noDeprecated and ignored: the company's bank decides the file form. pain001 (ISO 20022 pain.001.001.03) everywhere except Svea Bank, which takes only bg_lb (Bankgirot's LB file). The preview and create answers name it in format.
itemsobject[]yesOne line per supplier invoice, 1-100.
confirm_already_batchedbooleannotrue includes invoices that already sit in another active batch (pays them twice if both files are uploaded).
expected_payeesobject[]noOptional lock: per invoice the payee fingerprint and amount a dry run showed. Create refuses with 409 SI_BATCH_PAYEE_CHANGED if either changed. Staging over MCP fills this in itself.

Response fields

NameTypeDescription
supplier_payment_batch_idstring
handlestring (optional)Typed handle of this supplier payment batch: spb_ plus its id as 32 lowercase hex. Accepted wherever the id is.
msg_idstring
format"pain001" | "bg_lb"pain001: ISO 20022 pain.001.001.03 XML. bg_lb: Bankgirot's LB file (80-character records, ISO 8859-1), for Svea Bank, which takes no pain.001.
status"created"
currencystring
total_amountnumber
item_countnumber
created_atstring
fileobject

Example request

{
  "items": [
    {
      "supplier_invoice_id": "9e2f…"
    },
    {
      "supplier_invoice_id": "0a7d…",
      "amount": 5000
    }
  ]
}

Example response

{
  "data": {
    "supplier_payment_batch_id": "5b0c…",
    "msg_id": "ACCOUNTED-5566778899-B5B0C1A2F",
    "format": "pain001",
    "status": "created",
    "currency": "SEK",
    "total_amount": 12500,
    "item_count": 2,
    "created_at": "2026-09-25T09:00:00Z",
    "file": {
      "filename": "betalfil_20260925_5b0c1a2f.xml",
      "download": "/api/v1/companies/{companyId}/supplier-payment-batches/{supplier_payment_batch_id}/file"
    }
  },
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}

POST /api/v1/companies/:companyId/supplier-payment-batches/:id/cancel

supplier-payment-batches.cancel · scope suppliers:write

Cancel (makulera) a supplier payment batch.

Marks an active batch cancelled: Accounted stops serving its file and its invoices can go into a new batch. The batch and its lines are kept (they are underlag for the payment instruction). A file already uploaded to the bank is NOT recalled: stop those payments in the bank. Cannot be undone; create a new batch instead. Idempotent. Dry-runnable.

Use when: A betalfil was created by mistake or with wrong amounts, before (or instead of) uploading it.

Don't use for: Stopping a payment the bank already has (do that in the bank) or un-paying an invoice.

Pitfalls

  • An already cancelled batch answers 409 SI_BATCH_ALREADY_CANCELLED.
  • download_count above 0 means the file may already be at the bank: check there too.

Risk: medium · Idempotent: yes · Reversible: no · Dry-run supported: yes · Stage for approval: yes (?stage=true)

Query parameters

NameTypeRequiredDescription
dry_runstringnotrue (any case) previews the write without committing it, like the X-Dry-Run: true header. Any other value commits.
stagestringnotrue stages the write for approval instead of committing it: 202 with the pending operation to approve via POST /pending-operations/{id}/approve. Absent or false commits; other values are 400. A reason in the body (why you propose it, at most 500 characters) is shown to the approver as agent_reason and kept with the decision.

Response fields

NameType
supplier_payment_batch_idstring
status"cancelled"
cancelled_atstring | null

Example response

{
  "data": {
    "supplier_payment_batch_id": "5b0c…",
    "status": "cancelled",
    "cancelled_at": "2026-09-25T10:00:00Z"
  },
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}

POST /api/v1/companies/:companyId/supplier-payment-batches/preview

supplier-payment-batches.preview · scope suppliers:read

Check which supplier invoices can go into a payment file (betalfil), with amounts, payees and warnings.

Evaluates the given supplier invoices exactly as create will: eligible lines with the default amount (the remaining amount), payment date (the due date, the banking day before it when it falls on a weekend or holiday, or today when that has passed), payee (bankgiro, plusgiro or bank account from the supplier) and reference (OCR when valid, else the invoice number), plus non-blocking warnings; excluded invoices with the reason; the file form the company's bank takes (format: pain001, or bg_lb for Svea Bank); and whether the company's own bank details are complete. The file pays from the company's primary bank account, the account salaries are booked on, with that account's IBAN and BIC; org number, and the bankgiro an LB file is sent from, come from company settings. Reads only; creates nothing.

Use when: Before creating a payment batch, to see what would be paid and what blocks it.

Don't use for: Creating the batch (POST /supplier-payment-batches) or listing unpaid supplier invoices (GET /supplier-invoices).

Pitfalls

  • Excluded reasons: not_payable (draft, paid, credited...), nothing_remaining, credit_note, foreign_currency (only SEK), payee_missing / payee_invalid (fix the supplier's bankgiro, plusgiro or clearing + account number), reference_missing (no valid OCR and no supplier invoice number: add one of them to the invoice), payee_unconfirmed / payee_rejected (the invoice states bank details the supplier card lacks and a person has not approved them, or rejected them: a person decides in Accounted under Att göra; gnubok_confirm_supplier_payee stages the approval), attest_required (the attest policy of the company requires attest for the invoice and it has not been given: an attester approves it first), not_found, in_bank_payment, swedbank_iso2_giro_payee (the company pays through Swedbank, whose ISO 2.0 file agreement pays to bank accounts only: a supplier with a bankgiro or plusgiro is left out; pay those invoices with a bank payment or in the internet bank), lb_bank_account_payee (the company's bank takes only an LB file, which here pays to bankgiro and plusgiro only: a supplier paid to a bank account is left out; pay it in the internet bank).
  • debtor_ok false means create will refuse with SI_BATCH_DEBTOR_INCOMPLETE: debtor_missing names what to fill in (iban or bic: the paying account, named in debtor_account, has no IBAN or its bank cannot be determined; fill it in on that account under Inställningar → Fakturor, Bankkonton för kundfakturor, or make another account primary under Inställningar → Bokföring. org_number, swedbank_ids: a Swedbank company's swedbank_signer_id and swedbank_corporate_pay_id, which Swedbank assigns and refuses a file without, nordea_signer_id and nordea_agreement_id: a Nordea company's Signer ID and CCM agreement id, which Nordea assigns and refuses a file without (nordea_signer_id is named while the Signer ID is missing, nordea_agreement_id when only the agreement id is), or bankgiro: the company's bankgiro, which an LB file is sent from).
  • already_batched is a warning here but a refusal at create unless confirm_already_batched is true: paying the same invoice twice is the risk.
  • Only SEK invoices; at most 100 per call.

Risk: low · Idempotent: yes · Reversible: no · Dry-run supported: no

Request body

NameTypeRequiredDescription
format"pain001" | "bg_lb"noDeprecated and ignored: the company's bank decides the file form. pain001 (ISO 20022 pain.001.001.03) everywhere except Svea Bank, which takes only bg_lb (Bankgirot's LB file). The preview and create answers name it in format.
supplier_invoice_idsstring[]yesThe supplier invoices to evaluate (supplier_invoice_id), 1-100.

Response fields

NameTypeDescription
eligibleobject[]
excludedobject[]
format"pain001" | "bg_lb"The file form the company's bank takes, which create will write.
total_amountnumber
currency"SEK"
debtor_okboolean
debtor_missing"iban" | "bic" | "org_number" | "swedbank_ids" | "nordea_signer_id" | "nordea_agreement_id" | "bankgiro" | null
debtor_accountobject | nullWith debtor_missing iban or bic: the paying account that lacks it. Null otherwise.

Example request

{
  "supplier_invoice_ids": [
    "9e2f…"
  ]
}

Example response

{
  "data": {
    "eligible": [
      {
        "supplier_invoice_id": "9e2f…",
        "supplier_name": "Derome Bygg AB",
        "supplier_invoice_number": "CD3014794407",
        "amount": 737.5,
        "payment_date": "2026-10-01",
        "payee": {
          "type": "bankgiro",
          "label": "BG 5050-1055"
        },
        "reference": {
          "type": "invoice_number",
          "value": "CD3014794407"
        },
        "warnings": [
          "payee_city_missing"
        ],
        "active_supplier_payment_batch_id": null
      }
    ],
    "excluded": [],
    "format": "pain001",
    "total_amount": 737.5,
    "currency": "SEK",
    "debtor_ok": true,
    "debtor_missing": null,
    "debtor_account": null
  },
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}