Skip to content

Pagination

A list returns one page and says whether more follow. Send the cursor of one page to get the next, and stop when has_more is false.

A list endpoint returns one page of results and tells you whether there are more. To read on, send the page's next_cursor back as cursor. There are no page numbers and no total count.

curl "https://api.useinfrared.com/v1/webhooks/events?limit=2" \
  -H "Authorization: Bearer $INFRARED_KEY"
200 OK, trimmedJSON
{"object": "list","data": [{ "object": "webhook_event", "id": "evt_3JBjspfu9XetX1AI2E8K6G", "type": "moderation.completed", "created_at": "2026-10-08T08:55:24.332Z" },{ "object": "webhook_event", "id": "evt_5KRfjncmk4C517vNiS950P", "type": "queue_item.created", "created_at": "2026-10-08T08:55:24.071Z" }],"has_more": true,"next_cursor": "WyIyMDI2LTEwLTA4VDA4OjU1OjI0LjA3MVoiLCJhZjFlYWI2MS1iYzg3LTQ1ZGUtYmI1OS0wNzA1YTNiOTk0NjUiXQ"}

The next page is the same request with that cursor:

curl "https://api.useinfrared.com/v1/webhooks/events?limit=2&cursor=WyIyMDI2LTEwLTA4VDA4OjU1OjI0LjA3MVoiLCJhZjFlYWI2MS1iYzg3LTQ1ZGUtYmI1OS0wNzA1YTNiOTk0NjUiXQ" \
  -H "Authorization: Bearer $INFRARED_KEY"

Parameters and the answer

limitintegerDefault 20

How many items a page holds, from 1 to 100. A value outside that range answers 422 validation_error.

cursorstring

The next_cursor of the page before. Leave it out for the first page.

Every list answers with the same four fields.

objectstring

Always list.

dataarray

The items of this page.

has_moreboolean

true when another page follows.

next_cursorstring

What to send as cursor to get the next page. null on the last page.

The cursor is opaque: pass it back as you received it, and do not build one or read anything from it. A value the API did not issue answers 400 invalid_cursor.

Read every page

Loop until has_more is false.

const events = [];
let cursor;

do {
  const url = new URL("https://api.useinfrared.com/v1/webhooks/events");
  url.searchParams.set("limit", "100");
  if (cursor) url.searchParams.set("cursor", cursor);

  const response = await fetch(url, {
    headers: { Authorization: `Bearer ${process.env.INFRARED_KEY}` },
  });
  const page = await response.json();

  events.push(...page.data);
  cursor = page.has_more ? page.next_cursor : null;
} while (cursor);

Each page is a request, and each request counts against the key's rate limit.

Order

A list has a fixed order, and a page continues exactly after the last item of the one before. Items created while you are paging do not shift the pages or repeat an item.

Keep the filters and the sort the same from the first page to the last. A cursor marks a position in one ordering: with another filter or another sort it points nowhere useful.

ListOrderIts own parameters
GET /v1/moderationsNewest firstFilters such as template, status and author_id
GET /v1/authorsBy sort: activity (the default), trust, risk or created. order is desc (the default) or ascstatus, trust_level
GET /v1/authors/{external_id}/moderationsNewest firstNone
GET /v1/queueOldest first. sort=desc turns it aroundstate, template, language, severity, priority
GET /v1/wordlists/{id}/termsOldest firstlimit goes up to 500 here, and its default is 100
GET /v1/webhooks/eventsNewest firsttype
GET /v1/webhooks/{id}/deliveriesNewest firststatus

Authors sorted by activity or risk are ordered by a value that changes as they post. An author whose value changes between two of your requests can appear twice or be skipped. Sort by created when you need every author exactly once.

Lists that return everything

Six lists are short by nature and always come back whole, with has_more: false and next_cursor: null: GET /v1/templates, GET /v1/policies, GET /v1/guidelines, GET /v1/wordlists, GET /v1/actions and GET /v1/webhooks.

The answer of a batch has the same shape, with one entry per item you sent.

Next

Something missing or unclear on this page? Write to support@useinfrared.com.