Pagination
List endpoints are cursor-paginated. Cursors are stable and efficient even over large datasets, and there is deliberately no total count.
List envelope
Section titled “List envelope”Every list response has the same shape:
{ "object": "list", "data": [ { "object": "reservation", "id": "resv_…" } ], "has_more": true}data— the page of results.has_more—trueif more results exist after this page.
There is no total_count: computing an exact total is expensive and
race-prone on live data. Page until has_more is false.
Default order
Section titled “Default order”Without updated_since, each list endpoint has a stable default sort
(newest-first), with the resource id as a tie-breaker so the keyset cursor is
total:
| Endpoint | Default order |
|---|---|
GET /v1/reservations | by service_date descending, then id descending — the most recent service dates first. |
GET /v1/guests | by created_at descending, then id descending — most recently created guests first. |
GET /v1/reservations/{id}/events | by created_at ascending, then id ascending — oldest event first (chronological). |
Passing updated_since to
/v1/reservations or /v1/guests changes the sort to (updated_at, id)
ascending (see below), so a “changed since” feed reads oldest-change-first.
Parameters
Section titled “Parameters”| Parameter | Description |
|---|---|
limit | Page size. Default 20, maximum 100. (When you expand objects, the maximum is lowered.) |
starting_after | A resource id (resv_… / gst_…). Returns the page of results after that object. |
ending_before | A resource id. Returns the page of results before that object. |
Use the id of the last item in a page as starting_after to fetch the next
page:
# First pagecurl "https://api.useservice.app/v1/reservations?limit=20" \ -H "Authorization: Bearer $SERVICE_API_KEY"
# Next page — pass the last id you sawcurl "https://api.useservice.app/v1/reservations?limit=20&starting_after=resv_8xKQ2m4Vd0pErJ7sN1aZ9bQ" \ -H "Authorization: Bearer $SERVICE_API_KEY"Keep going while has_more is true.
Filtering
Section titled “Filtering”List endpoints accept filters alongside the pagination parameters (see the API reference for the full set per endpoint). A few matching rules worth knowing:
email(guests) is matched case-insensitively as an exact address —[email protected]and[email protected]return the same guest.phone(guests) is normalized to E.164 before matching, using the restaurant’s country. Pass the number however the guest gave it (local or international); it is canonicalized before the lookup.query(guests) is an accent-insensitive substring match over first name, last name, and email.
Filters combine with AND. An unknown filter value (for example an unknown
status or a malformed date) returns a 400 with the offending param —
see Errors.
Incremental sync with updated_since
Section titled “Incremental sync with updated_since”To keep a local copy in sync without re-reading everything, pass updated_since
(an ISO-8601 timestamp) to GET /v1/reservations or GET /v1/guests. You get
back only records changed at or after that time, sorted by (updated_at, id)
ascending. Combine it with cursor pagination as usual:
curl "https://api.useservice.app/v1/reservations?updated_since=2026-06-27T00:00:00Z&limit=100" \ -H "Authorization: Bearer $SERVICE_API_KEY"On the next sync, use the most recent updated_at you have seen as the new
updated_since.