Menu

Collections

Overdue invoices handed to the collections provider the company activated: the candidates and their checks, the case on each invoice, actions on it (pause, resume, withdraw, dispute, or what the provider waits for), and booking what the provider collected and paid out. The handover and the escalations are staged for a person to approve in Accounted (?stage=true; a direct call answers STAGE_REQUIRED).

Endpoints


GET /api/v1/companies/:companyId/collections/candidates

collections.candidates.list · scope invoices:read

List the overdue customer invoices that could be handed over to the company's collections provider.

Overdue customer invoices (due date passed, Europe/Stockholm) that are issued and still owed, checked against the handover rules: SEK and a Swedish customer, at least the company's minimum, no open case, a complete postal address, an org number for a business, not time-barred, no ROT/RUT share refused by Skatteverket. The bank check (an unbooked payment that may be this invoice) and a consumer's age are checked when the invoice is handed over, not here.

Use when: Deciding which overdue invoices to stage for collection with gnubok_send_invoice_to_collection.

Don't use for: Reading an invoice's case (gnubok_get_collection_case) or listing every unpaid invoice (GET /invoices).

Pitfalls

  • needs_attestation=true means only a person can hand the invoice over in the web UI (the invoice has no delivery record, was imported, or the customer answered a reminder).
  • COLLECTIONS_DISABLED or COLLECTIONS_NOT_ACTIVE: the company has not activated collections, or it is switched off on this installation.

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

Query parameters

NameTypeRequiredDescription
include_ineligibleboolean | "true" | "false"noAlso list overdue invoices that fail a check, with the checks they fail.

Response fields

NameType
candidates[].invoice_idstring
candidates[].invoice_numberstring | null
candidates[].customer_idstring | null
candidates[].customer_namestring | null
candidates[].due_datestring
candidates[].overdue_daysnumber
candidates[].claim_amountnumber
candidates[].remaining_amountnumber
candidates[].eligibleboolean
candidates[].blocksstring[]
candidates[].needs_attestationboolean

Example response

{
  "data": {
    "candidates": [
      {
        "invoice_id": "7d1e…",
        "invoice_number": "F-1042",
        "customer_id": "1c2d…",
        "customer_name": "Kund AB",
        "due_date": "2026-09-01",
        "overdue_days": 33,
        "claim_amount": 12500,
        "remaining_amount": 12500,
        "eligible": true,
        "blocks": [],
        "needs_attestation": false
      }
    ]
  },
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}

GET /api/v1/companies/:companyId/collections/settlements

collections.settlements.list · scope invoices:read

List the payments debtors made to the collections provider and the provider's payouts, with how far each is booked.

Newest first, up to 200 of each. With settlement_id it also returns that payout's lines: the account each books to and the choices a person (or an approved staged booking) must make before it books. Served whatever the collections start gates say.

Use when: Before booking a collected payment or a payout, or to see what waits in Avräkningar.

Don't use for: Open collection cases (gnubok_get_collection_case) or invoices not handed over.

Pitfalls

  • A payout in needs_mapping with reason possible_duplicate is answered by a person in the web UI, not by an agent.

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

Query parameters

NameTypeRequiredDescription
settlement_idstringnoA payout to read with its lines.

Response fields

NameType
providerstring | null
settlementsobject[]
collected_paymentsobject[]
settlementobject | null

Example request

{
  "settlement_id": "5c1e…"
}

Example response

{
  "data": {
    "provider": "Acme Inkasso",
    "settlements": [
      {
        "settlement_id": "5c1e…",
        "amount": 843.75,
        "status": "needs_mapping",
        "needs_mapping_reason": "vat_unconfirmed"
      }
    ],
    "collected_payments": [
      {
        "collected_payment_id": "8a2b…",
        "capital_paid": 1000,
        "status": "pending"
      }
    ],
    "settlement": {
      "settlement_id": "5c1e…",
      "lines": [
        {
          "position": 1,
          "kind": "agency_fee_vat",
          "needs_account": "vat"
        }
      ],
      "voucher_preview": null
    }
  },
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}

GET /api/v1/companies/:companyId/invoices/:id/collection

collections.cases.get · scope invoices:read

Read an invoice's collection case: stage, what the provider waits for, the actions it offers, amounts and timeline.

The invoice's open case, or its latest closed or refused one, re-read from the provider when it was last read more than a minute ago. Works whatever the company's plan or switches say: an open case is always readable.

Use when: Following up an invoice handed over to collection, or before gnubok_collection_case_action to see which actions the case offers.

Don't use for: Finding invoices to hand over (gnubok_list_collection_candidates).

Pitfalls

  • case=null means the invoice was never handed over.
  • submission_status=submitted means the handover is still being registered; it is retried automatically.

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

Response fields

NameTypeDescription
caseobject | null
withdraw_feeobject | nullFor an open case: whether withdrawing it may cost a fee.

Example request

{
  "invoice_id": "7d1e…"
}

Example response

{
  "data": {
    "case": {
      "case_id": "2b9c…",
      "stage": "reminder",
      "is_open": true,
      "actions": [
        "pause",
        "withdraw",
        "dispute"
      ]
    },
    "withdraw_fee": {
      "may_apply": false,
      "free_days": 14,
      "free_until": "2026-10-20T09:00:00.000Z"
    }
  },
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}

POST /api/v1/companies/:companyId/collections/payments/:paymentId/book

collections.payments.book · scope invoices:write

Book a payment a debtor made to the collections provider as a payment of the invoice.

Books the capital the debtor paid on the day they paid, against the clearing account for money the provider holds (default 1689), with the provider's payment data rendered as the voucher's underlag. A payment the books refuse (a locked period, an invoice already paid) answers outcome needs_review with the reason and waits for a person. The dry run reads only and names the invoice and the clearing account; the staged booking pins the payment day.

Use when: gnubok_list_collection_settlements lists a collected payment as pending or needs_review.

Don't use for: Payments the customer made to the company itself (mark the invoice paid; it is reported to the provider).

Pitfalls

  • A booked payment is corrected only with "Bokför om" under Avräkningar; a generic storno of its voucher is refused.

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
payment_datestringnoPinned at staging: the day the debtor paid, which the booking is dated.

Response fields

NameTypeDescription
outcome"booked" | "needs_review"
journal_entry_idstring | null (optional)
invoice_payment_idstring (optional)
write_off_idstring (optional)On a written-off invoice: the recovered customer loss decision it was booked as.
already_bookedboolean (optional)
reasonstring (optional)Why the books refused it (needs_review).

Example request

{
  "collected_payment_id": "8a2b…"
}

Example response

{
  "data": {
    "outcome": "booked",
    "journal_entry_id": "je…",
    "already_booked": false
  },
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}

POST /api/v1/companies/:companyId/collections/settlements/:settlementId/book

collections.settlements.book · scope bookkeeping:write

Book a payout from the collections provider as one voucher, with the settlement PDF as its underlag.

Records the accounts chosen for the lines the ledger could not place (lines), books the payout's pending collected payments first, then posts one voucher dated the payout day: principal against the clearing account, the provider's fees and their VAT, the payout to the payout account. The dry run reads only and previews that voucher (voucher_lines); it refuses a payout the ledger cannot book with the choices given (409 COLLECTION_SETTLEMENT_NEEDS_PERSON with the reason). The staged booking pins the payout's day, amount, lines and voucher: a payout or voucher that changed before approval answers 409 COLLECTION_SETTLEMENT_CHANGED. A payout that still needs a person at commit answers outcome needs_mapping with the reason.

Use when: gnubok_list_collection_settlements lists a payout as received or needs_mapping, and its lines show the choices to make.

Don't use for: A payout held as a possible duplicate of one booked by hand: a person answers that in Avräkningar.

Pitfalls

  • Pass a choice for every line with needs_account or needs_vat_account; VAT takes 2641 (deductible) or 6062 (cost) only.
  • 409 COLLECTION_SETTLEMENT_POSSIBLE_DUPLICATE: a bank row of the payout already sits on a voucher.
  • 409 COLLECTION_SETTLEMENT_CHANGED: read the payout again and stage a new booking.
  • 409 COLLECTION_SETTLEMENT_NEEDS_PERSON at staging: details.reason and details.issues say what is missing (a line without an account, an unbooked collected payment, a payout that does not balance).

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
linesobject[]noThe accounts for the lines that wait for a choice.
payment_datestringnoPinned at staging: the payout day, which the voucher is dated.
expected_amountnumbernoPinned at staging: the payout amount the approver saw.
expected_linesobject[]noPinned at staging: the payout's lines the approver saw.
expected_voucherobject[]noPinned at staging: the voucher lines the approver saw.

Response fields

NameTypeDescription
outcome"booked" | "needs_mapping"
journal_entry_idstring (optional)
already_bookedboolean (optional)
acknowledgedboolean (optional)The provider was told the payout is booked (retried by the sync run otherwise).
reasonstring (optional)
issuesobject[] (optional)

Example request

{
  "settlement_id": "5c1e…",
  "lines": [
    {
      "position": 1,
      "account_number": "2641"
    }
  ]
}

Example response

{
  "data": {
    "outcome": "booked",
    "journal_entry_id": "je…",
    "acknowledged": true
  },
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}

POST /api/v1/companies/:companyId/invoices/:id/collection

collections.cases.open · scope invoices:write

Hand an overdue customer invoice over to the company's collections provider.

Runs every handover check again (eligibility, the bank check for unbooked payments that may be this invoice, the amount still owed), then registers the claim with the provider, which starts with a reminder or a collection notice. The invoice PDF goes with it. The invoice's status does not change; payments recorded later are reported to the provider. The dry run checks everything as reads and contacts no provider.

Use when: gnubok_list_collection_candidates lists the invoice as eligible and the customer has not paid.

Don't use for: Invoices that need a person's attestation (imported, no delivery record, a customer answer to a reminder, a bank not synced in 24 hours): only a person can hand those over in the web UI.

Pitfalls

  • expected_remaining must equal what is still owed: a payment that arrived meanwhile answers 409 COLLECTION_REMAINING_CHANGED.
  • 409 COLLECTION_BANK_CANDIDATES: an unbooked incoming payment may be this invoice; book it or let a person dismiss it.
  • 409 COLLECTION_BANK_STALE: the account the customer pays to was not synced in 24 hours.
  • 409 COLLECTION_REMINDER_FEE_NOT_AGREED: a reminder needs a reminder fee agreed by the invoice date; omit start_step to start at the inkassokrav.
  • Approval is web-only: a person approves the staged operation in Accounted.
  • Over REST, send it with ?stage=true: a direct call answers 400 STAGE_REQUIRED and hands nothing over.

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
expected_remainingnumberyesWhat is still owed on the invoice, from gnubok_list_collection_candidates (remaining_amount).
start_step"reminder" | "collection" | nullnoWhere the provider starts; default the company's choice.
bank_attestedbooleannoRefused for agents (COLLECTION_ATTESTATION_WEB_ONLY): only a person attests in the web UI.
delivery_attestedbooleannoRefused for agents (COLLECTION_ATTESTATION_WEB_ONLY): only a person attests in the web UI.
imported_attestedbooleannoRefused for agents (COLLECTION_ATTESTATION_WEB_ONLY): only a person attests in the web UI.
response_attestedbooleannoRefused for agents (COLLECTION_ATTESTATION_WEB_ONLY): only a person attests in the web UI.

Response fields

NameTypeDescription
caseobject
registeredbooleanFalse while the handover is still being registered (retried automatically).

Example request

{
  "invoice_id": "7d1e…",
  "expected_remaining": 12500,
  "start_step": "collection"
}

Example response

{
  "data": {
    "case": {
      "case_id": "2b9c…",
      "stage": "registered",
      "submission_status": "registered"
    },
    "registered": true
  },
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}

POST /api/v1/companies/:companyId/invoices/:id/collection/actions

collections.cases.action · scope invoices:write

Act on an invoice's open collection case: pause, resume, withdraw, mark disputed, or answer what the provider waits for.

Only the actions the case offers right now are accepted (gnubok_get_collection_case lists them). Pausing, resuming, withdrawing and disputing serve the open case and always run. Approving the next step, contesting a dispute, overriding the customer's "already paid" and approving legal action escalate against the customer: they re-run the bank check and only a person can approve them in Accounted.

Use when: The case waits for a decision (stage awaiting_decision), the customer disputes the claim, or the company wants to pause or withdraw it.

Don't use for: Recording a payment (mark the invoice paid; it is reported to the provider).

Pitfalls

  • dispute and confirm_not_paid need a message of at least ten characters.
  • withdraw can cost a fee at the provider once its free period has passed (gnubok_get_collection_case withdraw_fee.may_apply): show the user, then pass fee_acknowledged=true.
  • already_paid is never sent: record the payment on the invoice instead (409 COLLECTION_REGISTER_PAYMENT); it is reported to the provider.
  • start is not taken here: starting a delivered invoice is a handover, through gnubok_send_invoice_to_collection (409 COLLECTION_START_VIA_HANDOVER).
  • 409 CONNECTOR_COLLECTIONS_ACTION_UNAVAILABLE: the case does not offer that action in its current stage.
  • Over REST, an escalation (approve_step, contest_dispute, confirm_not_paid, approve_legal_action) is sent with ?stage=true: a direct call answers 400 STAGE_REQUIRED. pause, resume, withdraw and dispute also commit directly.

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
action"start" | "pause" | "resume" | "withdraw" | "dispute" | "contest_dispute" | "approve_step" | "already_paid" | "confirm_not_paid" | "approve_legal_action" | "decline_legal_action"yes
step"reminder" | "collection" | nullnoFor start: where the provider begins.
messagestring | nullnoRequired (at least ten characters) for dispute and confirm_not_paid.
untilstring | nullnoFor pause: paused until and including this date, after today and at most 14 days ahead.
fee_acknowledgedbooleannoFor withdraw: the user has seen that the provider may charge a fee for withdrawing once its free period has passed (gnubok_get_collection_case withdraw_fee). Without it such a withdrawal answers 409 COLLECTION_WITHDRAW_FEE_UNACKNOWLEDGED.

Response fields

NameType
caseobject

Example request

{
  "invoice_id": "7d1e…",
  "action": "pause",
  "until": "2026-11-01"
}

Example response

{
  "data": {
    "case": {
      "case_id": "2b9c…",
      "stage": "paused"
    }
  },
  "meta": {
    "request_id": "req_…",
    "api_version": "2026-05-12"
  }
}