Skip to content

GET /api/agent/contacts

Returns XeroContact rows for the caller's org. Filter by type (customer|supplier|both, default both) and sort (revenue_desc|spend_desc|recent_desc, default recent_desc). Two pagination modes: cursor (cursor / nextCursor, default — caller MUST loop until nextCursor is null) or ?autoPaginate=true to receive the entire matched set in one response (hard-capped at 5,000; truncated: true on overflow). The response always includes totalCount (pre-redaction match count) so agents can answer 'how many customers do we have?' without iterating. Opt-in totals (?totals=true): adds a totals.byType block (customer / supplier / both / neither counts) honouring the type filter; count-only (contacts have no $ axis — LTV / spend live on TrendBaseline). Contacts flagged sensitive (isSensitive) are dropped unless the key carries READ_SENSITIVE; the dropped count surfaces as redactedItemCount.

Auth

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

Query parameters

NameTypeRequiredNotes
typestringno
sortstringnorevenue_desc / spend_desc sort the returned page in-memory by TrendBaseline.ltvCumulative (nulls last). recent_desc orders by lastSyncedAt — the default.
cursorstringno
limitintegerno
autoPaginatebooleannoWhen true, the server loops pages internally and returns every matching contact in one response (hard-capped at 5,000; truncated: true on overflow). Mutually exclusive with cursor. Prefer for aggregate reads (e.g. "how many customers do we have?"). The totalCount response field gives the count without forcing autoPaginate.
totalsbooleannoWhen true, the response carries a totals block with byType counts (customer / supplier / both / neither) + grandTotal.count. NO $ axis (contacts have no aggregable amount — LTV / spend live on TrendBaseline). Honours the type filter. Over the 100K cap → totalsTruncated: true.

Responses

200 — Page of contacts

Body: ContactsListResponse

FieldTypeRequiredNotes
contactsarray of ContactSummaryyes
nextCursorstringyesOpaque base64url cursor — pass back as ?cursor=.... Always present; null signals the last page in this view. ?autoPaginate=true responses always carry null here — truncation is signalled separately via truncated: true.
totalCountintegeryesTotal number of contacts matching the request filters (pre-redaction). See InvoicesResponse.totalCount.
redactedItemCountintegeryesNumber of contacts withheld 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 contacts matched. See InvoicesResponse.truncated.
totalsContactsTotalsno
totalsTruncatedbooleannoPresent and true only when ?totals=true was requested AND the matched contact set exceeded the 100,000-row 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.