Pagination
List endpoints return results in cursor-paginated pages. You control page size
with limit and walk forward with starting_after.
Query parameters
| Parameter | Type | Default | Notes |
|---|---|---|---|
limit | integer | 20 | Page size, between 1 and 100. |
starting_after | string | — | A cursor: the next_cursor from the prior page. |
Passing a limit outside 1–100, or any unrecognized query parameter, returns a
400 validation-failed.
Response envelope
Every list response has the same shape:
{
"data": [{ "id": "…", "object": "sensor", "…": "…" }],
"has_more": true,
"next_cursor": "cD0yMDI2LTA3LTAx"
}
| Field | Meaning |
|---|---|
data | The array of resources for this page. |
has_more | true if more pages exist after this one. |
next_cursor | The cursor to pass as starting_after for the next page, or null when has_more is false. |
next_cursor is non-null only when has_more is true. On the final page,
has_more is false and next_cursor is null — always branch on has_more.
Paging through all results
Request the first page, then keep passing next_cursor as starting_after
until has_more is false:
# First page
curl "https://api.evinor.ai/v1/sensors?limit=50" \
-H "Authorization: Bearer evnr_live_your_key_here"
# Next page — feed back the previous next_cursor
curl "https://api.evinor.ai/v1/sensors?limit=50&starting_after=cD0yMDI2LTA3LTAx" \
-H "Authorization: Bearer evnr_live_your_key_here"
In pseudocode:
cursor = null
loop:
page = GET /v1/sensors?limit=100[&starting_after=cursor]
process(page.data)
if not page.has_more: break
cursor = page.next_cursor
Treat cursor values as opaque — their internal format is not part of the
contract and may change. Don't construct or parse them yourself; only ever pass
back a next_cursor you received.
Event search pages differently
POST /v1/events/search uses the same data / has_more /
next_cursor envelope, with two differences worth knowing before you write a
paging loop against it:
- The cursor travels in the request body, as
cursor, not as astarting_afterquery parameter. It is opaque in the strongest sense: it encodes which search execution to continue, so a continuation request needs nothing else — no filter, and noexecution_id. Sending filter fields alongside acursoris a400. total_countis not a count of retrievable rows. The search envelope addstotal_count(corpus-wide matches for your filter) andexecution_id. You may reach fewer items thantotal_countsuggests: each execution exposes a bounded number of results, and events whose underlying record can no longer be resolved are omitted fromdata. Branch onhas_more, never ontotal_count.
A cursor there also expires with its search execution — a stale one returns 410
search-execution-expired. See
Searching events.