Paging, events and as-of reads

How to read long lists, follow every change in order, and see data as it was at a given time.

Lists: limit and offset

Most lists answer one page at a time. Send limit for the page size and offset for how many to skip:

curl
curl -X GET 'https://inventory.getmanifold.io/items?limit=50&offset=100' \
  -H "Authorization: Bearer $MANIFOLD_TOKEN"
Response · 200
{
  "items": [ … 50 items … ],
  "total": 128,
  "limit": 50,
  "offset": 100
}

total counts every match across all pages, with your filters applied. Ask for the next page with offset plus limit, and stop once offset reaches total.

Each list's page in the reference gives its largest limit and what it does when you leave limit out. Some lists then answer a default page, such as 50; others answer every match.

A few lists answer a bare array, with no total. Stop when a page comes back shorter than limit. These are:

  • GET /orders on fulfillment: newest first, limit 100 by default and at most 1000. GET /orders/count gives the total for the same filters.
  • GET /imports and GET /imports/{jobId}/failures on import and export.
  • Every service's GET /events, which pages by since (below).

Each list's page in the reference shows its answer, so you can see which shape it has.

Logs that grow: before and next

A log that grows while you read it, such as a SKU's activity or the webhook delivery log, is newest first and paged with before. An offset would shift every time a new entry landed.

curl
curl -X GET 'https://inventory.getmanifold.io/items/WIDGET-BLUE/events?limit=100&before=1031' \
  -H "Authorization: Bearer $MANIFOLD_TOKEN"
Response · 200
{
  "events": [ … 100 entries, newest first … ],
  "next": 931
}

Each page carries next: the sequence of the oldest entry on the page. Send it back as before for the older page, which starts below it. Pass it on as it came rather than working one out. The last page has no next.

Events: every change, in order

Each service keeps a record of every change it made for the organization, as facts it never edits or deletes (see Facts and the journal). Each fact has a sequence, counting up within one service for one organization. GET /events reads them, oldest first:

curl
curl -X GET 'https://inventory.getmanifold.io/events?since=1042&limit=500' \
  -H "Authorization: Bearer $MANIFOLD_TOKEN"
Response · 200
[
  {
    "_tag": "inventory.stock-dispatched",
    "eventId": "evt_01a1615a-c0e0-7d38-a94d-ee5249f39be3",
    "txId": "tx_01a1615a-c0e0-7de2-b618-5b6075c9f4c7",
    "tenantId": "org_019cadd3-7f48-7813-b601-1d0e5ec31353",
    "sequence": 1042,
    "occurredAt": "2026-10-22T02:05:00.000Z",
    "source": "inventory-manager",
    "version": 1,
    "actor": {
      "_tag": "user",
      "id": "usr_019cadd3-7fc0-792b-bb42-1992ef490f3b"
    },
    "correlationId": "req_01a1615a-c0e0-756f-be6c-4dc5e8f50d4d",
    "payload": {
      "sku": "WIDGET-BLUE",
      "locationId": "loc_019cadd3-8330-7e12-aa44-2cd5f05da74a",
      "quantity": 2,
      "orderId": "ord_01a1612f-7ea8-705d-b799-e8d57826848d",
      "reference": "dsp_309cca80-6f93-1b13-35a3-a6c100d3dd4d"
    }
  }
]

since is inclusive: a page starts at that sequence. limit is 500 by default, and at most 5000. To read every fact exactly once, start from since=0 the first time, then ask again from the last fact's sequence plus one, until a page comes back shorter than limit:

JavaScript
const base = "https://inventory.getmanifold.io";
const headers = { Authorization: `Bearer ${process.env.MANIFOLD_TOKEN}` };

// since is inclusive: a page starts at that sequence.
let since = 1042; // where you stopped last time; 0 on the first run
for (;;) {
  const res = await fetch(`${base}/events?since=${since}&limit=500`, { headers });
  if (!res.ok) throw new Error(`events: ${res.status}`);
  const page = await res.json();
  for (const fact of page) handle(fact);
  if (page.length < 500) break;
  since = page[page.length - 1].sequence + 1;
}
// Store `since`: next time, start from it.

Store the cursor and start from it next time. Each service has its own sequence and its own /events, and each needs the scopes that read what it records; the operation's page says which.

Inventory also pushes its facts as they happen, over GET /events/stream (Server-Sent Events). It is best effort: a slow reader loses its oldest messages. After a gap or a dropped connection, reconnect and read /events from the last sequence you saw plus one.

GET /events/head?at= answers the last sequence the service had recorded at that moment. There is no sequence if it had recorded nothing yet.

curl
curl -X GET 'https://inventory.getmanifold.io/events/head?at=2026-10-22T03%3A00%3A00.000Z' \
  -H "Authorization: Bearer $MANIFOLD_TOKEN"
Response · 200
{
  "at": "2026-10-22T03:00:00.000Z",
  "sequence": 1042
}

Then replay up to that sequence with upTo, beside since. upTo is inclusive: the replay ends at that sequence, so you get the record exactly as it stood then.

curl
curl -X GET 'https://inventory.getmanifold.io/events?since=0&upTo=1042' \
  -H "Authorization: Bearer $MANIFOLD_TOKEN"

Heads taken at the same at from several services describe the same moment.

As-of reads

Add x-manifold-as-of with a past moment to a GET, and the service answers as it would have at that moment:

curl
curl -X GET 'https://inventory.getmanifold.io/items/WIDGET-BLUE' \
  -H "Authorization: Bearer $MANIFOLD_TOKEN" \
  -H 'x-manifold-as-of: 2026-10-22T03:00:00.000Z'
  • Where it works: inventory, fulfillment, purchasing and CRM. Other services ignore the header and answer as of now.
  • The answer carries x-manifold-as-of-sequence: the sequence the service read up to. It is absent if the service had recorded nothing by then.
  • Reads only. A write with a past moment in the header is refused 409 AsOfIsReadOnly. An as-of read changes nothing and sends nothing.
  • A missing or invalid token is refused 401 Unauthorized before anything else.
  • A moment that is not a time is refused 400 AsOfInvalid. A moment that is now or later is answered as of now.
  • Details from another service in the answer, such as a location's name next to an old order, are as they are now.
  • A person whose data was erased stays erased at every moment, even before the erasure.

Your scopes apply as they do now. In the admin, a past moment shows as a bar reading Viewing as of the moment, with Back to now.

Reference