Skip to main content

Pages

Lists take page (1-100,000, default 1) and perPage (1-100, default 25) and answer with the page envelope:
  • total is exact; totalPages is ceil(total / perPage) and 0 when nothing matches.
  • A page beyond totalPages returns 200 with an empty data list.
  • There are no cursors or next links; compute neighbours from page and totalPages.
  • A page or perPage outside its range → 400 data-failed-validation, constraint invalid-page with params.min / params.max.

Sorting

sort is one field; prefix it with - for descending (sort=field or sort=-field):
Each list has a default sort and an allow-list of fields (shown on its reference page). The API always appends id in the direction of the sort field, so the order is total and stable. Any other value, a comma-separated list included → 400 data-failed-validation, constraint invalid-sort with params.allowed (the sortable fields).

Searching

Lists that support it take search (1-255 characters): a case-insensitive substring match over the fields the reference page names, combined with filters by AND. A number also matches the id. Voucher values are never searched as text: on the vouchers list, search is an exact match on the full value, and only for principals with reveal-provider-vouchers; others get an empty page.

Filtering

Filters use bracket notation: Operators: eq, ne, in, gt, gte, lt, lte, contains, startsWith, isNull. Each list allows specific fields and operators (see its reference page). Rules:
  • at most 20 filter parameters per request and 100 values per in list (more → constraint invalid-filter);
  • a literal comma inside a value is written \,, a backslash \\;
  • null is not a value; use isNull;
  • an unknown field or operator, or a value of the wrong type → 400 data-failed-validation, constraint invalid-filter, property the parameter (filter[redeemedAt][gte]); any other undeclared parameter → the same 400 with the constraint unknown-parameter;
  • URL-encode the brackets if your HTTP client does not (filter%5Bstatus%5D=active).
Voucher set status filters use the effective status: a scheduled set whose activeFrom has passed counts as active even before the schedule has run.

Invalid list parameters

Every problem with the list parameters of one request comes back in one 400 data-failed-validation, one more.validationErrors item per problem:
There is no limit on page × perPage, but deep pages are slow and shift while rows are added: narrow the query with filters, or walk time windows as in Downloading large lists.

Syncing large collections

Offset pages can skip or repeat rows when data changes between requests. To keep a local copy in sync, filter by a time field and sort by it, then deduplicate by id:
Start the next run at the newest redeemedAt you saw minus 60 seconds: a redemption can become visible shortly after its timestamp. For a full copy see Downloading large lists; for near-real-time updates use webhooks.

Downloading large lists

There are no export endpoints: to get a whole list (for a CSV or spreadsheet), page through the list operation itself.
  • Use perPage=100 (the maximum on every list) and send the same filters, search and sort on every request.
  • For a small list, request pages 1 to totalPages.
  • For a large list (we recommend it above about 100 pages), walk time windows on the list’s download key instead, so rows added meanwhile do not shift the pages: createdAt, or redeemedAt for redemptions. Fix a cut-off at the start time, sort newest first, and after page 100 restart at page 1 with the last row’s value as the new upper bound, dropping ids you already have:
  • Rows created after the cut-off are not included; run again later for newer rows.
  • Send one request at a time. On 429, wait Retry-After and repeat the same request. Requests are limited at the network edge per source IP address (see Limits → Edge limits), and a 50,000-row download (500 requests) stays far below that limit.