GET /api/agent/bills
AP-side mirror of /api/agent/invoices. Returns CashItem rows with source = XERO_BILL. Identical filter / pagination / sensitive-data semantics, including the ?autoPaginate=true opt-in (caps at 5,000 rows; truncated: true on overflow). Use ?autoPaginate=true for sums / totals so you don't report a partial-page subtotal as a full-period figure. The response always includes totalCount (pre-redaction match count). Opt-in totals (?totals=true): mirrors the AR endpoint — adds an aggregate totals.byStatus + totals.grandTotal block across the full filtered set; ideal for "what's my YTD AP spend?" style questions without paginating. Lines (when requested) are joined from XeroBillLine. Note: the discountRate, discountAmount, and lineSubtotal fields on each line are always null on bills — AP discount support is deferred. The fields are present in the response shape for symmetry with /api/agent/invoices.
Auth
- Required scope:
READ_INVOICES - Header:
Authorization: Bearer cr_live_<prefix>_<secret>
Query parameters
| Name | Type | Required | Notes |
|---|---|---|---|
status | string | no | Comma-separated Xero statuses. Same vocabulary as /invoices. |
contactId | string | no | |
dateFrom | string | no | |
dateTo | string | no | |
cursor | string | no | |
limit | integer | no | |
lines | boolean | no | |
autoPaginate | boolean | no | When true, the server loops pages internally and returns every matching bill in one response (hard-capped at 5,000; truncated: true on overflow). Mutually exclusive with cursor. Prefer for sum / aggregate reads. |
totals | boolean | no | AP-side mirror of /invoices?totals=true. Same shape (byStatus + grandTotal + currency; mixed-currency short-circuit; 100K cap → totalsTruncated: true). Off by default. |
Responses
200 — Page of bills
Body: BillsResponse
| Field | Type | Required | Notes |
|---|---|---|---|
bills | array of Invoice | yes | |
nextCursor | string | yes | |
totalCount | integer | yes | Total bills matching the request filters (pre-redaction). See InvoicesResponse.totalCount. |
redactedItemCount | integer | yes | |
truncated | boolean | no | Present and true only when ?autoPaginate=true was requested and more than 5,000 rows matched. See InvoicesResponse.truncated. |
totals | InvoiceBillTotals | no | |
totalsTruncated | boolean | no | Present and true only when ?totals=true was requested AND the matched set exceeded the 100,000-row cap. See InvoicesResponse.totalsTruncated. |
billingAlert | BillingAlert | no | |
xeroAlert | XeroAlert | no |
401 — Unauthorized
Body: ErrorResponse
| Field | Type | Required | Notes |
|---|---|---|---|
error | string | yes |
403 — Key lacks the required scope
Body: ErrorResponse
| Field | Type | Required | Notes |
|---|---|---|---|
error | string | yes |
429 — Rate-limited or quota-exhausted
Body: ErrorResponse
| Field | Type | Required | Notes |
|---|---|---|---|
error | string | yes |
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.