> ## Documentation Index
> Fetch the complete documentation index at: https://docs.solvice.io/llms.txt
> Use this file to discover all available pages before exploring further.

# OpenAPI specification

> Download the V3 Routing API as one OpenAPI 3.1 file and generate a client from it

<Info>
  **V3 is in beta.** General availability (GA) is planned for January 2027.
</Info>

One OpenAPI 3.1 file describes every V3 Routing API endpoint: solve, evaluate and suggest, and the four async-run endpoints. Use it to generate a client, to check requests in your tests, or to import the API into an HTTP tool.

<Card title="solvice-routing-v3.openapi.json" icon="download" href="/api-reference/solvice-routing-v3.openapi.json">
  OpenAPI 3.1, JSON, about 240 KB
</Card>

```bash theme={null}
curl -O https://docs.solvice.io/api-reference/solvice-routing-v3.openapi.json
```

## What the file contains

* **All seven endpoints**, tagged `Routing` (`/v3/routing/solve`, `/evaluate`, `/suggest`) and `Runs` (`/v3/routing/runs` and its status, result and cancel paths). See [Introduction](/api-reference/vrp/v3/introduction#endpoints) for what each one does.
* **The server and authentication:** `https://api.solvice.io`, with your API key in the `Authorization` header as the bare key, no `Bearer` prefix.
* **Every request and response schema**, with the field descriptions from this reference and the limits the API enforces, such as `minimum`, `maximum` and `maxItems`.

It is the same contract as the endpoint pages in this reference. Field names and the JSON on the wire are identical. Three schema names differ, so that generated code does not carry the server's internal type names:

| Endpoint pages | Download |
| - | - |
| `BTreeMap` (named capacity, demand and load dimensions) | `Quantities` |
| `OrValidateOnly_SolveResponse` | `SolveOrValidateOnlyResponse` |
| `OrValidateOnly_SuggestResponse` | `SuggestOrValidateOnlyResponse` |

The file changes with every API release, and during the beta a release can rename or remove fields. Download it again when you update your integration.

## Generate a client

For TypeScript, use the [`@solvice/routing`](https://www.npmjs.com/package/@solvice/routing) package (beta), which is typed from this contract. For other languages, generate a client from the file.

OpenAPI 3.1 support differs between generators. [openapi-python-client](https://github.com/openapi-generators/openapi-python-client) generates a working Python client from this file. The `python` generator of openapi-generator 7.14 does not yet handle its nullable fields.

<Steps>
  <Step title="Generate the package">
    ```bash theme={null}
    uvx openapi-python-client generate --path solvice-routing-v3.openapi.json --output-path solvice_routing --meta none
    ```

    Without [uv](https://docs.astral.sh/uv/), run `pip install openapi-python-client` and then the same command without `uvx`. `--meta none` writes the package alone; it needs `httpx`, `attrs` and `python-dateutil` installed.
  </Step>

  <Step title="Call the API">
    The generated client sends `Authorization: Bearer <token>` unless you set `prefix=""`. Set it, because the API expects the bare key.

    ```python theme={null}
    import os

    from solvice_routing import AuthenticatedClient
    from solvice_routing.api.routing import solve
    from solvice_routing.models import ErrorBody, SolveRequest

    client = AuthenticatedClient(
        base_url="https://api.solvice.io",
        token=os.environ["SOLVICE_API_KEY"],
        prefix="",
        timeout=30,
    )

    request = SolveRequest.from_dict({
        "problem": {
            "jobs": [{"id": "delivery-1", "location": [4.7005, 50.8798], "service_duration_s": 300}],
            "vehicles": [{"id": "truck-1", "shifts": [{
                "id": "mon",
                "from": "2026-04-01T08:00:00+02:00",
                "to": "2026-04-01T17:00:00+02:00",
                "start": {"location": [4.3517, 50.8503]},
                "end": {"location": [4.3517, 50.8503]},
            }]}],
        },
        "options": {"time_limit_s": 1},
    })

    result = solve.sync(client=client, body=request)
    if isinstance(result, ErrorBody):
        print(result.code, [item.code for item in result.errors])
    else:
        print(result.summary.tasks.served, "served, cost", result.summary.score.cost)
    ```

    `solve.sync` returns a `SolveResponse`, or an `ErrorBody` for a `400`, `403`, `413`, `415`, `500`, `502` or `503`. Pass `validate_only=True` to get a `ValidateOnlyResponse` instead of a solve.
  </Step>
</Steps>

Whichever generator you use:

* **Accept unknown values.** Responses can gain fields, and every code or type in a response can gain values, without a new major version. Configure the generator to accept them; for openapi-generator, set `enumUnknownDefaultCase=true`.
* **Send only documented fields.** Requests are strict: an unknown field is a `400` with an `unknown_field` item.
* **Do not parse `message`.** Branch on the HTTP status, then on `code` and `errors[].code`. See [Errors](/guides/vrp/v3/errors).
* **Authentication and rate-limit errors** (`401`, `429`) come from the API gateway in its own shape, not as an `ErrorBody`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.