Skip to content

Credit accounts

Everything here needs credit:read. Check what you hold with GET /v1/me.

Endpoint Returns
GET /v1/credit-accounts A page of allotments, filterable by siteId, divisionId, userId, active
GET /v1/credit-accounts/{creditAccountId} One allotment and its remaining balance
GET /v1/credit-accounts/{creditAccountId}/adjustments That account’s ledger - every debit and credit, with the order that caused it

Read-only. Credit is allotted by staff tooling and drawn down by the order flow. There is no credit:write scope, and no endpoint here creates or adjusts credit.

Its own scope, not orders:read. Balances are financial standing, and a partner running an order-status integration should not receive their customers’ remaining credit as a side effect of a scope they asked for to poll shipments.

Two behaviors that are not obvious from the endpoint list, and that are much cheaper to learn here than from a reconciliation that does not balance.

An account belongs to either a division or a user - exactly one of divisionId and userId is set on every account, and the other is null. They are published as two fields rather than one polymorphic holder so that a row which ever violated that is visible as such rather than silently attributed to the wrong party.

Both kinds come back by default. Narrow with ?divisionId= or ?userId=, or with ?siteId= for one granted site - GET /v1/credit-accounts?siteId=222 and GET /v1/sites/222/credit-accounts are the same request, same handler, same result. Use whichever reads better in your code; a siteId outside your grant is a 400 invalid_site_id either way.

Terminal window
# One division's allotments, live ones only
curl -s -H "Authorization: Bearer $TOKEN" \
"https://api.partners.collaterate.com/v1/credit-accounts?divisionId=4021&active=true"

Passing both filters is accepted and returns an empty page rather than an error: the two are mutually exclusive on every row, so the honest answer to “held by division 5 and user 9” is that there are none.

active must be exactly true or false. 1, yes and on are rejected rather than coerced, because every coercion rule anyone might expect disagrees with some other one about 0.

An expired or deactivated allotment stays in the list with active: false, rather than disappearing. Hiding it would make “inactive” and “never existed” look identical - the same decision users and divisions make. Pass ?active=true when you only want live ones.

Each adjustment is one movement of money and the order that caused it:

{
"amount": "-42.1700000000",
"type": "PRODUCT_DEBIT",
"orderNumber": 550123,
"postedOn": "2026-02-11T14:22:03.000Z"
}

type is a raw movement code, and the set is open. PRODUCT_DEBIT, TAX_DEBIT, SHIPPING_DEBIT, ORDER_HANDLING_DEBIT, ORDER_ITEM_HANDLING_DEBIT and their _CREDIT reversals are the ten values in use today, but there is no enumeration behind them upstream and nothing stops an eleventh appearing.

Match on the _DEBIT/_CREDIT suffix rather than enumerating the ten. Filtering with ?type= accepts any well-formed upper-case code - an unknown one returns an empty page rather than an error, so a new code does not break your integration on the day it ships.

Resolve orderNumber with GET /v1/orders/{orderNumber}.

All three list endpoints use the same cursor/limit contract as every other collection here: walk nextCursor until it is null. Default page size 50, capped at 200.

See Errors for the full table. The ones specific to this surface:

code Status Meaning
invalid_credit_account_id 400 Path segment is not a positive whole number of at most nine digits
invalid_site_id 400 The siteId filter is malformed, or names a site outside your grant
invalid_division_id · invalid_user_id 400 The filter is not a positive whole number
invalid_active 400 active was something other than exactly true or false
invalid_adjustment_type 400 type is not an upper-case movement code
invalid_cursor 400 The cursor could not be decoded - restart pagination without one
credit_account_not_found 404 No such account on your granted sites

An account that does not exist and one that sits on a site you were not granted return the identical 404, on purpose - see Tenancy and access. Asking for the adjustments of an account you cannot see is that same 404, not an empty page.