Pagination
How list endpoints page their results — offset, limit, and the response envelope.
Every list endpoint in the Routal API returns the same paginated envelope. This page documents the shape and the per-endpoint defaults.
Defaults and parameter lists below are pulled live from the OpenAPI spec at build time. If the backend changes a default, this page updates on the next deploy.
Response envelope
{
"total": 1000,
"limit": 50,
"offset": 0,
"pages": 20,
"page": 1,
"docs": [ /* items */ ]
}| Field | Type | Description |
|---|---|---|
total | integer | Total items matching the filter, ignoring limit / offset. |
limit | integer | Echo of the requested limit (or default). |
offset | integer | Echo of the requested offset (or default). |
pages | integer | Total pages at the current limit (ceil(total / limit)). |
page | integer | Current page, 1-indexed (floor(offset / limit) + 1). |
docs | array | The page of items. |
The shape is the same across /v2/plans, /v2/vehicles, and /v2/stops/search.
Per-endpoint defaults
Defaults are not uniform — each endpoint declares its own. The tables below come straight from the spec.
GET /v2/plans
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
text | string | — | no | Search string |
sort | string | — | no | Sort columns |
offset | number | 0 | no | Number of plans to skip |
limit | number | 20 | no | Number of plans to fetch |
deleted | boolean | false | no | with deleted plans |
project_id | string | — | no | Plan project ID |
status | string | — | no | Plan status |
sort follows the format field:asc|desc (e.g. created_at:desc).
curl -G 'https://api.routal.com/v2/plans' \
--data-urlencode 'private_key=YOUR_KEY' \
--data-urlencode 'limit=50'GET /v2/vehicles
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
text | string | — | no | Search string |
sort | string | — | no | Sort columns |
offset | number | 0 | no | Number of vehicles to skip |
limit | number | 20 | no | Number of vehicles to fetch |
deleted | boolean | false | no | with deleted vehicles |
enabled | boolean | false | no | Retrieve only enabled vehicles |
project_id | string | — | yes | Vehicle project ID |
POST /v2/stops/search
Pagination here lives in the request body, not the query string:
| Field | Type | Required | Description |
|---|---|---|---|
limit | integer | no | Limit of results |
offset | integer | no | Offset of results |
sort_by | string | no | Sort by field |
sort_direction | string (enum) | no | Sort order |
predicates | object[] | no | Predicates to search |
Query string carries only project_id (and your private_key):
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
project_id | string | — | no | (no description in spec) |
Iterating all items
async function* iteratePlans(privateKey) {
const limit = 50;
let offset = 0;
while (true) {
const url = new URL('https://api.routal.com/v2/plans');
url.searchParams.set('private_key', privateKey);
url.searchParams.set('limit', String(limit));
url.searchParams.set('offset', String(offset));
const res = await fetch(url);
if (!res.ok) throw new Error(`Failed: ${res.status}`);
const body = await res.json();
for (const plan of body.docs) yield plan;
offset += limit;
if (offset >= body.total) return;
}
}For stop search, swap the GET for a POST with the body shape above and read body.docs the same way.
Recommendations
- Cache
totalonly at the start of a job. It can shift while you paginate if other users mutate resources. - Pin a sort order. Without
sort(orsort_by+sort_directionfor stops/search) the same record can appear on two pages or be skipped if rows are inserted mid-pagination. - Don't deep-paginate to find one record. If you know the
idorexternal_id, fetch it directly (GET /v2/plan/{id}) or filter throughPOST /v2/stops/searchwith a predicate.
Empty pages
When offset >= total, the response is docs: [] with total echoed accurately. Treat that as the end of the iteration.
What's not supported
- Cursor-based pagination (
?after=…) — not available. Useoffset+ a stablesort. - Server-Sent Events / streaming list — not available.
