V3 is in beta. General availability (GA) is planned for January 2027.
POST: you send the whole problem and get the whole answer back in the response, and the API keeps no state between calls. For a long search, an async run takes the same body, answers at once and keeps the run for you to poll.
Base URL
Authentication
Send your API key in theAuthorization header, as the bare key with no Bearer prefix:
401. See Authentication.
Endpoints
The full request and response schema of each endpoint is under Endpoints in the sidebar. The first three share one
problem object, which a run takes too, described in The V3 API model.
Requests
- Content type. Send
Content-Type: application/json, or anyapplication/*+jsontype. Anything else is a415. - Compression. A body may be gzip-compressed with
Content-Encoding: gzip. The 10 MiB size limit applies to the decompressed body. - Strict schema. Field names are snake_case. An unknown field, a missing required field or a wrong type is a
400that names the field, so a misspelt or outdated field name is never dropped. Accepted does not always mean applied: a shipment id in a relation is accepted and does not change the plan. See Relations and shipments. - Coordinates.
[longitude, latitude], in that order. - Times. ISO 8601 date-times. Always include a UTC offset, as in
2026-04-01T08:00:00+02:00or2026-04-01T06:00:00Z. A timestamp without an offset is a400that names the field, since reading it as UTC would move every window and shift by your offset. The V2 endpoints still accept one and read it as UTC. Timestamps in a response are written in the UTC offset of the shift they belong to (the offset of that shift’sfrom,Zfor UTC): the same instant, in local time. - Units. Durations are seconds (
_s), distances are metres (_m), costs are in your own currency.
Dry run with validate_only
Add ?validate_only=true to any endpoint to check a request without running it:
200 OK
400 the real call would. No travel times are fetched, nothing is searched, and the call is not billed. It validates problem and options; a plan is matched against the problem only by the real call.
The value must be the literal true or false. Any other value, such as validate_only=1, is a 400 with a plain-text body instead of the JSON error body.
Responses and errors
A200 carries the result, the same shape on solve and evaluate. summary.tasks tells you whether every task was planned (unserved_required counts the required tasks left out; a job and a shipment are one task each), summary.score.violations counts broken constraints, and unassigned[] explains every task that was not planned.
Any other status from the routing service carries one JSON error body with status, code, message, request_id and, on a 400, an errors[] list with a JSON pointer to each problem. There are three exceptions. A validate_only value other than true or false is the plain-text 400 described above. A 401 and a 429 are answered before the request reaches the routing service, and they can have a different body or none at all, so branch on the HTTP status for those two. See Authentication.
Response headers
To trace a call with your own id, send an
X-Request-Id request header of 1 to 128 visible ASCII characters with no spaces. That value is then used as the request id: it is echoed in the x-request-id response header and as request_id in an error body. Without the header, or with a value outside that format, an id is generated for you.
Errors
The error body, every status and code, and unassigned-job reasons.
Limits
Request size, solve time and problem size limits.
Quickstart
Send your first solve request.
The V3 API model
How jobs, shipments, vehicles and the objective fit together.