Pagination
All list endpoints use cursor-based pagination for consistent, efficient traversal of large result sets.
Why cursor-based?
Unlike offset-based pagination, cursor-based pagination:
- Handles real-time data insertions without skipping or duplicating items
- Performs consistently regardless of page depth
- Works well with append-only datasets like observations and CV jobs
Request parameters
| Parameter | In | Type | Description |
|---|---|---|---|
cursor | query | string | Pagination cursor from a previous response |
limit | query | integer | Number of items per page (1-100)Default: 20 |
Response format
Every list endpoint returns the same paginated structure:
{
"data": [
{ "id": "obs_001", "...": "..." },
{ "id": "obs_002", "...": "..." }
],
"cursor": {
"next": "eyJpZCI6Im9ic18wMDIifQ==",
"hasMore": true
}
}
| Field | Type | Description |
|---|---|---|
data | T[] | Array of items for the current page |
cursor.next | string | null | Cursor to fetch the next page |
cursor.hasMore | boolean | Whether more pages exist |
Iterating through pages
Manual pagination
let cursor: string | undefined;
const allObservations = [];
do {
const page = await tenant.observations.list({
cursor,
limit: 100,
});
allObservations.push(...page.data);
cursor = page.cursor.hasMore ? page.cursor.next : undefined;
} while (cursor);
console.log(`Total: ${allObservations.length}`);Auto-pagination (recommended)
The SDK provides auto-pagination helpers that handle cursor management automatically:
// Async iterator - memory efficient
for await (const obs of tenant.observations.listAll({
locationId: 'loc_abc123',
})) {
console.log(obs.id);
}
// Collect all into array
const all = await tenant.observations.listAll().toArray();Rate limiting
The API enforces rate limits to ensure fair usage. When you exceed the limit:
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests per window |
X-RateLimit-Remaining | Remaining requests in current window |
X-RateLimit-Reset | Unix timestamp when the window resets |
Retry-After | Seconds to wait before retrying (on 429) |
HTTP/1.1 429 Too Many Requests
Retry-After: 30
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1714300800
SDK handles rate limits
The SDK automatically retries on 429 responses with exponential backoff. No action needed on your part.
Next steps
- Observations — Work with observation data
- CV Jobs — Start and manage CV analysis
- API Reference — Full endpoint documentation