API basics
Pagination
Which lists come back in pages, how to walk them with a cursor, and which return everything at once.
Lists that can grow without bound (calls, leads, conversations, audit entries) come back one page at a time, newest first. You ask for the next page with the cursor the previous page gave you.
The shape of a page
{
"data": [{ "id": "call_9e1d..." }, { "id": "call_4b7a..." }],
"next_cursor": "eyJ0IjoiMjAyNi0xMC0yOFQwOToyOTo1OC4xMjM0NTZaIiwiaSI6ImNhbGxfNGI3YS4uLiJ9",
"has_more": true
}| Field | Meaning |
|---|---|
data | This page, newest first. |
has_more | true while there are older rows. |
next_cursor | Send it as cursor to get the next page; null on the last page. Treat it as opaque. |
Two query parameters drive it:
| Parameter | Meaning |
|---|---|
limit | Rows per page. Defaults to 50. Values above the maximum are lowered to it, not refused. |
cursor | The next_cursor from the page before. Leave it out for the first page. |
Keep every other filter (from, to, assistant_id, status, and so on) the same from page to page; the cursor only says where the last page stopped.
Which endpoints page
| Endpoint | Max limit | Notes |
|---|---|---|
GET/api/calls | 200 | Filters: assistant_id, status, call_type, from, to, q. |
GET/api/leads | 200 | Filters: project_id, from, to. |
GET/api/conversations | 200 | Also sorts: sort=created_at or message_count, dir=desc or asc. Add include_total=true for a total count. |
GET/api/audit-log | 200 | |
GET/api/chat-analytics/failures | 100 | |
GET/api/chat-analytics/incidents | 100 |
Everything else returns the whole list in data with no cursor: assistants, projects, phone numbers, publishable keys, webhooks, knowledge bases, alerts and the rest. Some are filtered by default: publishable keys list site keys unless you pass kind=test or kind=all, and an assistant's version history returns its latest 100. Webhook deliveries are the exception in between: GET/api/webhooks/{id}/deliveries returns the newest 100 attempts and has no further pages.
Walk every page
async function* allCalls(params = {}) {
let cursor
do {
const qs = new URLSearchParams({ ...params, limit: '200', ...(cursor ? { cursor } : {}) })
const res = await fetch(`https://api.myleadsfactory.tech/api/calls?${qs}`, {
headers: { Authorization: `Bearer ${process.env.MLF_API_KEY}` },
})
if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`)
const page = await res.json()
yield* page.data
cursor = page.has_more ? page.next_cursor : undefined
} while (cursor)
}
for await (const call of allCalls({ from: '2026-10-01T00:00:00Z' })) {
console.log(call.id, call.status)
}Rows that arrive while you page
Pages are ordered by creation time and id, so a row created after you started is never slipped into a later page: it is newer than your first page, and the next walk from the top picks it up. Rows created in the same millisecond keep their order too.