Register payments and read unplaced payments
Inbound payments normally arrive through bank files, but you can also post them through the API, for example from an ERP that receives the bank statements itself. A payment that cannot be linked to a debt becomes an unplaced payment, which you read through a separate set of endpoints. The people who work those payments in the Operations Portal are described in the knowledge base.
Register payments in bulk
Section titled “Register payments in bulk”POST /payments/multiple registers many payments for one bank account, one date and one currency.
It needs CreatePaymentTransactions, or CreatePaymentTransactionsClientRestricted for a token
that belongs to a client. POST /payments registers a single payment.
curl -X POST "https://$HOST/payments/multiple" \ -H "Authorization: Bearer $JWT" -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "paymentAccountNumber": "'"$ACCOUNT_NUMBER"'", "paymentDate": "2026-09-01", "currency": "SEK", "payments": [ { "amount": 1250.00, "amountLocale": 1250.00, "externalId": "ERP-2026-0001", "references": ["123456789"], "links": [] }, { "amount": 800.00, "amountLocale": 800.00, "externalId": "ERP-2026-0002", "links": [{ "invoiceId": "'"$INVOICE_ID"'", "amount": 800.00 }] } ] }'Request body
Section titled “Request body”| Field | Notes |
|---|---|
paymentAccountNumber or paymentAccountId |
The bank account the money arrived on. One of them is required |
paymentDate |
Required. A date inside a locked accounting period is refused |
currency |
Required. The currency of the payments |
dcaPaymentUniversal |
Optional. Marks every payment in the request as a debt collection agency payment. A payment’s own dcaPayment overrides it |
payments |
Required. The list of payments |
payments[].amount, payments[].amountLocale |
The amount in the payment currency and in the system currency |
payments[].references, payments[].descriptions |
Lists of strings (for example an OCR number). Quiddly matches on them |
payments[].externalId |
Your own reference for the payment, see below |
payments[].links |
Required: explicit links, for example invoiceId or partPaymentPlanId with an amount. A token that does not belong to a client can send an empty list when the payment should be matched on its references. A payment without the key fails with 'links'. A token that belongs to a client must send at least one link, see below |
payments[].sender |
Optional sender details |
Quiddly checks that the required fields are present, and each payment is then validated on its own.
What happens to each payment
Section titled “What happens to each payment”-
Every payment is handled separately. A payment that fails is reported and does not stop the others. The response lists both outcomes:
{"paymentBatchId": "...","succeeded": { "<paymentId>": { "id": "<paymentId>", "externalId": "ERP-2026-0001", "...": "..." } },"failed": { "2": "Only payments towards accounts that we handle can be registered" }}succeededis keyed by the id Quiddly gave the payment, and holds the payment.failedis keyed by the position of the payment in yourpaymentslist, counting from 1, and holds the reason. -
With
links, your links are used as they are. Links with anamountof 0 are ignored. A link points to its target with one ofinvoiceId,partPaymentPlanId,partPaymentAccountId,clientAccountId,collectionBatchNumber,businessLoanNumberorbusinessLoanId. A link to a target that does not exist fails the payment, reported underfailedas for exampleInvoice I.123 does not exist. A link that names its target only withcollectionBatchId,enforcementId,debitInvoiceIdorcreditInvoiceIdalso fails the payment: usecollectionBatchNumberfor a collection batch andinvoiceIdfor an invoice. A link with none of these fields is skipped, and the amount that is not linked stays on the payment, which then is partly linked or unplaced. The links cannot add up to more than the payment. -
Without
links, Quiddly matches the payment itself on itsreferencesanddescriptions, and what it cannot match becomes an unplaced payment. This only applies to a token that does not belong to a client. The first payment in the example above is of this kind. -
A token that belongs to a client must send
links. An empty list fails the payment withLinks cannot be empty, and every link must point to something that belongs to the client. Such a payment is never matched by Quiddly. If none of its links points to a target, the whole amount becomes an unplaced payment for the client. -
Bookkeeping runs after the call. Each payment is sent to bookkeeping straight away, but the work is done in the background. An unplaced payment shows up in the unplaced payment endpoints once its batch has been booked.
externalId is your own reference
Section titled “externalId is your own reference”externalId is free text. Quiddly stores it and returns it unchanged next to the payment id, so you
can map each answer to the line you sent. It is not used for matching, it is not validated, and it
is not unique. Do not put personal data in it. There is no other per-payment reference field:
references and descriptions are for matching, not for your own bookkeeping.
Large requests and retries
Section titled “Large requests and retries”There is no fixed limit on the number of payments in one request, but each payment is created and sent to bookkeeping one at a time inside the request, so a very large request is slow and can time out. Split large batches into several smaller requests.
The endpoint honours the Idempotency-Key header. Send a new key with each request and reuse it
when you retry, and a retry after a network failure returns the stored response instead of
registering the payments twice. See
Idempotency and errors.
Read unplaced payments
Section titled “Read unplaced payments”| Endpoint | Right | What it does |
|---|---|---|
GET /unplaced-payments |
ReadUnplacedPayments |
List unplaced payments |
POST /unplaced-payments/search |
SearchUnplacedPayments |
Filter them, for example { "status": "OPEN" } |
GET /unplaced-payments/<id> |
ReadUnplacedPayment |
Read one |
A token that belongs to a client uses the client-restricted versions of these rights instead, see the rights catalogue. Lists follow Pagination and search.
curl -X POST "https://$HOST/unplaced-payments/search" \ -H "Authorization: Bearer $JWT" -H "Content-Type: application/json" \ -d '{ "status": "OPEN" }'Two status fields tell you where a payment stands. status is on the unplaced payment, and
matching.status describes the payment behind it.
status |
Meaning |
|---|---|
OPEN |
There is still a balance to place |
REVENUE |
The balance has been booked as revenue. The payment stays open, see the knowledge base |
LINKED |
No balance is left |
matching.status |
Meaning |
|---|---|
LINKED |
Fully matched |
LINKED_PART |
Partly matched, with a balance remaining |
UNPLACED |
Not matched |
UNPLACED_RETURNED |
Returned to the sender, no balance left |
UNPLACED_WRITEOFF |
Written off, no balance left |
INFO |
A payment with the amount zero, kept for information |
balance and balanceLocale are what is left to place, and revenueBalance is what has been booked
as revenue.