Skip to navigation

Pagination

How list endpoints page through results.
View as Markdown

Jelliu uses four paging styles, depending on the endpoint. Each is described below with its parameter names and bounds.

StyleParametersUsed by
Cursorlimit, cursorGET /api/agents, GET /api/calls, GET /api/webhooks/{webhookId}/deliveries
Page numberpage, limitGET /api/campaigns, GET /api/campaigns/{campaignId}/contacts, GET /api/contacts
Message cursorlimit, beforeGET /api/conversations/{conversationId} (its messages)
Offsetlimit, offsetGET /api/widgets, GET /api/integrations, GET /api/mcp-servers, GET /api/exports, GET /api/agents/{agentId}/knowledge, GET /api/agents/{agentId}/tools

Parameters are query-string values. A value out of range is rejected with 400 VALIDATION_FAILED rather than silently clamped. See Errors.

Cursor

Items come newest first. Each page returns a cursor that marks the position of its last item; pass it back as cursor to get the items that come after it. Items created at the same instant are never skipped or repeated between pages.

The cursor is an opaque string. Pass it back exactly as you received it, and do not build, parse or store it as a date: its format can change.

  • Legacy timestamp cursors. Until 2026-09-15 the cursor was the ISO 8601 created_at of the last item. A timestamp is still accepted and keeps its old meaning, items created strictly before that instant, so a client holding one keeps working. It can skip items created at the same instant as the boundary, so switch to the returned cursor.
  • Malformed cursors. Any other value returns 400 VALIDATION_FAILED with details.fieldErrors.cursor.

Agents

limit
integer

1 to 200. Defaults to 50.

cursor
string

The meta.nextCursor value from the previous page. A legacy ISO 8601 timestamp is also accepted.

search
string

Case-insensitive match on the agent name. 1 to 200 characters.

GET /api/agents returns { "data": [ ... ], "meta": { "nextCursor": "..." } }. data is the array of agents. Pass meta.nextCursor as cursor to fetch the next page. It is null when the page has fewer items than limit, which means you have reached the end.

curl -sS "https://api.jelliu.co/api/agents?limit=50&cursor=MjAyNi0wOS0wMVQxNTowNDowNS4wMDAwMDBafDdjMWU0YjJhLTlkM2YtNGU4YS1iNWM2LTJmMWEwZDllOGI3Yw" \
-H "Authorization: Bearer $JELLIU_API_KEY"

Calls

limit
integer

1 to 100. Defaults to 50.

cursor
string

The nextCursor value from the previous page. A legacy ISO 8601 timestamp is also accepted.

offset
integer

0 to 100000. Alternative to cursor for numbered pages. A non-zero offset takes precedence over cursor.

agentId
string (uuid)

Only calls handled by this agent.

campaignId
string (uuid)

Only calls from this campaign.

GET /api/calls returns the page together with its paging state:

{
"data": {
"calls": [ { "id": "...", "created_at": "..." } ],
"total": 1284,
"limit": 50,
"offset": 0,
"nextCursor": "MjAyNi0wOS0xMFQxODoyMjo0MS41MTIwMDBafDBiOGY1YzJkLTNlNGEtNGI2Yy05ZDdlLTFmMmEzYjRjNWQ2ZQ"
}
}

nextCursor is null when the page holds fewer than limit calls. Pass it back as cursor to continue:

async function* allCalls(apiKey) {
let cursor = null;
do {
const url = new URL('https://api.jelliu.co/api/calls');
url.searchParams.set('limit', '100');
if (cursor) url.searchParams.set('cursor', cursor);
const res = await fetch(url, { headers: { Authorization: `Bearer ${apiKey}` } });
const { data } = await res.json();
yield* data.calls;
cursor = data.nextCursor;
} while (cursor);
}

Listing calls uses the general API limit of your plan; it does not spend the 20-per-minute budget for placing calls. Use limit=100 when walking the full history. See Rate limits.

Webhook deliveries

GET /api/webhooks/{webhookId}/deliveries takes limit (1 to 100, default 50) and cursor, plus the optional filters status and type. It returns { "data": [ ... ], "meta": { "next_cursor": "..." } }, newest first; pass meta.next_cursor back as cursor for the next page. It is null when there is nothing more. A cursor this endpoint did not return is refused with 400 VALIDATION_FAILED (El cursor no es válido.); timestamps are not accepted. Deliveries are kept for 30 days. See Delivery log.

Page number

page
integer

1-based page number. 1 to 100000. Defaults to 1.

limit
integer

1 to 100. Defaults to 20 for campaigns and 50 for contacts.

Extra filters:

  • GET /api/campaigns/{campaignId}/contacts accepts status.
  • GET /api/contacts accepts search (1 to 200 characters) over phone, name and email.

Response shapes:

EndpointShape
GET /api/campaigns{ "data": [ ... ], "meta": { "page": 1, "limit": 20 } }
GET /api/campaigns/{campaignId}/contacts{ "data": { "contacts": [ ... ], "total": 0, "page": 1, "limit": 50 } }
GET /api/contacts{ "data": { "contacts": [ ... ], "total": 0, "page": 1, "limit": 50 } }

Contact lists report total, so you can compute the number of pages. The campaign list does not; stop when a page returns fewer than limit items.

Message cursor

GET /api/conversations/{conversationId} pages the thread’s messages backwards, from the newest.

limit
integer

1 to 200. Defaults to 50.

before
string (uuid)

The ID of a message in this conversation. The page holds the limit messages immediately older than it.

Each page is in chronological order (oldest first), and the response carries the cursor under meta:

{
"data": { "id": "3f6a2c1e-8b4d-4f7a-9e2b-5c8d1a0f7e36", "messages": [ ] },
"meta": {
"messages": { "limit": 50, "hasMore": true, "nextBefore": "c7d8e9f0-1a2b-4c3d-8e4f-5a6b7c8d9e0f" }
}
}

Without before you get the most recent messages. While hasMore is true, pass nextBefore (the ID of the oldest message on the page) as before to read further back; it is null on the first page of the thread. Messages sharing a timestamp are never skipped or repeated between pages. See Conversations for a full example.

Offset

limit
integer

1 to 100. Defaults to 50.

offset
integer

Number of items to skip. 0 to 100000. Defaults to 0.

curl -sS "https://api.jelliu.co/api/widgets?limit=50&offset=50" \
-H "Authorization: Bearer $JELLIU_API_KEY"

Stop when a page returns fewer than limit items.

Endpoints without paging

Some lists are small and take no paging parameters. For example, GET /api/webhooks returns every webhook of the workspace (at most 20), newest first, and GET /api/webhooks/event-types returns the whole event catalog.