Pagination · MachineMail Docs
Walking every page
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. |
Response
{
"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
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
| 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). |