Skip to main content
V3 is in beta. General availability (GA) is planned for January 2027.
The V3 Routing API is a JSON API over HTTPS. A solve, evaluate or suggest call is a single 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 the Authorization header, as the bare key with no Bearer prefix:
Create a key under Settings → API Keys at platform.solvice.io. A missing or unrecognised key is a 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 any application/*+json type. Anything else is a 415.
  • 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 400 that 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:00 or 2026-04-01T06:00:00Z. A timestamp without an offset is a 400 that 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’s from, Z for 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:
A valid request returns:
200 OK
An invalid one returns the same 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

A 200 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.