MailcrateDocs

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
}
FieldMeaning
dataThis page's items
totalHow many items match across all pages
limitPage size that was applied
offsetHow many items were skipped to reach this page

Query parameters

ParameterDefaultMeaning
limit50Items per page, from 1 to 500
offset0Items to skip
pagenoneA 1-based alternative to offset. When both are sent, page wins
sortByper endpointField to sort on, where the list supports it
sortOrderper endpointASC 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.

Terminal
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:

all-deliveries.ts
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.

On this page