pagination.md

Pagination

How MachineMail list endpoints page with limit, page_token and next_page_token: walking every page, sort order, and the endpoints that page differently.

Source: https://machinemail.dev/docs/reference/pagination

List endpoints page with three query parameters and return three fields, the same as AgentMail.

Query parameter Type Default Meaning
limit integer 50 Items per page. Values above 500 are capped at 500. A missing value, 0 or a negative number means 50; decimals are rounded down. A non-number returns 400 limit must be a number.
page_token string none The next_page_token from the previous page.
ascending boolean false true for oldest first. Most lists are newest first by default.
{
  "count": 50,
  "limit": 50,
  "next_page_token": "eyJvIjo1MH0",
  "inboxes": [ ... ]
}
Field Meaning
count Number of items in this page (not a total).
limit The limit that was applied.
next_page_token Present only when there is another page. Pass it as page_token to get it.
truncated Present and true on searches that hit their scan cap (see below).

The items are under a key named after the resource: inboxes, messages, threads, drafts, webhooks, deliveries, domains, pods, api_keys, entries, suppressions, events, agent_registrations.

Walking every page

async function listAll(path: string, key: string) {
  const items = [];
  let pageToken: string | undefined;
  do {
    const url = new URL(`https://api.machinemail.dev${path}`);
    url.searchParams.set('limit', '500');
    if (pageToken) url.searchParams.set('page_token', pageToken);
    const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.MACHINEMAIL_API_KEY}` } });
    const page = await res.json();
    items.push(...page[key]);
    pageToken = page.next_page_token;
  } while (pageToken);
  return items;
}

const inboxes = await listAll('/v0/inboxes', 'inboxes');

Page tokens

Treat tokens as opaque. Today a token encodes an offset into the result set, so:

Sort order

List Sorted by Default
Messages, threads message or thread timestamp newest first
Allow and block list entries the entry value descending (Z to A); ascending=true for A to Z
Everything else created_at newest first
Events with after event order oldest first

Endpoints that page differently

Endpoint Behaviour
GET /v0/api-keys Returns up to limit non-revoked keys (from the newest 500). limit defaults to 50 and is not capped. Never returns next_page_token; page_token and ascending are ignored.
GET /v0/webhooks with a pod or inbox key Returns every webhook in scope (up to 500) in one response, with no next_page_token.
GET /v0/pods with a pod key Returns only that pod.
GET /v0/inboxes/search Scans the newest 500 inboxes. Returns count, inboxes and truncated: true when there were more. No paging.
Thread search (q on thread lists, /threads/search) Scans the newest 500 matching messages. truncated: true when it hit the cap.
POST .../messages/batch-get, batch-update Not paged. At most 100 IDs; limit in the response is the number of IDs you sent.
GET /v0/events after takes an event ID (evt_...) or an ISO 8601 time and switches the default to oldest first: a cursor you can poll.
GET /v0/metrics/* Not paged. limit trims the result.
GET /v0/threads/{thread_id} Not paged. Returns up to 500 messages.
MCP tools limit is 1 to 100, default 20 (list_inboxes uses the API default of 50).