Pagination and filtering
Lists that grow with your customer volume page with cursors, and you filter them with one field[operator]=value grammar. Code that pages and filters one list works for the others.
Read a list response
Every list that grows with your customer volume is cursor-paginated and returns the same shape:
{
"object": "list",
"data": [ … ],
"has_more": true,
"next_cursor": "k:inv_9f2c…",
"total": 1284
}
Page through a list
Pass next_cursor back as starting_after:
curl "$TMBILLING_URL/v1/businesses/$BIZ/invoices?limit=50" \
-H "Authorization: Bearer $TMBILLING_API_KEY"
curl "$TMBILLING_URL/v1/businesses/$BIZ/invoices?limit=50&starting_after=k:inv_9f2c…" \
-H "Authorization: Bearer $TMBILLING_API_KEY"
limit defaults to 50 and caps at 1000. Treat next_cursor as opaque — it encodes how tmbilling
is walking the current sort, so parsing it breaks when the sort changes.
has_more: false means the end of the list. A page can be shorter than limit and still not be
the last one.Filter a list
Write filters as field[operator]=value:
?created_at[after]=2026-09-01&status[in]=paid,posted
There is no generic filters parameter. Each filterable field is its own documented query
parameter, and any query key that is neither a filter nor a documented parameter returns 400.
So a misspelled filter tells you, rather than quietly returning an unfiltered list.
Select an operator
| Field type | Operators |
|---|---|
| Text | is, is_not, contains, not_contains, starts_with, ends_with, is_present |
| Enum | is, is_not, in, not_in, is_present |
| Boolean | is |
| Number | is, is_not, gt, gte, lt, lte, between, is_present |
| Date | on, before, after, between, in_last, in_next, is_present |
Most operators take one scalar. Four take something else:
| Operator | Value | Example |
|---|---|---|
in, not_in | a comma-separated set | status[in]=paid,posted matches any member |
between | exactly two values | total[between]=1000,5000, both ends inclusive |
in_last, in_next | a number of days | created_at[in_last]=30 — days, not hours, not an ISO duration |
is_present | true or false | po_number[is_present]=false asks whether the field is set |
Give dates in ISO-8601. tmbilling resolves day boundaries in the business's timezone rather
than UTC, so created_at[on]=2026-09-01 means that calendar day where the business is — the same
day the row is labelled with everywhere else.
Sort a list
?sort_by[desc]=created_at
?sort_by[asc]=total
Sort on one field at a time. tmbilling returns newest first by default.
Search a list
Lists that support it take q=<text> and search the fields a person would search by, such as a
customer's name and email or an invoice number. Combine it with filters:
curl "$TMBILLING_URL/v1/businesses/$BIZ/customers?q=ada&status[is]=active&limit=20" \
-H "Authorization: Bearer $TMBILLING_API_KEY"
Related
Errors
Read one error format across the whole API, branch on a small set of error types, and know from the status code whether anything was processed before it failed.
Rate limits
Read the rate-limit headers on every response, slow your client down before requests are refused, and design your integration so it never reaches the limit.