Skip to content

GET /api/agent/invoices

Returns AR invoices (CashItem source = XERO_INVOICE) for the caller's org. Filterable by Xero status, contact, and date range. Two pagination modes: (1) cursor pagination via cursor / nextCursor (default, max 200 rows per page — caller MUST loop until nextCursor is null), or (2) ?autoPaginate=true opt-in which loops pages server-side and returns the combined set in one response (hard-capped at 5,000 rows; truncated: true is set when the cap is hit so the caller knows to fall back to cursor mode). For sum/total calculations always use ?autoPaginate=true or loop the cursor to completion — reporting partial-page sums as totals is the most common agentic failure mode this endpoint guards against. The response always includes totalCount (pre-redaction match count) so agents can decide up-front whether to paginate. Opt-in totals (?totals=true): when set, the response carries an aggregate totals.byStatus + totals.grandTotal block computed across the full filtered set (not just the page); prefer this over ?autoPaginate=true for pure aggregate questions ("how much have I invoiced YTD?") as it avoids transporting the rows. Set lines=true to include each invoice's XeroInvoiceLine[]. Line items carry per-unit pricing (quantity, unitAmount) plus line-level discount data (discountRate 0–1, discountAmount, lineSubtotal) so callers can reconcile lineSubtotal * (1 - discountRate) ≈ lineAmount without going back to Xero. Sensitive contacts and (when lines=true) sensitive account codes drop invoices from the response unless the key carries READ_SENSITIVE; the redactedItemCount field surfaces the count of dropped rows. This endpoint EXCLUDES credit notes (CN-####) — they are a separate Xero document type. Use /api/agent/credit-notes (and /api/agent/credit-notes/{id}) to look those up. A 'not found' here does NOT mean a claimed credit doesn't exist; check the credit-note endpoint before concluding a credit is absent.

Auth

  • Required scope: READ_INVOICES
  • Header: Authorization: Bearer cr_live_<prefix>_<secret>

Query parameters

NameTypeRequiredNotes
statusstringnoComma-separated list of Xero invoice statuses: DRAFT, SUBMITTED, AUTHORISED, PAID, VOIDED, DELETED. Unknown values are ignored.
contactIdstringnoFilter by Xero contact external id.
dateFromstringnoInclusive lower bound on the issue date (issueDate, falling back to the due date when the issue date is unknown) (YYYY-MM-DD).
dateTostringnoInclusive upper bound on the issue date (issueDate, falling back to the due date when the issue date is unknown) (YYYY-MM-DD; expanded to end-of-day UTC).
cursorstringnoOpaque cursor returned by a prior request's nextCursor.
limitintegernoMax rows per page. Capped at 200.
linesbooleannoWhen true, include XeroInvoiceLine[] per invoice.
autoPaginatebooleannoWhen true, the server loops pages internally and returns the combined matched set in one response (hard-capped at 5,000; truncated: true is set on overflow). Mutually exclusive with cursorcursor is silently ignored when autoPaginate=true. Use this for sum / aggregate reads to avoid partial-page-totalling bugs.
totalsbooleannoWhen true, the response carries an aggregate totals block computed across the FULL filtered set (NOT just the page). Shape: { byStatus: { PAID: { count, amount }, AUTHORISED: {...}, ... }, grandTotal: { count, amount }, currency }. Mixed-currency sets short-circuit to { mixedCurrency: true, primaryCurrency, byStatus: null }. Over the 100K aggregation cap, totals is omitted and totalsTruncated: true is set instead. Off by default — the aggregation runs an extra GROUP BY status, SUM(amount) query so reserve it for the questions that need it.

Responses

200 — Page of invoices

Body: InvoicesResponse

FieldTypeRequiredNotes
invoicesarray of Invoiceyes
nextCursorstringyesOpaque base64url cursor — pass back as ?cursor=... on the next request. Always present; null signals 'this is the last page in this view'. Both the natural last page AND an ?autoPaginate=true response (truncated or not) emit null — truncation is signalled via the separate truncated field, not via the cursor.
totalCountintegeryesTotal number of rows matching the request filters (pre-redaction). Reconciles to Xero source-of-truth; the page array may be shorter if sensitive rows were dropped (the delta is redactedItemCount). Always present.
redactedItemCountintegeryesNumber of rows withheld in this page due to sensitive-data gating. Always 0 when the key carries READ_SENSITIVE.
truncatedbooleannoPresent and true only when ?autoPaginate=true was requested and more than 5,000 rows matched. The response carries the first 5,000 rows; fall back to cursor pagination (drop autoPaginate=true) to read the rest. Absent on healthy responses.
totalsInvoiceBillTotalsno
totalsTruncatedbooleannoPresent and true only when ?totals=true was requested AND the matched set exceeded the 100,000-row aggregation cap. The totals block is omitted in this case; refine the filter (date range / status) to bring the scan back under the cap.
billingAlertBillingAlertno
xeroAlertXeroAlertno

401 — Unauthorized

Body: ErrorResponse

FieldTypeRequiredNotes
errorstringyes

403 — Key lacks the required scope

Body: ErrorResponse

FieldTypeRequiredNotes
errorstringyes

429 — Rate-limited or quota-exhausted

Body: ErrorResponse

FieldTypeRequiredNotes
errorstringyes

Response headers

Every successful response carries X-CashRunway-Subscription, X-CashRunway-Plan, X-CashRunway-Quota-Remaining, and X-CashRunway-Quota-Reset. Trialing subscriptions also include X-CashRunway-Trial-Days-Remaining. See the overview for details.

Released under a proprietary license. · cashrunway.ai