Pagination
How list endpoints page their results, with 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 | — | yes | (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. Useoffsetwith a stablesort. - Server-Sent Events / streaming list: not available.
