Pagination
How list endpoints page their results with limit and offset, and a loop that reads every page.
Every endpoint that returns a list returns it one page at a time, in the same envelope:
{
"data": [{ "id": "…" }, { "id": "…" }],
"total": 1284,
"limit": 50,
"offset": 100
}| Field | Meaning |
|---|---|
data | This page's items |
total | How many items match across all pages |
limit | Page size that was applied |
offset | How many items were skipped to reach this page |
Query parameters
| Parameter | Default | Meaning |
|---|---|---|
limit | 50 | Items per page, from 1 to 500 |
offset | 0 | Items to skip |
page | none | A 1-based alternative to offset. When both are sent, page wins |
sortBy | per endpoint | Field to sort on, where the list supports it |
sortOrder | per endpoint | ASC or DESC |
A limit above 500 or a page below 1 is rejected with 400, not quietly corrected. Most lists also take filters of their own (such as status on campaigns, or query for a text search); each one is listed on its endpoint's page in the API Reference.
curl "https://api.mailcrate.io/public/delivery?limit=100&page=2" \
-H "Authorization: Api-Key $MAILCRATE_API_KEY"offset in the response is always the offset actually applied, also when you paged with page, so it is safe to compute the next request from the response alone.
Read every page
Keep asking until you have total items or a page comes back short:
async function* listAll(path: string, limit = 500) {
for (let offset = 0; ; offset += limit) {
const url = `https://api.mailcrate.io${path}?limit=${limit}&offset=${offset}`;
const res = await fetch(url, {
headers: { Authorization: `Api-Key ${process.env.MAILCRATE_API_KEY}` },
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const page = await res.json();
yield* page.data;
if (page.data.length < limit || offset + limit >= page.total) return;
}
}
for await (const delivery of listAll('/public/delivery')) {
console.log(delivery.id, delivery.status);
}Pages can shift while you read
Pagination is by position, not by cursor. If items are created or deleted while you are walking the list, an item can move across a page boundary and be skipped or seen twice. For a complete sync of something that changes, de-duplicate by id, or narrow the list with a filter (such as a date range) so it stops changing while you read it.
A full read of a large list is also the fastest way to spend your rate limit. The largest page, limit=500, costs the same single request as the smallest.