V3 is in beta. General availability (GA) is planned for January 2027.
Overview
POST /v3/routing/solve holds the connection open until the plan is ready, caps the search at 60 seconds and takes at most 400 tasks. An async run takes the same request body, answers at once, and solves in the background, with a search of up to 3,600 seconds. You then poll the run and fetch the plan when it is done.
Only solve runs in the background. Evaluate and suggest are quick, and stay synchronous.
All four are served from
https://api.solvice.io and take your API key in the Authorization header, as on the other endpoints. A run belongs to your account: another account’s run id is a 404.
The life of a run
succeeded, failed and cancelled are final.
Submit a run
Send the body you would send to/v3/routing/solve: a problem, and optionally a plan and options. These differ from solve:
options.time_limit_smay be up to3600(solve:60).problemmay hold up to 10,000 tasks (solve:400).- A locked or
pinnedstop that cannot be driven is not caught at submission: the run endsfailed, where solve returns a400. callbackis not supported yet. A body that has it is a400with the item codenot_supportedat/callback.- The request is validated before the run is accepted, with the same checks and the same error body as solve, so a bad body is a
400here and never afailedrun later.
202 with the run. Keep its id:
202 Accepted
X-Request-Id header of 1 to 128 visible ASCII characters to trace the call. It is echoed in the x-request-id response header, and a generated req_… id is used when it is absent or malformed.
The run
Every endpoint but/result answers with the run:
string (UUID)
The run id, for the paths above.
string
queued, running, succeeded, failed or cancelled. See The life of a run.object
self and result: the paths to poll and to fetch the plan from, relative to the API host.object
On
failed only: status, code, message and, for an invalid request, errors[], in the shape of the error body. The code is invalid_request, travel_provider_error, internal or worker_lost.string (RFC 3339, UTC)
When a worker claimed the run. Absent while it is
queued.string (RFC 3339, UTC)
When the run became final. Absent before then.
string (RFC 3339, UTC)
When the run and its plan are deleted:
finished_at plus 365 days. Absent before the run is final.Poll a run
status is final. While the worker runs:
200 OK, running
200 OK, succeeded
running for ever. Each poll checks the worker, and the run turns failed with error.code worker_lost when the worker is gone or the run is older than 6,000 seconds. A run that is still queued after 30 minutes turns failed with internal.
Fetch the plan
succeeded run the answer is 200 with exactly the response POST /v3/routing/solve returns: summary, routes, plan and unassigned. See The V3 API model for every field, and send plan back in a later request to re-optimise. The plan is kept until expires_at.
For any other status /result answers 409:
Cancel a run
200 with the run: cancelled, or unchanged when it had already finished, since finishing wins a race. A run is cancelled whether it is queued or running.
200 OK, cancelled
/result is a 409 with no_result.
Limits
The other request limits apply as on solve. Over the rate limit the answer is a
429 as on every endpoint.
Errors
A bad request body is answered with the error body of solve, with the same400, 403, 413 and 415 cases. The gateway answers the rest in its own shape, so branch on the HTTP status first:
On
404 and 409 the message begins with a code (not_found, run_not_finished or no_result), then a colon and a sentence. Branch on the code and never parse the sentence. The other rows have no code in the body: branch on the HTTP status.
Next steps
The V3 API model
The request, and the plan a run returns
Errors
The error body and every code