Fibric. Docs fibric.io →
v1.0.0 ยท stable
Reference

Pagination

Every list endpoint in the Fibric API paginates the same way: opaque cursors, a bounded limit, and stable newest-first ordering. There are no page numbers and no offsets. This page specifies the contract once, so each endpoint page only has to name its filters.

Shared conventions, including authentication and the error envelope, are defined in the API overview. Error codes are catalogued in Errors.

The list envelope

Every list response is wrapped in the same four-field envelope, regardless of what it lists.

objectstring

Always list.

dataobject[]

The page of results, each a full or summarized API object. An empty page is [], never null.

has_moreboolean

true when at least one more page exists beyond this one. The loop condition: keep fetching while has_more is true.

next_cursorstring or null

Opaque cursor for the next page, prefixed cur_. null exactly when has_more is false. Pass it back verbatim as the cursor query parameter.

json · the list envelope
{
  "object": "list",
  "data": [
    { "id": "rc_5b21", "object": "receipt", "outcome": "applied", "at": "2026-07-02T15:04:41Z" },
    { "id": "rc_5b1f", "object": "receipt", "outcome": "blocked", "at": "2026-07-02T14:58:07Z" }
  ],
  "has_more": true,
  "next_cursor": "cur_eyJpZCI6InJjXzViMWYifQ"
}

Request parameters

Two query parameters drive pagination on every list endpoint. Endpoint-specific filters are documented on each endpoint page; filters combine with AND and are compatible with pagination.

limitinteger · query

Page size, 1–100. Defaults to 20. A value outside the bounds fails with 400 invalid_parameter; it is never silently clamped.

cursorstring · query

The next_cursor from a previous response, verbatim. Omit it for the first page. A cursor is bound to the query that produced it: reusing it with different filters, a different limit is permitted, fails with 400 invalid_cursor.

curl · first page, then the next
curl "https://api.fibric.io/v1/receipts?verdict=BLOCK&limit=50" \
  -H "Authorization: Bearer $FIBRIC_KEY"

# then, using next_cursor from the response:
curl "https://api.fibric.io/v1/receipts?verdict=BLOCK&limit=50&cursor=cur_eyJpZCI6InJjXzViMWYifQ" \
  -H "Authorization: Bearer $FIBRIC_KEY"

Stable ordering

Every list returns newest first, ordered by the object's creation-time field and tie-broken by id, so the order is total and deterministic. The anchor field per endpoint group:

EndpointOrdered by
GET /eventsreceived_at, then id
GET /operatorscreated_at, then id
GET /connectorscreated_at, then id
GET /plansproposed_at, then id
GET /actionsdisposed_at, then id
GET /receiptsat, then id
GET /guardrailscreated_at, then id
GET /webhook_endpointscreated_at, then id
GET /keyscreated_at, then id

There is no sort parameter in v1.0. To read oldest first, walk to the end and reverse client-side, or bound the range with a since filter where the endpoint offers one.

Consistency under writes

A cursor marks a fixed position in the ordering, not a snapshot of the data. The guarantees while you paginate:

i
Polling versus paginating

Pagination is for reading history. For keeping up with new activity, prefer a webhook endpoint, which pushes plan proposals and action dispositions as they happen, or poll the first page with a since filter anchored at your high-water mark.

Cursor lifetime

Cursors are opaque and expire. Treat them as short-lived continuation tokens, not durable bookmarks:

Walking all pages

bash · drain a listing with jq
CURSOR=""
while :; do
  PAGE=$(curl -s "https://api.fibric.io/v1/receipts?entity=order:SO-10884&limit=100${CURSOR:+&cursor=$CURSOR}" \
    -H "Authorization: Bearer $FIBRIC_KEY")
  echo "$PAGE" | jq -r '.data[].id'
  [ "$(echo "$PAGE" | jq -r '.has_more')" = "true" ] || break
  CURSOR=$(echo "$PAGE" | jq -r '.next_cursor')
done
typescript · an async page walker
async function* pages(path: string, params: Record<string, string>) {
  let cursor: string | null = null;
  do {
    const qs = new URLSearchParams({ ...params, limit: "100", ...(cursor ? { cursor } : {}) });
    const res = await fetch(`https://api.fibric.io/v1${path}?${qs}`, {
      headers: { Authorization: `Bearer ${process.env.FIBRIC_KEY}` },
    });
    const page = await res.json();
    yield* page.data;
    cursor = page.has_more ? page.next_cursor : null;
  } while (cursor);
}

for await (const receipt of pages("/receipts", { verdict: "BLOCK" })) {
  console.log(receipt.id, receipt.outcome);
}

Draining a long history counts against the read rate limit for the route class; use limit=100 and back off on 429 per Rate limits & quotas. For a complete extract of the audit ledger, prefer the asynchronous receipts export over paging.

Errors

StatusCodeWhen
400invalid_parameterlimit is outside 1–100 or not an integer.
400invalid_cursorThe cursor is malformed, expired, or was issued for a different query. Restart from the first page.
429rate_limitedThe read budget for the route class is exhausted. Honor Retry-After; the cursor remains valid within its lifetime.

Both 400 codes are client errors; do not retry unchanged. See retryability in Errors.