Pagination
Every Platform API listing endpoint uses the same offset/limit/total pattern. Documented once, here.
Every Platform API endpoint that returns a list — GET /channels/, GET /customers/, GET /channels/{channel_id}/message_hooks/ — uses the same three query parameters and response shape.
Query parameters
| Parameter | Type | Default | Range | Meaning |
|---|---|---|---|---|
offset |
integer | 0 |
≥ 0 | Number of items to skip from the start. |
limit |
integer | 20 |
0–100 |
Maximum items to return in this page. |
There is no cursor. Pagination is purely numeric.
Response shape
{
"success": true,
"total": 2000,
"customers": [
{ "id": 42, "name": "Ataulfo", "...": "..." }
]
}
total— the total number of items matching the filter, ignoringoffsetandlimit. Use it to decide when to stop.- The resource key (
customers,channels,hooks, ...) holds the current page.
Iterating a complete list
async function listAllCustomers(token, filters = {}) {
const out = [];
const limit = 100; // max allowed
let offset = 0;
while (true) {
const params = new URLSearchParams({ ...filters, offset, limit });
const res = await fetch(`https://api.landbot.io/v1/customers/?${params}`, {
headers: { 'Authorization': `Token ${token}` },
});
const data = await res.json();
out.push(...data.customers);
offset += data.customers.length;
if (offset >= data.total || data.customers.length === 0) break;
}
return out;
}
import requests
def list_all_customers(token, **filters):
out = []
limit = 100
offset = 0
while True:
res = requests.get(
'https://api.landbot.io/v1/customers/',
headers={'Authorization': f'Token {token}'},
params={**filters, 'offset': offset, 'limit': limit},
).json()
out.extend(res['customers'])
offset += len(res['customers'])
if offset >= res['total'] or not res['customers']:
break
return out
Stopping conditions
Two conditions terminate a paginated walk:
offset >= total— you've seen every matching item.- The current page is empty (
results.length === 0) — defensive: covers edge cases wheretotalchanges between calls or the filter is suddenly empty.
Check both. A naive for offset in range(0, total, limit) loop will miss the second condition.
Filters and pagination interact
Filters like channel_id, agent_id, archived, opt_in (on /customers/) or type, active (on /channels/) narrow the result set before pagination. total reflects the filtered count, not the workspace-wide count.
# Returns the count and first 20 archived customers in channel 8
curl 'https://api.landbot.io/v1/customers/?channel_id=8&archived=true&limit=20' \
-H 'Authorization: Token YOUR_AGENT_TOKEN'
Caveats
- Pagination is not snapshot-consistent. If new customers are created (or existing ones deleted) during a long walk, you can see duplicates across pages or miss items. For high-churn iterations, fetch the list quickly with
limit=100and accept the lossy semantics, or filter by a stable field (e.g.register_daterange) per page. limit=0is legal but rarely useful — it returns justtotaland an empty results list. Use this to count without paginating.offsetpasttotalreturns an empty results list, not a400. The walk-termination conditions above handle this naturally.
Endpoints that paginate
GET /channels/GET /customers/GET /channels/{channel_id}/message_hooks/GET /channels/whatsapp/templates/— small, fixed result, but follows the same shape
APIchat endpoints currently return single resources or operate on a single customer; none paginate.