Menu

Bank payments

Betalningar via banken for supplier invoices: prepare and approve payment orders, read their bank status, cancel, check the company verification, and fetch the link where a person signs with BankID. Agents prepare; a person signs.

Endpoints


GET /api/v1/companies/:companyId/payment-orders

payment-orders.list · scope suppliers:read

List bank payment orders (betalningar via banken), newest first.

Returns the company's bank payment orders, newest first, cursor-paginated: status, amount, execution date, the payee as the order carries it (with its check), the reference, the bank's own status, and the supplier invoice each order pays. Filter by one status, by open (everything not yet closed) or by supplier_invoice_id. Pass next_cursor from the answer as cursor to get the next page; it is null on the last page.

Use when: Following up bank payments: what is waiting for approval or signing, what the bank holds, what is paid.

Don't use for: Payment files (betalfiler): GET /supplier-payment-batches. Preparing a payment: POST /payment-orders.

Pitfalls

  • next_cursor rides in data (not meta): pass it back as ?cursor= until it is null.
  • An executed order stays open until its bank debit is matched to the invoice (matched_at); the invoice shows as unpaid until then.
  • outcome_unknown true means the bank may hold the payment while its answer was lost: nobody should pay the invoice again; a person resolves it in Accounted.

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

Query parameters

NameTypeRequiredDescription
status"draft" | "approved" | "submitted" | "awaiting_signature" | "awaiting_second_signer" | "accepted" | "executed" | "rejected" | "cancelled" | "failed" | "open" | "all"noOne status; open (every order not closed: drafts, approved, at the bank, and executed ones whose debit is not matched yet); or all (default).
supplier_invoice_idstringnoOnly the orders that pay this supplier invoice.
limitnumbernoPage size, 1-100 (default 50).
cursorstringnonext_cursor from the previous page. Omit for the first page.

Response fields

NameType
payment_ordersobject[]
next_cursorstring | null

Example response

{
  "data": {
    "payment_orders": [
      {
        "payment_order_id": "7c2e…",
        "supplier_invoice_id": "9e2f…",
        "payment_order_batch_id": null,
        "status": "draft",
        "amount": 737.5,
        "currency": "SEK",
        "requested_execution_date": "2026-10-20",
        "cash_account_id": "41b0…",
        "payee": {
          "type": "bankgiro",
          "label": "BG 5050-1055",
          "name": "Derome Bygg AB",
          "source": "supplier",
          "check": "known"
        },
        "reference": {
          "type": "ocr",
          "value": "4400112233"
        },
        "end_to_end_id": "ACC7C2E1A2F3B4C5",
        "provider_status": null,
        "provider_error_code": null,
        "outcome_unknown": false,
        "approved_at": null,
        "submitted_at": null,
        "signed_at": null,
        "executed_at": null,
        "cancelled_at": null,
        "matched_at": null,
        "created_at": "2026-10-10T09:00:00Z",
        "updated_at": "2026-10-10T09:00:00Z",
        "supplier_invoice": {
          "supplier_invoice_number": "CD3014794407",
          "due_date": "2026-10-20",
          "supplier_name": "Derome Bygg AB"
        }
      }
    ],
    "next_cursor": null
  },
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}

GET /api/v1/companies/:companyId/payment-orders/:id

payment-orders.get · scope suppliers:read

Read one bank payment order.

Returns the order with its payee (as the order carries it, with its check), reference, status, the bank's own status and error code, its timestamps and the supplier invoice it pays.

Use when: Checking where one payment stands.

Don't use for: Several orders at once (GET /payment-orders).

Pitfalls

  • An order of another company answers 404, like one that does not exist.

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

Response fields

NameTypeDescription
payment_order_idstring
handlestring (optional)Typed handle of this payment order: pmt_ plus its id as 32 lowercase hex. Accepted wherever the id is.
supplier_invoice_idstring | null
payment_order_batch_idstring | nullThe signing batch (one BankID signing) the order went to the bank in, once it did.
status"draft" | "approved" | "submitted" | "awaiting_signature" | "awaiting_second_signer" | "accepted" | "executed" | "rejected" | "cancelled" | "failed"draft: prepared, not attested. approved: attested, waiting for a BankID signing. submitted, awaiting_signature, awaiting_second_signer, accepted: at the bank. awaiting_second_signer: signed once, the bank waits for another signatory; where the bank takes that signature through the API (SEB) they sign in Accounted (Kontrasignera on Betalningar, or a signing link over those orders), elsewhere in the online bank. executed: paid by the bank; the order closes when its debit is matched to the invoice. rejected, cancelled, failed: closed without a payment.
amountnumber
currencystring
requested_execution_datestringYYYY-MM-DD: the day the bank is asked to pay.
cash_account_idstringThe company account the payment leaves from.
payeeobject
referenceobject
end_to_end_idstringAccounted's id for the payment at the bank; the debit on the bank statement carries it.
provider_statusstring | nullThe bank's own status code, verbatim, once the bank has the payment.
provider_error_codestring | nullThe bank's refusal code when it refused or failed the payment.
outcome_unknownbooleantrue while the bank may hold the payment but its answer was lost: a person resolves it in Accounted.
approved_atstring | null
submitted_atstring | null
signed_atstring | null
executed_atstring | null
cancelled_atstring | null
matched_atstring | nullWhen the bank debit was matched to the invoice, which settles the order.
created_atstring
updated_atstring
supplier_invoiceobject | nullThe invoice the order pays, when the answer carries it (lists and reads do; prepare does not).

Example response

{
  "data": {
    "payment_order_id": "7c2e…",
    "supplier_invoice_id": "9e2f…",
    "payment_order_batch_id": null,
    "status": "draft",
    "amount": 737.5,
    "currency": "SEK",
    "requested_execution_date": "2026-10-20",
    "cash_account_id": "41b0…",
    "payee": {
      "type": "bankgiro",
      "label": "BG 5050-1055",
      "name": "Derome Bygg AB",
      "source": "supplier",
      "check": "known"
    },
    "reference": {
      "type": "ocr",
      "value": "4400112233"
    },
    "end_to_end_id": "ACC7C2E1A2F3B4C5",
    "provider_status": null,
    "provider_error_code": null,
    "outcome_unknown": false,
    "approved_at": null,
    "submitted_at": null,
    "signed_at": null,
    "executed_at": null,
    "cancelled_at": null,
    "matched_at": null,
    "created_at": "2026-10-10T09:00:00Z",
    "updated_at": "2026-10-10T09:00:00Z",
    "supplier_invoice": {
      "supplier_invoice_number": "CD3014794407",
      "due_date": "2026-10-20",
      "supplier_name": "Derome Bygg AB"
    }
  },
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}

GET /api/v1/companies/:companyId/payment-orders/availability

payments.availability · scope suppliers:read

Whether the company can pay through its bank from Accounted, and from which accounts.

Answers available (a payment provider serves this installation, the company is on a paid plan and it is not a sandbox), why not when it is false (reason: no_provider, not_in_pilot, subscription, sandbox), the provider, and the company's bank accounts with payable true or a reason (account_disabled, not_sek, iban_missing, bank_unknown, bank_not_supported: the payment provider does not pay from this bank, Svea Bank today). signer_known says whether the calling person has a BankID login on file, so signing needs no typed personnummer. IBANs are masked.

Use when: Before preparing a bank payment: pick a payable cash_account_id.

Don't use for: Payment files, which need no provider (GET /supplier-payment-batches/preview).

Pitfalls

  • available false means POST /payment-orders answers PAYMENTS_UNAVAILABLE; pay with a payment file instead.
  • reason subscription: bank payments are part of the paid plan; the company upgrades under Inställningar, Abonnemang.

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

Response fields

NameTypeDescription
availableboolean
reason"no_provider" | "not_in_pilot" | "subscription" | "sandbox" | nullWhy available is false; null when it is true.
providerstring | null
accountsobject[]
signer_knownboolean

Example response

{
  "data": {
    "available": true,
    "reason": null,
    "provider": "open_payments",
    "accounts": [
      {
        "cash_account_id": "41b0…",
        "name": "Företagskonto",
        "ledger_account": "1930",
        "iban": "SE35 **** 0003",
        "bank_name": "Swedbank",
        "payable": true,
        "reason": null
      }
    ],
    "signer_known": true
  },
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}

payments.signing-link · scope suppliers:read

The Betalningar page link where a person approves and signs bank payments, with what is waiting there.

Answers the URL of the Betalningar page in Accounted (optionally with orders preselected), how many orders wait for approval, how many wait for a BankID signing, how many the bank holds, how many have an unknown bank outcome, and the company's verification at the provider when it answers. Approval and signing are a person's acts in Accounted; no door here does them.

Use when: After preparing payments, to hand the person the place where they sign; or to report what is waiting.

Don't use for: The orders themselves (GET /payment-orders).

Pitfalls

  • verification is null when the provider did not answer in time; it is informational here.
  • verification.state says what to do: not_started, link_expired, expiring or expired call for POST /payment-orders/verification/start.

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

Query parameters

NameTypeRequiredDescription
payment_order_idsstringnoComma-separated payment_order_id values to preselect on the page; omit for the page as it stands.

Response fields

NameTypeDescription
urlstring
awaiting_approvalnumberDraft orders.
awaiting_signaturenumberApproved orders not yet signed.
at_banknumberOrders the bank holds and has not finished with.
outcome_unknownnumberOrders whose bank answer was lost; a person resolves them.
verificationobject | null
notestring

Example response

{
  "data": {
    "url": "https://app.accounted.se/payments?orders=7c2e…",
    "awaiting_approval": 1,
    "awaiting_signature": 0,
    "at_bank": 0,
    "outcome_unknown": 0,
    "verification": {
      "status": "valid",
      "valid_until": "2027-10-03",
      "state": "valid",
      "link_expires_at": null
    },
    "note": "Approval and BankID signing happen in Accounted, by a person: open the url. No API or MCP door signs a payment."
  },
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}

GET /api/v1/companies/:companyId/payment-orders/usage

payments.usage · scope suppliers:read

Bank payments sent and accounts used in a month, against the monthly cap.

Counts the payments that reached the provider (an order with a provider payment id) and the accounts they left from, in one month in Stockholm time, against what the company may send per month. A payment counts in the month its signing sent it to the provider, not the month it was drafted. Payments are capped: included_payments is the cap (10 a month unless raised for the company), remaining_payments what the month still takes, and a BankID signing that would pass the cap is refused with BANK_PAYMENTS_ALLOWANCE_EXCEEDED. Accounts are counted, not capped. Payment files are not counted. The month defaults to the current one.

Use when: Before a batch of bank payments, to see how many the month still takes.

Don't use for: Payment files (pain.001): they are not bank payments and are neither counted nor capped.

Pitfalls

  • A person asks for a higher cap under Settings, Connections, Bank payments; no API raises it.
  • extra_payments is non-zero only when two signings raced past the cap or the cap was lowered mid-month; the counter is read from the orders, never edited.

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

Query parameters

NameTypeRequiredDescription
periodstringnoYYYY-MM in Stockholm time. Default: the current month.

Response fields

NameType
periodstring
payments_sentnumber
accounts_usednumber
included_paymentsnumber
included_accountsnumber
remaining_paymentsnumber
extra_paymentsnumber
extra_accountsnumber

Example response

{
  "data": {
    "period": "2026-10",
    "payments_sent": 4,
    "accounts_used": 1,
    "included_payments": 10,
    "included_accounts": 2,
    "remaining_payments": 6,
    "extra_payments": 0,
    "extra_accounts": 0
  },
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}

GET /api/v1/companies/:companyId/payment-orders/verification

payments.verification · scope suppliers:read

The company's verification (know your customer) at the payment provider, and where it stands.

Answers whether the provider has verified the company (status, valid_until) and the derived state: not_started, form_open, awaiting_signatory, link_expired, valid, expiring (within 30 days of valid_until), expired. Payments are refused until the status is valid. The stored answer is used when it is under six hours old; the provider is asked again when it is older or a form is out. A missing, expired or expiring verification is started or renewed with POST /payment-orders/verification/start, which answers a form link (valid 24 h) a signatory fills in and signs.

Use when: Bank payments are available but signing is refused for the company, before the first payment, or to see whether a renewal is due.

Don't use for: Whether payments are switched on at all (GET /payment-orders/availability).

Pitfalls

  • PAYMENT_PROVIDER_UNAVAILABLE is transient: the provider did not answer and nothing was on file; try again shortly.
  • state link_expired: the 24-hour form link ran out unsigned; start again rather than re-sending the old link.

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

Response fields

NameTypeDescription
status"valid" | "invalid" | "unknown"valid: payments are allowed. invalid: not verified, or the verification failed or lapsed. unknown: the provider gave no answer.
valid_untilstring | nullYYYY-MM-DD, when the provider reports it.
state"not_started" | "form_open" | "awaiting_signatory" | "link_expired" | "valid" | "expiring" | "expired"not_started: no form yet. form_open: a form link exists (24 h). awaiting_signatory: that form was handed to a firmatecknare. link_expired: the link ran out unsigned; start again. valid: payments allowed until valid_until. expiring: valid_until within 30 days; renew. expired: valid_until passed or the verification lapsed; renew.
link_expires_atstring | nullISO instant the current form link runs out (24 h after it was created); null without a link.

Example response

{
  "data": {
    "status": "valid",
    "valid_until": "2027-10-03",
    "state": "valid",
    "link_expires_at": null
  },
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}

GET /api/v1/companies/:companyId/payments/creditor-lookup

payments.lookup-creditor · scope suppliers:read

The name Bankgirot has registered for a bankgiro or plusgiro number, and whether an OCR passes its check.

Asks Bankgirot (through the payment provider's premium Bankgiro Lookup) which name is registered for a bankgiro or plusgiro number before money goes there: the check against invoice fraud and typos. With the payment's OCR, ocr_valid says whether the creditor accepts it. Enabled only when the installation has switched the lookups on (OPENPAYMENTS_BANKGIRO_LOOKUP); otherwise enabled is false and nothing is asked. Advice, never a gate: a refusal is a typed reason, and the payment may still be prepared.

Use when: Before paying a supplier for the first time, when an invoice states another account than the supplier card, or when a new supplier card carries a giro: compare creditor_name with the supplier name.

Don't use for: The company's own giro numbers (GET /payments/giro-numbers). Bank accounts (clearing + account) or IBANs: Bankgirot does not register them.

Pitfalls

  • Every enabled call may cost a premium fee at the provider; answers are cached for ten minutes per company and question.
  • A name that differs from the supplier card is a reason for a person to check with the supplier, not proof of fraud: companies register trade names.
  • reason not_found means Bankgirot knows no such number: check the digits before paying.

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

Query parameters

NameTypeRequiredDescription
girostringyesThe bankgiro or plusgiro number, as typed or stored (digits, spaces and dashes).
type"bankgiro" | "plusgiro"yesWhich kind of giro number giro is.
ocrstringnoThe payment's OCR reference, when it has one: the creditor's OCR check runs on it and ocr_valid answers.
invoice_refstringnoThe payment's free reference (the invoice number) when it has no OCR. Ignored when ocr is given.

Response fields

NameTypeDescription
enabledbooleanFalse when the installation has not switched the premium lookups on: nothing was asked.
availablebooleanTrue when Bankgirot answered with a name.
reason"premium_not_enabled" | "provider_refused" | "not_found" | "invalid_number" | "org_number_missing" | nullWhy there is no answer although the lookup is enabled: premium_not_enabled (the provider has not opened the product for this service), provider_refused (the provider failed or refused; try later), not_found (Bankgirot knows no such giro, or no registration for the company), invalid_number (the giro fails its check digit), org_number_missing (the company has no organisationsnummer). Null when available is true, or when enabled is false.
creditor_namestring | nullThe name Bankgirot has registered for the giro number, when available.
ocr_validboolean | nullWith an ocr: whether the creditor accepts it. Null when no OCR was given or nothing is available.
warningsobject[]The provider's warnings on a successful answer, verbatim codes; [] when none.

Example request

{
  "giro": "5050-1055",
  "type": "bankgiro",
  "ocr": "4400112233"
}

Example response

{
  "data": {
    "enabled": true,
    "available": true,
    "reason": null,
    "creditor_name": "Derome Bygg AB",
    "ocr_valid": true,
    "warnings": []
  },
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}

GET /api/v1/companies/:companyId/payments/giro-numbers

payments.company-giro-numbers · scope companies:read

The bankgiro and plusgiro numbers Bankgirot has registered to the company's own organisationsnummer.

Asks Bankgirot (through the payment provider's premium Bankgiro Lookup) which giro numbers are registered to the company, so the invoice payee (the bankgiro printed on the company's invoices) can be picked from the registry instead of typed. Enabled only when the installation has switched the lookups on (OPENPAYMENTS_BANKGIRO_LOOKUP); otherwise enabled is false and nothing is asked.

Use when: Setting up or checking the bankgiro the company prints on its invoices (cash account payee details).

Don't use for: A supplier's giro (GET /payments/creditor-lookup). Reading the payee details already saved (GET /cash-accounts).

Pitfalls

  • Every enabled call may cost a premium fee at the provider; the answer is cached for ten minutes per company.
  • An empty list with available true means Bankgirot has no giro registered to this organisationsnummer.

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

Response fields

NameTypeDescription
enabledbooleanFalse when the installation has not switched the premium lookups on: nothing was asked.
availablebooleanTrue when Bankgirot answered (possibly with an empty list).
reason"premium_not_enabled" | "provider_refused" | "not_found" | "invalid_number" | "org_number_missing" | nullWhy there is no answer although the lookup is enabled: premium_not_enabled (the provider has not opened the product for this service), provider_refused (the provider failed or refused; try later), not_found (Bankgirot knows no such giro, or no registration for the company), invalid_number (the giro fails its check digit), org_number_missing (the company has no organisationsnummer). Null when available is true, or when enabled is false.
giro_numbersobject[]The giro numbers registered to the company's organisationsnummer; [] when none or not available.

Example response

{
  "data": {
    "enabled": true,
    "available": true,
    "reason": null,
    "giro_numbers": [
      {
        "number": "5050-1055",
        "type": "bankgiro",
        "name": "Derome Bygg AB"
      }
    ]
  },
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}

POST /api/v1/companies/:companyId/payment-orders

payment-orders.prepare · scope suppliers:write

Prepare draft bank payments (betalningar via banken) for supplier invoices, or one payment in to the skattekonto.

Creates one draft payment order per payable supplier invoice, from one of the company's own bank accounts: the remaining amount, the due date (the banking day before it when it falls on a weekend or holiday, or today when that has passed) unless execution_date is given, the supplier's bankgiro, plusgiro or bank account, and the OCR or invoice number as reference. Nothing reaches the bank: a draft is approved by a person (POST /payment-orders/approve) and then signed with BankID on the Betalningar page in Accounted. The database decides each order's payee check (known, new, changed) from the supplier card, the invoice and payments a person already approved; new and changed accounts need that person's confirmation at approval. Invoices that cannot be paid are skipped with a reason; the request fails only when nothing is payable. Dry-runnable: ?dry_run=true answers the lines without creating anything; each line carries document: what the invoice document states (document_id, the account and the OCR read off it, its total and due date) and checks (same, differs or missing) for the account and the reference against what would be paid. With skattekonto instead of supplier_invoice_ids it creates one draft payment in to the skattekonto: Skatteverket's bankgiro 5050-1055 with the company's OCR number (set by Accounted, never typed). skattekonto.source names what it pays: next_charge (default: what the synced skattekonto lacks for its next charge), vat_declaration (ruta 49 of the momsdeklaration as filed, due on its deadline), agi (avdragen skatt + arbetsgivaravgifter of the arbetsgivardeklaration, due the 12th, 17th in January and August) or due_date (everything declared due on skattekonto.due_date as one payment, its parts in skattekonto.combined); skattekonto.amount pays another amount instead. The day defaults to the banking day before the due date. The synced saldo comes back as information and is never netted. Nothing is booked when the order is made or paid: the bank row to Skatteverket is booked like any other, against the skattekonto account (1630).

Use when: The user wants to pay approved supplier invoices from their bank account in Accounted instead of a payment file, or to pay the moms or the arbetsgivardeklaration (or any amount) in to the skattekonto after filing. Call with the invoices or skattekonto and the account; then hand the person the Betalningar link (GET /payment-orders/signing-link).

Don't use for: A payment file (POST /supplier-payment-batches), marking an invoice paid (mark-paid), or signing: no API or MCP door signs.

Pitfalls

  • PAYMENTS_UNAVAILABLE: bank payments are not switched on for the company (no provider, or a sandbox company). Check GET /payment-orders/availability first.
  • PAYMENT_ORDERS_ACCOUNT_NOT_PAYABLE: the account needs a Swedish IBAN in SEK, enabled, at a bank the provider reaches; details.reason says which.
  • PAYMENT_ORDERS_INELIGIBLE: no invoice in the selection is payable; details.skipped names each reason.
  • An invoice already in an open bank payment or an active betalfil is skipped (already_in_payment, in_payment_file), never paid twice.
  • use_stated_payee_for pays the account the invoice states instead of the supplier card for the listed invoices; the database then marks the order's payee changed and a person confirms it at approval.
  • Only SEK; at most 100 invoices per call; execution_date may not be in the past.
  • Send supplier_invoice_ids or skattekonto, never both.
  • One open payment to Skatteverket per execution_date: an unsigned one takes the amount as an addition (skattekonto.merged_into); a signed one refuses SKATTEKONTO_PAYMENT_ALREADY_IN_PAYMENT, pick another day. VAT and AGI due the same day: source due_date. Paying one alone warns same_due_date_parts.
  • source due_date never nets: a declaration asking for nothing (a refund in ruta 49, already paid) is left out and listed in skattekonto.combined.excluded.
  • SKATTEKONTO_PAYMENT_NOTHING_DUE: the declaration asks for no payment (details.reason refund, zero, already_paid, period_not_ended; for due_date also no_declaration, nothing_payable) or nothing is due on the skattekonto; skattekonto.amount pays in anyway.
  • skattekonto.warnings not_filed: the declaration is not on record as filed; possible_duplicate: a bank payment to the skattekonto of the same amount was executed since the period. Tell the person before they sign.

Risk: medium · Idempotent: yes · Reversible: yes · 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
supplier_invoice_idsstring[]noThe supplier invoices to pay (supplier_invoice_id), 1-100. Only SEK. Omit when skattekonto is sent.
skattekontoobjectnoInstead of supplier_invoice_ids: one payment in to the skattekonto (bankgiro 5050-1055, the company's OCR number).
cash_account_idstringyesThe company bank account to pay from (cash_account_id from GET /payment-orders/availability, payable true).
execution_datestringnoYYYY-MM-DD for every order; defaults per invoice to the due date, the banking day before it when it falls on a weekend or holiday, or today when that has passed. A non-banking day given here moves to the next banking day. Never in the past.
use_stated_payee_forstring[]noInvoice ids where the account the invoice states is paid instead of the supplier card.

Response fields

NameTypeDescription
payment_ordersobject[]
skippedobject[]
warningsobject[]
skattekontoobject | null (optional)For a payment in to the skattekonto: what it pays, and its warnings.
nextobject

Example request

{
  "supplier_invoice_ids": [
    "9e2f…"
  ],
  "cash_account_id": "41b0…"
}

Example response

{
  "data": {
    "payment_orders": [
      {
        "payment_order_id": "7c2e…",
        "supplier_invoice_id": "9e2f…",
        "payment_order_batch_id": null,
        "status": "draft",
        "amount": 737.5,
        "currency": "SEK",
        "requested_execution_date": "2026-10-20",
        "cash_account_id": "41b0…",
        "payee": {
          "type": "bankgiro",
          "label": "BG 5050-1055",
          "name": "Derome Bygg AB",
          "source": "supplier",
          "check": "known"
        },
        "reference": {
          "type": "ocr",
          "value": "4400112233"
        },
        "end_to_end_id": "ACC7C2E1A2F3B4C5",
        "provider_status": null,
        "provider_error_code": null,
        "outcome_unknown": false,
        "approved_at": null,
        "submitted_at": null,
        "signed_at": null,
        "executed_at": null,
        "cancelled_at": null,
        "matched_at": null,
        "created_at": "2026-10-10T09:00:00Z",
        "updated_at": "2026-10-10T09:00:00Z",
        "supplier_invoice": null
      }
    ],
    "skipped": [],
    "warnings": [],
    "skattekonto": null,
    "next": {
      "approve": "/api/v1/companies/{companyId}/payment-orders/approve",
      "sign_in_app": "https://app.accounted.se/payments"
    }
  },
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}

POST /api/v1/companies/:companyId/payment-orders/:id/cancel

payment-orders.cancel · scope suppliers:write

Cancel a bank payment order.

Before the bank has the payment (draft, approved) the order is cancelled in Accounted. After that the bank is asked, and the order is cancelled only when the bank confirms the cancel; any other bank answer leaves the payment where it is and is reported as an error code. An executed payment cannot be cancelled. An order whose bank outcome is unknown is not cancelled here: a person resolves it in Accounted after checking the online bank. Dry-runnable.

Use when: A prepared or approved payment should not be made, or a payment the bank holds must be stopped before execution.

Don't use for: Un-paying an invoice, or an executed payment (ask the bank to recall it).

Pitfalls

  • PAYMENT_CANCEL_NEEDS_SIGNING: the bank wants the cancel signed; cancel it in the online bank.
  • PAYMENT_CANCEL_TOO_LATE: executed, or past the bank's cut-off.
  • PAYMENT_CANCEL_UNSIGNED_REFUSED: the bank holds the payment unsigned and refused the cancel; nothing is paid unless someone signs it. Retry in 30 minutes; with details.releasable true a person releases it in Accounted (Betalningar).
  • PAYMENT_CANCEL_NOT_CONFIRMED: the bank did not confirm; check the payment in the online bank. The order is unchanged.
  • PAYMENT_CANCEL_CONFIRMATION_REQUIRED: the bank may hold the payment but its answer was lost; a person resolves the order in Accounted.
  • PAYMENT_ORDER_CREATE_IN_PROGRESS: the payment is on its way to the bank right now; wait a few minutes.

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

NameTypeDescription
payment_order_idstring
cancelledboolean
statusstringThe order's status after the answer.

Example response

{
  "data": {
    "payment_order_id": "7c2e…",
    "cancelled": true,
    "status": "cancelled"
  },
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}

POST /api/v1/companies/:companyId/payment-orders/approve

payment-orders.approve · scope suppliers:write

Approve (attest) draft bank payments so they can be signed.

Moves draft orders to approved: the attestation that these invoices are to be paid, from this account, to these payees. An order to an account that is new for the supplier or differs from the supplier card (payee.check new or changed) needs its invoice named in confirmed_payee_invoice_ids: one confirmation per invoice, never one flag for a whole selection. Nothing reaches the bank: signing with BankID happens on the Betalningar page, by a person. All or nothing: a draft that changed meanwhile fails the request. Undo with POST /payment-orders/unapprove.

Use when: The person behind the API key has checked the drafts and attests them before signing in Accounted.

Don't use for: Signing (only a person signs, in Accounted) or preparing (POST /payment-orders).

Pitfalls

  • PAYMENT_ORDERS_PAYEE_CONFIRMATION_REQUIRED: details.invoices lists the invoices whose account must be confirmed; resend with them in confirmed_payee_invoice_ids after checking the account.
  • PAYMENT_ORDERS_WRONG_STATUS: an order is no longer a draft (details.orders); reload and select again.
  • SKATTEKONTO_PAYMENT_DAY_TAKEN: a skattekonto draft whose day passed would move onto a day that already has an open skattekonto payment; cancel it and prepare it again (the amount is added to that day's payment).
  • Not offered over MCP: attestation is a person's act. An agent prepares and hands out the Betalningar link.

Risk: high · Idempotent: yes · Reversible: yes · Dry-run supported: yes

Query parameters

NameTypeRequiredDescription
dry_runstringnotrue (any case) previews the write without committing it, like the X-Dry-Run: true header. Any other value commits.

Request body

NameTypeRequiredDescription
payment_order_idsstring[]yesPayment order ids (payment_order_id), 1-100.
confirmed_payee_invoice_idsstring[]noSupplier invoice ids whose payee account the person checked; required for every order with payee.check new or changed.

Response fields

NameTypeDescription
approved_payment_order_idsstring[]
sign_in_appstringThe Betalningar page where a person signs the approved orders with BankID.

Example request

{
  "payment_order_ids": [
    "7c2e…"
  ]
}

Example response

{
  "data": {
    "approved_payment_order_ids": [
      "7c2e…"
    ],
    "sign_in_app": "https://app.accounted.se/payments"
  },
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}

POST /api/v1/companies/:companyId/payment-orders/unapprove

payment-orders.unapprove · scope suppliers:write

Take approved bank payments back to draft.

Moves approved orders back to draft so they can be edited or cancelled before signing. Only orders the bank does not have yet (status approved) can go back; anything submitted is cancelled instead (POST /payment-orders/{id}/cancel). All or nothing.

Use when: An attested payment should not be signed as it stands.

Don't use for: Stopping a payment the bank has (cancel) or removing a draft (cancel).

Pitfalls

  • PAYMENT_ORDERS_WRONG_STATUS: an order is not approved any more (details.unapproved lists what did move).

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

Query parameters

NameTypeRequiredDescription
dry_runstringnotrue (any case) previews the write without committing it, like the X-Dry-Run: true header. Any other value commits.

Request body

NameTypeRequiredDescription
payment_order_idsstring[]yesPayment order ids (payment_order_id), 1-100.

Response fields

NameType
unapproved_payment_order_idsstring[]

Example request

{
  "payment_order_ids": [
    "7c2e…"
  ]
}

Example response

{
  "data": {
    "unapproved_payment_order_ids": [
      "7c2e…"
    ]
  },
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}

POST /api/v1/companies/:companyId/payment-orders/verification/start

payments.verification-start · scope suppliers:write

Start or renew the company's verification at the payment provider and get the form link.

Creates a verification form at the provider and answers its link, which a person fills in and a signatory of the company signs with BankID. The link is valid 24 hours (expires_at); starting again makes a new form and a new link. The state is then form_open, or awaiting_signatory with handoff true (the link goes to a firmatecknare rather than the caller). The provider approves afterwards; read the result with GET /payment-orders/verification. Changes nothing in the books.

Use when: GET /payment-orders/verification answers a state of not_started, link_expired, expiring or expired.

Don't use for: Checking the status (GET /payment-orders/verification).

Pitfalls

  • The link is for a person who may sign for the company; it is not an API. Hand it over once and do not store it.
  • A non-signatory can fill the form in and share it with a signatory to sign; pass handoff true when the link is for the signatory.

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

Query parameters

NameTypeRequiredDescription
dry_runstringnotrue (any case) previews the write without committing it, like the X-Dry-Run: true header. Any other value commits.

Request body

NameTypeRequiredDescription
handoffbooleannoTrue when the link is handed to a firmatecknare rather than opened by the caller: the state reads awaiting_signatory.

Response fields

NameTypeDescription
urlstring
expires_atstringISO instant the form link runs out (24 hours).
state"not_started" | "form_open" | "awaiting_signatory" | "link_expired" | "valid" | "expiring" | "expired"not_started: no form yet. form_open: a form link exists (24 h). awaiting_signatory: that form was handed to a firmatecknare. link_expired: the link ran out unsigned; start again. valid: payments allowed until valid_until. expiring: valid_until within 30 days; renew. expired: valid_until passed or the verification lapsed; renew.

Example request

{
  "handoff": true
}

Example response

{
  "data": {
    "url": "https://kyc.openbankingplatform.com/…",
    "expires_at": "2026-10-14T09:00:00.000Z",
    "state": "awaiting_signatory"
  },
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}

POST /api/v1/companies/:companyId/payments/signing-links

payment-signing-links.create · scope suppliers:write

Ask someone without an Accounted login to sign approved bank payments with BankID: a signing link.

Creates a link, valid 72 hours, to a page at /betala/<token> where the company's firmatecknare sees the basket (payee, amount, date and reference per payment, the account paying, who asked, the note) and signs it with BankID at their bank, without logging in to Accounted. The orders must be approved, from one account and in one currency; if any of them leaves approved before the signing (cancelled, signed or un-approved elsewhere) the page says so and signs nothing. The link can instead ask for the second signature: every order of one signing the bank holds for another signatory (awaiting_second_signer) at a bank that takes that signature through the API (SEB); the page signs as that signatory. The link is consumed when the signing finalises. With recipient_email it is mailed (template payment_signing_request); the url is answered either way. Owners and admins, or the person who prepared every order. Dry-runnable: ?dry_run=true answers the basket and mints nothing.

Use when: A byrå or an agent prepared supplier payments and a person approved them, but the client's firmatecknare signs at the bank.

Don't use for: Signing in person (the Betalningar page), approving drafts (POST /payment-orders/approve) or payment files.

Pitfalls

  • The url carries the credential: hand it to the signer only, once, and do not store it.
  • PAYMENT_ORDERS_WRONG_STATUS: an order is not approved (details.orders); approve it first. For the second signature, name every order of the signing that waits (details.missing).
  • PAYMENT_SECOND_SIGNATURE_IN_ONLINE_BANK: the bank takes the second signature in its online bank; nothing to sign on a page.
  • PAYMENT_SIGNING_LINK_ALREADY_OPEN: another open link covers an order (details.signing_link_ids); it is cancelled on the Betalningar page.
  • PAYMENT_ORDERS_MIXED_ACCOUNTS / PAYMENT_ORDERS_MIXED_CURRENCY: one link is one signing, from one account in one currency.

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.

Request body

NameTypeRequiredDescription
payment_order_idsstring[]yesApproved payment orders (payment_order_id), 1-100, from one account in one currency; or every order of one signing waiting for a second signatory.
recipient_emailstring | nullnoMail the link to the signer; omit to only get the url.
notestring | nullnoA message to the signer, shown on the page and in the mail.

Response fields

NameTypeDescription
signing_link_idstring
urlstringThe signing page; the credential itself. Hand it to the signer only.
expires_atstring
email_sentboolean
order_countnumber
total_amountnumber
currencystring

Example request

{
  "payment_order_ids": [
    "7c2e…"
  ],
  "recipient_email": "anna@example.se",
  "note": "Leverantörsbetalningar för oktober."
}

Example response

{
  "data": {
    "signing_link_id": "5d1a…",
    "url": "https://app.accounted.se/betala/…",
    "expires_at": "2026-10-17T09:00:00.000Z",
    "email_sent": true,
    "order_count": 1,
    "total_amount": 737.5,
    "currency": "SEK"
  },
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}