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, ignoring offset and limit. 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:

  1. offset >= total — you've seen every matching item.
  2. The current page is empty (results.length === 0) — defensive: covers edge cases where total changes 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=100 and accept the lossy semantics, or filter by a stable field (e.g. register_date range) per page.
  • limit=0 is legal but rarely useful — it returns just total and an empty results list. Use this to count without paginating.
  • offset past total returns an empty results list, not a 400. The walk-termination conditions above handle this naturally.

Endpoints that paginate

APIchat endpoints currently return single resources or operate on a single customer; none paginate.