Pagination

Cursor-based pagination for stable, consistent list traversal.

List endpoints use cursor pagination. The default ordering is
(created_at desc, id desc), which is stable: results don't shift as new
records are added while you page.

Request

ParameterDescription
limitPage size, 1-100 (default 25)
cursorOpaque cursor from the previous response's next_cursor

Cursors are opaque

Pass next_cursor back exactly as you received it. Do not parse it, construct
one, or persist it across sessions - the encoding is an implementation detail
and differs between endpoints.

A cursor is also tied to the query that produced it. Changing limit, any
filter, or sort_by mid-traversal invalidates it, and you may see skipped or
repeated rows. When the query changes, start again from the first page.

Response envelope

{
  "object": "list",
  "data": [ /* resources */ ],
  "has_more": true,
  "next_cursor": "MTcxOTg0..."
}

Paging through all results

cursor=""
while :; do
  resp=$(curl -s "https://studio.zentag.ai/api/v1/partner/clips?limit=100&cursor=$cursor" \
    -H "Authorization: Bearer $ZENTAG_SECRET_KEY")
  echo "$resp" | jq -c '.data[]'
  more=$(echo "$resp" | jq -r '.has_more')
  cursor=$(echo "$resp" | jq -r '.next_cursor // empty')
  [ "$more" = "true" ] && [ -n "$cursor" ] || break
done

Stop when has_more is false. Do not stop on an empty data array alone, and
do not keep calling with the same cursor - that loops forever.

Sorting

GET /highlights and GET /media accept sort_by. Anything other than the
default latest sorts on a non-unique column, so the cursor additionally
carries the timestamp and id as tiebreakers; rows with equal values still page
correctly.

sort_byOrdering
latestNewest first (default)
oldestOldest first
ratingHighest rated first
durationLongest first

Endpoints that don't paginate

A few list responses return everything in one page and always report
has_more: false with a null next_cursor, because the collections are
inherently small: GET /storage/buckets, GET /webhook-endpoints,
GET /webhook-endpoints/{id}/deliveries and GET /clips/{id}/jobs. They still
use the standard list envelope, so the loop above works unchanged.


Did this page help you?