Overview
Partners read invoices under/v1/invoices with scope invoices:read. The public contract is a lean profile by default (amounts, status, customer id, dates). Pass expand to add related fields. Office /api/v2/invoices remains the internal surface and may return richer fields.
Endpoints
List filters
GET /v1/invoices supports:
page,limit— pagination (default page 1, limit 25, max 100)open=true— only OPEN / OVERDUE / PARTIAL_PAID invoices with billing queue status POSTEDcustomerIds— comma-separated customer UUIDsinvoiceNumbers— comma-separated invoice numbersstatus— comma-separated status values (ignored whenopen=true)invoiceDateFrom/invoiceDateTo— ISO date-time bounds oninvoiceDateexpand— allowlisted tokens below; unknown tokens return400
Billing queue
GET /v1/invoices/billing-queue calls the same LoopBack billing-queue controller the office uses (Company.getPosted). Query args match that controller (q, billingQueueStatus, status, customers, date ranges, delivery, sales/accounting filters, haulers, labels, sort, pageNo, limit). Default tab is POSTED. The response is projected onto the public invoice list shape. Pass expand=customer,order,location to include those fields from the queue row.
Open for match
GET /v1/invoices/open-for-match shares the Nest open-for-match reader used by GET /api/v2/invoices/open-for-match. Query params: customerIds, invoiceNumbers, limit (default 50, max 100). With neither customer nor invoice number filter, the response is an empty list. Pass expand=customer for { id, displayName } on each row.
Get by id
GET /v1/invoices/{id} returns { data: PublicInvoice }. Cross-company ids return 404 NOT_FOUND. Pass detail expands (items, payments, creditNotes, paymentPolicy) to include those fields.
Expand
Passexpand as a comma-separated list. Default responses stay lean; expand only adds fields. Allowlists differ by route.
GET /v1/invoices and GET /v1/invoices/open-for-match
GET /v1/invoices/billing-queue
GET /v1/invoices/{id}
Unknown expand values fail closed with
400 BAD_REQUEST. A token valid on one route and invalid on another is rejected on the wrong route (for example items on billing-queue, or order on get).