Pagination
Page and cursor lists.
Two kinds of list, chosen by how the data grows.
Page lists
Contacts and templates page by number. per_page is at most 100.
GET /contacts?search=rahul&page=2&per_page=25
{
"data": [ … ],
"meta": { "current_page": 2, "per_page": 25, "total": 1204, "last_page": 49 },
"links": { "next": "https://…/contacts?search=rahul&page=3&per_page=25", "prev": "https://…/contacts?search=rahul&page=1&per_page=25" }
}
Follow links.next until it is null. meta.total is exact.
Cursor lists
Conversations and messages are append-heavy and can be very long, and an offset into a list that keeps growing skips or repeats rows. They page by cursor instead: an opaque token that means "after this row".
GET /conversations/{id}/messages?limit=50
{
"data": [ … ],
"meta": { "per_page": 50, "has_more": true },
"links": { "next": "https://…/messages?limit=50&cursor=eyJpZCI6Ij…", "prev": null }
}
Follow links.next while meta.has_more is true. There is no total; counting a thread of two hundred thousand messages on every page is what the cursor exists to avoid. Cursors are valid indefinitely for the same list and filters; a cursor from one filter used on another is refused.
Ordering
Messages come newest first (the latest page is page one), so a client that shows a thread reads the first page, renders it at the bottom, and follows next upward for history - the way a chat app scrolls. Conversations come by last activity, newest first. Contacts and templates come by name.
Rates
Walking a whole list counts against the request bucket like anything else: a full export of 50,000 contacts at 100 a page is 500 requests. For a one-off export ask the business for a CSV from the dashboard instead.
https://communication-api.artofluminaire.com
Every response carries X-Request-ID; quote it when you write to support.