Pagination
Cursor-based, opaque, stable across writes. Filter and sort grammar.
List shape
GET /v2/<surface>/<resource>
?sort=<field>|-<field>[,...]
&filter[<field>]=<value>
&filter[<field>][op]=<value> # for non-equality
&page[size]=<n>
&page[after]=<cursor>
&page[before]=<cursor>
&include=<rel>[,<rel>...] # optional embed
→ 200 {
"data": [<Resource>...],
"page": {
"next_cursor": "...",
"prev_cursor": "...",
"has_more": true,
"size": 25
},
"meta": { "count": 1234 } # only present when ?meta=count is requested
} Sort
- One or more fields, comma-separated.
-prefix for descending; no prefix = ascending.- Per-endpoint sortable-field whitelist declared in OpenAPI. Sorts on non-whitelisted fields return
400 invalid_sort_field. - Default sort per endpoint (typically
-inserted_at).
?sort=-launched_at
?sort=-launched_at,name Filter
filter[<field>]=<value>for equality.filter[<field>][<op>]=<value>for comparisons.- Allowed ops:
eq,neq,lt,lte,gt,gte,in(comma-separated),nin,contains,starts_with,ends_with,present,missing. - Multiple filters AND together. For OR semantics on contact lists, use a Cohort.
?filter[status]=launched
?filter[launched_at][gte]=2026-01-01
?filter[objective_keys][in]=direct_deposit,card_activation Pagination
Cursor-based, opaque, stable across writes. Cursors are base64-encoded JSON of {sort_key_values, position_token, sort_signature}. Clients treat them as opaque.
page[size]is the requested page size. Server caps at endpoint-defined max (typically 100). Default 25.page[after]=<cursor>returns the next page.page[before]=<cursor>returns the previous page.- Newly-inserted rows that match the filter appear at the boundaries of the current pagination window, not retroactively in pages the client already fetched.
- Cursors stay valid until the underlying sort or filter shape changes. If they don't, the server returns
410 cursor_invalid— re-fetch from page 1.
Count
meta.count is returned only when requested via ?meta=count. Counting is expensive; opt-in.
For aggregate-shaped responses (rates, time series), count is part of the typed payload, not the meta.
Include (relationship embed)
?include=<rel>[,<rel>] embeds related resources in the response. Embedded resources land in data[].relationships.<rel> as fully-typed resources (not just IDs).
Per-endpoint includeable-relationship whitelist declared in OpenAPI. Embedding does NOT bypass authorization — the consumer must have read scope on the included resource type.
Errors
| Code | HTTP | Meaning |
|---|---|---|
invalid_sort_field | 400 | Sort references a non-whitelisted field |
invalid_filter_field | 400 | Filter references a non-whitelisted field |
invalid_filter_op | 400 | Filter uses an unsupported op |
invalid_page_size | 400 | Exceeds endpoint max |
cursor_invalid | 410 | Sort or filter shape changed since cursor was issued |