Pagination
Two mechanisms are available. Both need an explicit order to be stable - without one the database may return rows in a different sequence between pages, silently skipping or duplicating records.
Limit and offset
curl "https://taa.data.tidio.com/ticket_details?select=ticket_id,subject,created_at&order=_unique_id.asc&limit=1000&offset=0" ...Advance offset by limit for each page.
Range headers
The equivalent using HTTP ranges. Ranges are inclusive, so 0-999 is the first 1000 rows:
curl -i "https://taa.data.tidio.com/ticket_details?select=ticket_id,subject&order=_unique_id.asc" \
-H "X-Tidio-Openapi-Client-Id: $TIDIO_CLIENT_ID" \
-H "X-Tidio-Openapi-Client-Secret: $TIDIO_CLIENT_SECRET" \
-H "Range-Unit: items" \
-H "Range: 0-999"Counting rows
Send a Prefer header to have the total reported in Content-Range. The response echoes back which behaviour was actually applied in a Preference-Applied header:
Prefer | Behaviour | Cost |
|---|---|---|
| (omitted) | Content-Range: 0-9/* - no total | free |
count=exact | Content-Range: 0-9/112 - precise total | scans the whole table |
count=planned | planner estimate | cheap |
count=estimated | exact when small, planned when large | cheap |
curl -i "https://taa.data.tidio.com/agent_details?select=_unique_id&limit=1" \
-H "X-Tidio-Openapi-Client-Id: $TIDIO_CLIENT_ID" \
-H "X-Tidio-Openapi-Client-Secret: $TIDIO_CLIENT_SECRET" \
-H "Prefer: count=exact"
# Content-Range: 0-0/112
# Preference-Applied: count=exactOn the large tables, use count=planned - count=exact will time out.
Keyset pagination for full extracts
offset gets slower as it grows, because the database still walks every skipped row. For a complete extract, filter on the last id you saw instead. Page 500 then costs the same as page 1:
# First page
curl "https://taa.data.tidio.com/ticket_details?select=_unique_id,ticket_id,subject&order=_unique_id.asc&limit=1000" ...
# Subsequent pages - feed the last _unique_id back in
curl "https://taa.data.tidio.com/ticket_details?select=_unique_id,ticket_id,subject&_unique_id=gt.15664967821407535453&order=_unique_id.asc&limit=1000" ...Stop when a page returns fewer rows than the limit.
Choosing a page size
1000 rows is a good default. On the widest and largest tables - live_chat_message_details, ticket_message_details, visitor_details, ticket_details, flow_statistics_daily - use 500 to stay clear of the 25s timeout.
Paging past the end
Behaviour differs depending on whether you asked for a count:
| Request | Result |
|---|---|
offset past the end, no count | 200 with [] and Content-Range: */* |
offset past the end + Prefer: count=exact | 500 with PGRST103 |
Range past the end | 200 with [] and Content-Range: */* |
{"detail": {"code": "PGRST103", "details": "An offset of 999 was requested, but there are only 112 rows."}}If you page with a count, read the total from Content-Range first and stop before the end.
Updated 17 days ago