Docs / Reference
API reference
LaneZero exposes OpenAI-compatible chat and model routes, a public health check, and a session-authenticated management API.
Send Authorization: Bearer lz-live_... to both /v1 routes. Provider credentials are separate. The health and documentation routes are public.
/v1/chat/completions
Creates a normalized chat completion. The request body is JSON. Set stream to true for Server-Sent Events.
Request fields
| Field | Type | Behavior |
|---|---|---|
model | string | A namespaced provider/model ID. Required unless models is present. |
models | string[] | LaneZero extension. A non-empty ordered fallback chain. Its first entry is the primary model. If model is also sent, it must equal the first entry. |
messages required | object[] | Ordered system, user, assistant, and tool messages. Content may be a string or an array of text parts. Image, audio, and other content-part types are not accepted. |
stream | boolean | Only literal true selects SSE. Missing or false returns one JSON response. |
tools | object[] | Function tools with name, optional description, optional JSON Schema parameters, and optional strict. |
tool_choice | string or object | none, auto, required, or one named function choice. |
temperature | number | Forwarded or translated to the selected provider. LaneZero does not impose a range. |
top_p | number | Forwarded or translated to the selected provider. |
max_tokens | integer | Maximum output tokens. Anthropic uses catalog metadata or 4096 when this field is absent. |
stop | string or string[] | One or more stop sequences. |
user | string | Forwarded to OpenAI-compatible providers. Anthropic and Google ignore it. |
| Other top-level fields | any JSON | Preserved and forwarded to OpenAI-compatible providers. Anthropic and Google ignore unmodeled fields. |
LaneZero removes models before calling a provider and sends only that attempt's provider-local model name. For Anthropic and Google, strict is currently not forwarded. Assistant tool-call arguments must contain valid JSON for Anthropic and a JSON object for Google.
Provider-key passthrough headers
| Header | Scope and precedence |
|---|---|
x-provider-key | Credentials for the primary provider only. The primary provider comes from model or the first models entry. |
x-provider-key-<provider> | Credentials for one named provider, such as x-provider-key-openai. This takes precedence over the generic header and also works for fallback entries. |
If neither matching header is present, LaneZero looks for that provider in the user's vault. Passthrough values are used for the current request and are not stored.
Request example
{
"models": [
"anthropic/claude-sonnet-4-6",
"openai/gpt-4.1"
],
"messages": [
{"role": "user", "content": "What is the weather in Liverpool?"}
],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Read current weather",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"]
}
}
}
],
"tool_choice": "auto",
"stream": false
}
Non-streaming response
{
"id": "chatcmpl_example",
"object": "chat.completion",
"created": 1720000000,
"model": "openai/gpt-4.1",
"choices": [
{
"index": 0,
"message": {"role": "assistant", "content": "Use soft tyres."},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 12,
"completion_tokens": 4,
"total_tokens": 16
}
}
usage and system_fingerprint are omitted when the provider does not supply them. created is 0 for Anthropic and Google because those adapters do not receive a compatible creation timestamp.
Streaming response
The response uses Content-Type: text/event-stream and Cache-Control: no-cache. Each chunk is one data: event followed by a blank line. The final success chunk has empty choices and a usage object. LaneZero writes data: [DONE] immediately after that usage chunk.
data: {"id":"chatcmpl_example","object":"chat.completion.chunk","created":1720000000,"model":"openai/gpt-4.1","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
data: {"id":"chatcmpl_example","object":"chat.completion.chunk","created":1720000000,"model":"openai/gpt-4.1","choices":[{"index":0,"delta":{"content":"Hello"},"finish_reason":null}]}
data: {"id":"chatcmpl_example","object":"chat.completion.chunk","created":1720000000,"model":"openai/gpt-4.1","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
data: {"id":"chatcmpl_example","object":"chat.completion.chunk","created":1720000000,"model":"openai/gpt-4.1","choices":[],"usage":{"prompt_tokens":7,"completion_tokens":2,"total_tokens":9}}
data: [DONE]
Tool calls arrive in delta.tool_calls. Function argument text can be split across chunks. Z.ai and Mistral do not receive stream_options; if they omit usage, LaneZero synthesizes a final usage object containing zeros. For the other OpenAI-compatible adapters, LaneZero requests usage but does not synthesize it. If one of those providers ends with [DONE] and no usage chunk, the downstream response currently ends without a final usage chunk or its own [DONE].
A failure after the first downstream chunk cannot switch providers. The HTTP status is already 200. LaneZero sends event: error with the normal error JSON in data:, then sends data: [DONE].
Routing response headers
| Header | Meaning |
|---|---|
x-lz-provider | The provider for the selected model or final routing failure. It is unknown when failure happens before a model can be routed. |
x-lz-attempts | The number of upstream calls made. Missing credentials do not increment it. |
x-lz-fallback | true when the final provider differs from the primary provider. It does not mean simply that attempts are greater than one. |
These three headers are added to every /v1/chat/completions response, including gateway authentication and JSON errors. Early failures use unknown, 0, and false.
Routing and fallback
The models array is evaluated from left to right. LaneZero makes at most three upstream calls.
- Fallback advances after provider
429, provider5xx, a transport or upstream-protocol failure, or a request timeout. - For streaming, fallback is allowed only before the first normalized chunk reaches the client. This includes a timeout waiting for response headers or the first upstream data. Once one chunk exists, later failures become SSE error events.
- Fallback does not advance after provider
400,401,403, or another non-4294xx. - A fallback entry without a passthrough or vaulted credential is skipped. The skip does not consume the three-call budget.
- An upstream
Retry-Afterdelay is honored only when it parses successfully and is no more than two seconds.
The implementation also classifies upstream 3xx responses as retryable upstream errors. Non-streaming timeouts can occur while waiting for the full response body, not only before the first byte.
/v1/models
Returns the embedded chat-model catalog, sorted by namespaced model ID. A gateway bearer key is required.
{
"object": "list",
"data": [
{
"id": "anthropic/claude-sonnet-4-6",
"object": "model",
"owned_by": "anthropic"
}
]
}
The response does not include prices, context limits, or tool capabilities. See Models and providers for catalog details.
/healthz
Public liveness response. The HTTP status and top-level status remain 200 and ok even when the database check is degraded.
- Database reachable
{"status":"ok","db":"ok"}
- Database check failed
{"status":"ok","db":"degraded"}
- No database configured
{"status":"ok","db":"absent"}
Management API
Management routes use the signed browser session created by GitHub or Google OAuth. They do not accept a gateway bearer key as a substitute. Every POST, PUT, and DELETE also requires X-LaneZero-CSRF: 1. They return 503 when LaneZero runs without DATABASE_URL.
For privacy, usage-event records are retained for 90 days by default. Operators can change the window with RACEWAY_USAGE_RETENTION_DAYS; setting it to 0 disables automatic pruning. Account deletion anonymizes usage unless RACEWAY_DELETE_USAGE_ON_ACCOUNT_DELETE=true.
| Route | Purpose |
|---|---|
GET /mgmt/me | Returns the backward-compatible github_login console label; Google-only accounts receive their verified email in that field. |
POST /mgmt/keys | Mints a gateway key from name and optional rate_limit_rps. The default is 10 requests per second. The response is the only time the full key is returned. |
GET /mgmt/keys | Lists key metadata and prefixes. Revoked keys remain in the list. Plaintext keys and hashes are never returned. |
DELETE /mgmt/keys/{id} | Revokes one active gateway key owned by the session user. |
POST /mgmt/keys/{id}/rotate | Mints a replacement key and returns its plaintext once. The old key remains usable until its configured grace deadline. |
GET /mgmt/provider-keys | Lists stored provider names, masked key prefixes and four-character hints, and creation times. |
POST /mgmt/provider-keys/test | Tests {"provider":"openai","key":"..."} against that provider's read-only models-list endpoint with a 10-second timeout. Returns a translated success or failure reason. Limited to six tests per minute per browser session. |
PUT /mgmt/provider-keys/{provider} | Validates, encrypts, and creates or replaces one provider key from {"key":"..."}. Connectivity failures store it with stored_unverified: true; provider 401/403 responses reject it. Set save_anyway to true only to bypass validation when the gateway cannot reach the provider. |
DELETE /mgmt/provider-keys/{provider} | Deletes one stored provider key. |
POST /mgmt/signout | Clears the current browser session cookie. |
POST /mgmt/signout-all | Clears the cookie and invalidates every previously issued session for the user. |
GET /mgmt/sessions | Returns the current stateless browser session's issue time and session epoch. |
GET /mgmt/usage?window=24h | Returns totals and per-model summaries. Valid windows are 24h, 7d, and 30d. |
GET /mgmt/usage/recent?limit=20 | Returns recent requests. The default limit is 20. The allowed range is 1 through 100. |
GET /mgmt/usage/export?format=csv | Streams all usage events owned by the account as csv or json. |
DELETE /mgmt/account | Revokes and removes gateway keys, crypto-shreds provider keys, disconnects identities, invalidates sessions, and anonymizes usage unless deletion is configured. |
Error JSON
Gateway-generated errors use one envelope.
{
"error": {
"message": "model `openai/not-in-the-catalog` is not present in the catalog",
"type": "invalid_request_error",
"code": "model_not_found"
}
}
| Error type | HTTP status | Typical codes |
|---|---|---|
invalid_request_error | 400 or 404 | invalid_json, model_not_found, invalid_request, management validation and not-found codes |
authentication_error | 401 | invalid_api_key, missing_provider_key, invalid_session |
rate_limit_error | 429 | rate_limit_exceeded |
upstream_error | 502 | upstream_error, oauth_upstream_error |
timeout_error | 504 | timeout |
service_unavailable_error | 503 | auth_backend_unavailable, account_backend_unavailable, vault_unavailable, database_disabled |
not_implemented_error | 501 | provider_not_implemented |
server_error | 500 | oauth_configuration_error |
See Errors and retries for triggers and caller guidance. Malformed management JSON or query extraction can be rejected by the web framework before this envelope is built.
Limits and spend caps
Rate limits are enforced per gateway key across the authenticated /v1 routes. The configured requests-per-second value is also the burst size. Exceeding it returns 429 with rate_limit_error.
Spend caps are advisory. They use estimated provider cost for the current calendar month. They never block a request. The current wire header is:
x-lz-spend-cap: true
x-lz-spend-cap appears after an authenticated /v1 request when the asynchronously refreshed estimate is greater than the configured cap.