Supplier invoices
AP lifecycle: register, approve, mark paid, credit. With ROT/RUT and reverse-charge support.
Endpoints
GET/api/v1/companies/:companyId/supplier-invoices— List supplier invoices for a company.GET/api/v1/companies/:companyId/supplier-invoices/:id— Retrieve a single supplier invoice by id.POST/api/v1/companies/:companyId/supplier-invoices— Register a new supplier invoice.POST/api/v1/companies/:companyId/supplier-invoices/:id/approve— Approve a registered supplier invoice.POST/api/v1/companies/:companyId/supplier-invoices/:id/credit— Issue a credit note for a supplier invoice.POST/api/v1/companies/:companyId/supplier-invoices/:id/mark-paid— Record a payment against a supplier invoice.PATCH/api/v1/companies/:companyId/supplier-invoices/:id— Update a registered supplier invoice.
GET /api/v1/companies/:companyId/supplier-invoices {#get-supplier-invoices-list}
supplier-invoices.list · scope suppliers:read
List supplier invoices for a company.
Returns supplier invoices in most-recent-first order. Filters: status, supplier_id, currency, date_from / date_to (filter by invoice_date).
Use when: You need to enumerate registered supplier invoices for an AP dashboard, a payment run, or a leverantörsreskontra reconciliation.
Don't use for: Fetching a single supplier invoice — use GET /supplier-invoices/{id}. Listing customer invoices (different resource).
Pitfalls
- Credit notes (is_credit_note=true) appear in the same list as the originals; filter by status=credited or check the flag to separate.
- remaining_amount is the unpaid portion; a partially_paid SI has remaining_amount > 0.
- arrival_number is internal book-keeping, not the seller's invoice number — use supplier_invoice_number for matching to received documents.
Risk: low · Idempotent: yes · Reversible: no · Dry-run supported: no
Example response
{
"data": [
{
"id": "0e9c…",
"supplier_id": "a8f1…",
"supplier_name": "Office Depot AB",
"arrival_number": 42,
"supplier_invoice_number": "2026-1234",
"invoice_date": "2026-05-10",
"due_date": "2026-06-09",
"status": "registered",
"currency": "SEK",
"subtotal": 1000,
"vat_amount": 250,
"total": 1250,
"paid_amount": 0,
"remaining_amount": 1250,
"is_credit_note": false,
"paid_at": null,
"created_at": "2026-05-13T15:00:00Z"
}
],
"meta": {
"request_id": "req_…",
"api_version": "2026-05-12",
"next_cursor": null
}
}
GET /api/v1/companies/:companyId/supplier-invoices/:id {#get-supplier-invoices-get}
supplier-invoices.get · scope suppliers:read
Retrieve a single supplier invoice by id.
Returns the full supplier-invoice record. Pass ?expand=supplier,items,payments to embed the related rows in the same response.
Use when: You need the full record before approving, paying, or crediting it — or for audit trail / reconciliation.
Don't use for: Listing supplier invoices (use the list endpoint). Customer-invoice lookups (different resource).
Pitfalls
- Credit notes return is_credit_note=true and a credited_invoice_id pointing at the original.
- registration_journal_entry_id and payment_journal_entry_id let you trace the SI to its bokföring rows; they are null when no JE has been posted (e.g. on a kontantmetoden SI before payment).
Risk: low · Idempotent: yes · Reversible: no · Dry-run supported: no
Example response
{
"data": {
"id": "0e9c…",
"supplier_id": "a8f1…",
"arrival_number": 42,
"supplier_invoice_number": "2026-1234",
"status": "registered",
"currency": "SEK",
"subtotal": 1000,
"vat_amount": 250,
"total": 1250,
"remaining_amount": 1250,
"is_credit_note": false
},
"meta": {
"request_id": "req_…",
"api_version": "2026-05-12"
}
}
POST /api/v1/companies/:companyId/supplier-invoices {#post-supplier-invoices-create}
supplier-invoices.create · scope suppliers:write
Register a new supplier invoice.
Creates a supplier invoice in registered status and posts the registration journal entry under faktureringsmetoden (Debit expense + Debit 2641 Ingående moms / Credit 2440 Leverantörsskulder). Under kontantmetoden no JE is posted at this stage. Idempotent (mandatory Idempotency-Key). Dry-runnable.
Use when: You're registering an incoming leverantörsfaktura. Use dry-run first to validate VAT calculations + period-lock state before committing.
Don't use for: Marking an existing SI as paid (use POST /:id/mark-paid). Issuing a credit note (use POST /:id/credit). Customer invoices (different resource).
Pitfalls
- Idempotency-Key is mandatory.
- invoice_date must fall within an open fiscal period — a date covered by a locked period or the company-wide bookkeeping lock returns 400 PERIOD_LOCKED.
- Under faktureringsmetoden the registration JE is posted atomically with the SI row. JE failure aborts the whole call and no SI row is left behind (strict-mode).
- supplier_id must reference an existing, non-archived supplier in the same company — 404 SUPPLIER_NOT_FOUND otherwise.
- Duplicate (supplier_id, supplier_invoice_number) returns 409 SI_CREATE_DUPLICATE_INVOICE_NUMBER. Use the credit flow on the original instead of re-registering with a tweaked number.
Risk: medium · Idempotent: yes · Reversible: yes · Dry-run supported: yes
Example request
{
"supplier_id": "a8f1…",
"supplier_invoice_number": "2026-1234",
"invoice_date": "2026-05-10",
"due_date": "2026-06-09",
"items": [
{
"description": "Office supplies",
"amount": 1000,
"account_number": "5410",
"vat_rate": 0.25
}
]
}
Example response
{
"data": {
"id": "0e9c…",
"supplier_id": "a8f1…",
"arrival_number": 42,
"supplier_invoice_number": "2026-1234",
"status": "registered",
"total": 1250,
"registration_journal_entry_id": "7b3a…"
},
"meta": {
"request_id": "req_…",
"api_version": "2026-05-12"
}
}
POST /api/v1/companies/:companyId/supplier-invoices/:id/approve {#post-supplier-invoices-approve}
supplier-invoices.approve · scope suppliers:write
Approve a registered supplier invoice.
Flips a supplier invoice from registered to approved. No journal entry is posted here — the registration JE was already booked at :create under accrual, or is deferred to :mark-paid under cash. Idempotent. Dry-runnable.
Use when: A registered SI has been reviewed and you want to mark it ready for payment. Many AP workflows gate :mark-paid behind an explicit approval step.
Don't use for: Posting a journal entry (already done at :create under accrual). Paying the SI (use :mark-paid). Re-approving an already-approved SI (returns 400 SI_APPROVE_NOT_REGISTERED).
Pitfalls
- Idempotency-Key is mandatory.
- Returns 400 SI_APPROVE_NOT_REGISTERED when current status !== "registered". Use the detail endpoint to inspect status first if unsure.
Risk: low · Idempotent: yes · Reversible: no · Dry-run supported: yes
Example response
{
"data": {
"id": "0e9c…",
"status": "approved",
"arrival_number": 42,
"supplier_invoice_number": "2026-1234"
},
"meta": {
"request_id": "req_…",
"api_version": "2026-05-12"
}
}
POST /api/v1/companies/:companyId/supplier-invoices/:id/credit {#post-supplier-invoices-credit}
supplier-invoices.credit · scope suppliers:write
Issue a credit note for a supplier invoice.
Creates a kreditfaktura that reverses the original supplier invoice. Under accrual the reversing JE is posted atomically (Debit 2440 / Credit expense + Credit 2641). The original status flips to credited. Strict-mode: any failure rolls back the credit-note row. Idempotent. Dry-runnable.
Use when: You need to nullify a registered, approved, partially_paid, or paid supplier invoice — for a returned shipment, an over-invoice, or a vendor dispute resolution. Use dry-run to confirm the totals first.
Don't use for: Editing line items on an unchanged invoice (use PATCH on registered SIs). Crediting an already-credited SI (returns 409 SI_CREDIT_ALREADY_CREDITED). Reversing a v1-issued credit (no v1 endpoint today — use the dashboard).
Pitfalls
- Idempotency-Key is mandatory.
- Today's date is used as the credit-note invoice_date. It must fall in an open fiscal period — locked period returns 400 SI_CREDIT_PERIOD_LOCKED.
- Cash basis (kontantmetoden): no reversing JE is posted — recognition is deferred until a refund transaction is booked. The credit-note row is still created so the AP audit trail stays consistent.
- The original SI is flipped to
creditedregardless of how much of it was already paid; reconcile the bank refund via the transactions endpoints.
Risk: high · Idempotent: yes · Reversible: no · Dry-run supported: yes
Example response
{
"data": {
"credit_note_id": "4d2a…",
"original_id": "0e9c…",
"arrival_number": 43,
"supplier_invoice_number": "KREDIT-2026-1234",
"registration_journal_entry_id": "9c2f…"
},
"meta": {
"request_id": "req_…",
"api_version": "2026-05-12"
}
}
POST /api/v1/companies/:companyId/supplier-invoices/:id/mark-paid {#post-supplier-invoices-mark-paid}
supplier-invoices.mark-paid · scope suppliers:write
Record a payment against a supplier invoice.
Books the payment journal entry (Debit 2440 / Credit 1930 under accrual; or Debit expense + Debit 2641 / Credit 1930 under cash) and flips the SI status to paid (full settlement) or partially_paid. Strict-mode: a JE failure aborts before any SI mutation. Idempotent. Dry-runnable.
Use when: You paid a registered or approved leverantörsfaktura through a channel other than the synced bank flow. For bank-matched payments use POST /transactions/{id}/match-supplier-invoice instead — that path also reconciles the bank line.
Don't use for: Refunding a payment (the public API does not expose unmark-paid; credit the SI instead). Paying a credited or already-paid SI (returns 409 SI_PAID_ALREADY).
Pitfalls
- Idempotency-Key is mandatory.
- payment_date must fall in an open fiscal period — locked period returns 400 PERIOD_LOCKED.
- exchange_rate_difference (SEK delta vs the booked rate at registration) is required for foreign-currency SIs to book the FX gain/loss to 3960 / 7960. Omitting it on a non-SEK SI under accrual mis-books FX.
- Strict-mode: a JE creation failure ABORTS before the status flip. There is no partial-state recovery banner — retry the call.
- Cash basis (kontantmetoden) recognizes the expense + ingående moms HERE, not at :create.
Risk: medium · Idempotent: yes · Reversible: no · Dry-run supported: yes
Example request
{
"payment_date": "2026-05-13"
}
Example response
{
"data": {
"id": "0e9c…",
"status": "paid",
"total": 1250,
"paid_amount": 1250,
"remaining_amount": 0,
"paid_at": "2026-05-13",
"payment_journal_entry_id": "7b3a…"
},
"meta": {
"request_id": "req_…",
"api_version": "2026-05-12"
}
}
PATCH /api/v1/companies/:companyId/supplier-invoices/:id {#patch-supplier-invoices-update}
supplier-invoices.update · scope suppliers:write
Update a registered supplier invoice.
Patches a supplier invoice with the supplied fields. Only allowed on registered status — once approved, paid, or credited, the record is effectively immutable from the API's perspective. Idempotent (mandatory Idempotency-Key). Dry-runnable.
Use when: You need to fix a typo in supplier_invoice_number, adjust dates, or attach a payment reference / notes to a registered SI before approval. Use dry-run to confirm the merged state first.
Don't use for: Editing line items (immutable — credit the SI and register a new one). Changing status (use action verbs). Approved/paid/credited SIs (returns 400 SI_NOT_DRAFT).
Pitfalls
- Returns 400 SI_NOT_DRAFT when current status !== "registered".
- invoice_date / due_date changes do not re-post the registration JE; if the entry date needs to change, credit the SI and re-register.
Risk: low · Idempotent: yes · Reversible: yes · Dry-run supported: yes
Example request
{
"payment_reference": "OCR-1234567890"
}
Example response
{
"data": {
"id": "0e9c…",
"payment_reference": "OCR-1234567890"
},
"meta": {
"request_id": "req_…",
"api_version": "2026-05-12"
}
}