---
title: "Pagination"
description: "How MachineMail list endpoints page with limit, page_token and next_page_token: walking every page, sort order, and the endpoints that page differently."
canonical: "https://machinemail.dev/docs/reference/pagination"
---

# 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.                                                                                                                            |

```json title="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

```ts title="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](https://machinemail.dev/docs/reference/api/events) 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).                                                                                                       |
