Skip to content
machinemail

Pagination

limit, page_token and next_page_token, and the endpoints that page differently.

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

Query parameterTypeDefaultMeaning
limitinteger50Items 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_tokenstringnoneThe next_page_token from the previous page.
ascendingbooleanfalsetrue for oldest first. Most lists are newest first by default.
Response
{
  "count": 50,
  "limit": 50,
  "next_page_token": "eyJvIjo1MH0",
  "inboxes": [ ... ]
}
FieldMeaning
countNumber of items in this page (not a total).
limitThe limit that was applied.
next_page_tokenPresent only when there is another page. Pass it as page_token to get it.
truncatedPresent 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

list-all.ts
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:

  • Items created while you page can shift later pages: an item can appear twice or be skipped. For a stable feed of changes, read the event log with after=<event_id> instead.
  • A token that cannot be decoded is ignored and the list starts again from the first page. It is not an error.
  • Use a token with the same filters and sort order that produced it.

Sort order

ListSorted byDefault
Messages, threadsmessage or thread timestampnewest first
Allow and block list entriesthe entry valuedescending (Z to A); ascending=true for A to Z
Everything elsecreated_atnewest first
Events with afterevent orderoldest first

Endpoints that page differently

EndpointBehaviour
GET /v0/api-keysReturns 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 keyReturns every webhook in scope (up to 500) in one response, with no next_page_token.
GET /v0/pods with a pod keyReturns only that pod.
GET /v0/inboxes/searchScans 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-updateNot paged. At most 100 IDs; limit in the response is the number of IDs you sent.
GET /v0/eventsafter 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 toolslimit is 1 to 100, default 20 (list_inboxes uses the API default of 50).