Developer guide

Pick a model, copy a snippet, ship.

Every endpoint below uses the model you select. Switch the dropdown and the snippets update instantly. When you're ready to try in Postman, the "Download collection" button builds a v2.1 collection pre-wired to that exact model.

Prefer to click before you code? /playground runs the same request against three curated models with no signup, 20 free requests / day, live gateway headers surfaced next to the response.

Pick a model
anthropic/claude-sonnet-4-6anthropicflagshipglobalvisionupstream: $3.00 in / $15.00 out per 1M tokens
7 endpoints
POST/v1/chat/completions

The main routing endpoint. OpenAI-shape request, OpenAI-shape response.

curl https://api.leanroute.dev/v1/chat/completions \
  -H "authorization: Bearer gw_live_YOUR_KEY" \
  -H "content-type: application/json" \
  -d '{
    "model": "anthropic/claude-sonnet-4-6",
    "messages": [
      { "role": "user", "content": "Hello in one sentence." }
    ]
  }'
POST/v1/chat/completions • streaming

Set stream:true. SSE chunks terminated by data:[DONE]. Tool-call deltas translate across every provider.

curl https://api.leanroute.dev/v1/chat/completions \
  -H "authorization: Bearer gw_live_YOUR_KEY" \
  -H "content-type: application/json" \
  -d '{
    "model": "anthropic/claude-sonnet-4-6",
    "stream": true,
    "messages": [{ "role": "user", "content": "Count to 5." }]
  }'
POST/v1/chat/completions • tools

Standard OpenAI tools[]. The gateway translates per provider and back to OpenAI tool_calls in the response.

curl https://api.leanroute.dev/v1/chat/completions \
  -H "authorization: Bearer gw_live_YOUR_KEY" \
  -H "content-type: application/json" \
  -d '{
    "model": "anthropic/claude-sonnet-4-6",
    "messages": [{ "role": "user", "content": "Weather in SG?" }],
    "tools": [{
      "type": "function",
      "function": {
        "name": "get_weather",
        "parameters": { "type": "object", "properties": { "city": { "type": "string" } } }
      }
    }]
  }'
POST/v1/chat/completions • vision

OpenAI image_url content part. Accepts HTTPS URLs or data:image/* URIs. Per-provider wire translation handled upstream.

curl https://api.leanroute.dev/v1/chat/completions \
  -H "authorization: Bearer gw_live_YOUR_KEY" \
  -H "content-type: application/json" \
  -d '{
    "model": "anthropic/claude-sonnet-4-6",
    "messages": [{
      "role": "user",
      "content": [
        { "type": "text", "text": "What is in this image?" },
        { "type": "image_url", "image_url": { "url": "https://example.com/receipt.jpg" } }
      ]
    }]
  }'
POST/v1/embeddings

OpenAI-shape embeddings. Independent of the chat model selector; embedding ids are namespaced openai/text-embedding-3-*.

curl https://api.leanroute.dev/v1/embeddings \
  -H "authorization: Bearer gw_live_YOUR_KEY" \
  -H "content-type: application/json" \
  -d '{
    "model": "openai/text-embedding-3-small",
    "input": "the quick brown fox"
  }'
GET/v1/models

Authenticated discovery. OpenAI-shape {data:[{id,object:'model',…}]}.

curl https://api.leanroute.dev/v1/models \
  -H "authorization: Bearer gw_live_YOUR_KEY"
GET/health

Unauthenticated. Returns {ok:true, providers:{…}}. Suitable for a load-balancer health check.

curl https://api.leanroute.dev/health

Endpoints

Base URL https://api.leanroute.dev. Every endpoint takes your gw_live_* key as a bearer token and runs through the same caching, guardrails, spend caps and failover.

EndpointUse it for
POST /v1/chat/completionsOpenAI Chat Completions on any model. Streaming, tools, vision, and MCP tools via mcp_servers.
POST /anthropic/v1/messagesAnthropic Messages API. Point the Anthropic SDK or Claude Code at https://api.leanroute.dev/anthropic. Anthropic SDK and Claude Code guide.
POST /v1/embeddingsOpenAI and Google embedding models.
GET /v1/modelsModels your key can reach right now.
curl https://api.leanroute.dev/anthropic/v1/messages \
  -H "x-api-key: $LEANROUTE_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{"model":"claude-sonnet-5","max_tokens":256,
       "messages":[{"role":"user","content":"Hello"}]}'

Gateway-specific headers

Headers we read on the way in, and the diagnostic headers we emit on the way out. All ASCII (RFC 7230 §3.2.4 enforced by CI). Quick reference below; full docs at /docs/headers include per-header examples and JS/Python snippets.

HeaderDirectionMeaning
authorization: Bearer gw_live_*requestYour gateway API key. Required on every authenticated endpoint.
x-gateway-routing: explicitrequestDisable cheaper-model swaps for this single request, even if your org has them on.
x-gateway-credit-balance-usdresponseYour prepaid balance after the request, in USD with 6-digit precision.
x-gateway-byok: trueresponsePresent when the request was dispatched using your BYOK key for that provider.
x-gateway-failover: trueresponsePresent when the originally-routed provider returned 5xx and we transparently retried on a same-tier alternative.
x-gateway-failover-fromresponseOriginal provider name that 5xx'd. Only present when x-gateway-failover is set.
x-gateway-routed-fromresponseOriginal model id you requested, when the gateway swapped to a cheaper same-tier model. Only present with cheaper-model-swap opt-in.
x-gateway-model-deprecatedresponseOriginal model id when we auto-rewrote to its current canonical name (e.g. claude-sonnet-4.6 -> claude-sonnet-4-6).
x-gateway-prompts-persisted: falseresponsePresent when your org has flipped no-persistence mode in /dashboard/settings — prompts are not cached for this request.
x-gateway-throttle-scoperesponseOn 402 / 429: which limit fired (credit_balance, spend_cap_daily, spend_cap_monthly, rpm, tpm).

Error codes

All errors come back as { "error": { "code": "...", "message": "...", ...context } }. Codes are stable; messages may change.

HTTPCodeMeaning
400unknown_modelThe model string doesn't match any canonical id. See the dropdown above or /docs/models for the full catalog. Provider prefix (e.g. anthropic/) is required.
400bad_requestRequest body failed schema validation. The error message names the field.
400prompt_blockedA per-org guardrail blocked the prompt before dispatch. Body includes 'scope' (block | moderation) and the 'pattern' that fired (block) or 'categories' that tripped (moderation). Configure or disable in /dashboard/settings → Guardrails.
401unauthorizedMissing or revoked gateway API key. Issue a new one at /dashboard/keys.
402insufficient_creditPrepaid balance dropped below the dispatch floor. Top up at /dashboard/billing. Body includes balance_usd.
402spend_cap_exceededDaily or monthly spend cap hit. Body names which (scope=spend_cap_daily / spend_cap_monthly). Checked when a request arrives; an MCP request that passes can still make up to 10 model calls (see /docs/mcp).
429rate_limitedRPM or TPM cap hit. Body names which scope. Retry after a moment.
400provider_not_configuredNo key for the provider this model routes to. reason is plan_byok_only (your BYOK plan needs your own key for every provider you call) or provider_byok_only (this provider is BYOK-only for everyone). Add the key at /dashboard/providers and retry. On a BYOK plan, callable_models lists models you can call right now with the keys you have. Returned as 503 with reason no_managed_key only if our own managed key is missing, which is on us.
400upstream_errorThe provider refused this request, e.g. a parameter the model doesn't support. message quotes the provider's reason; upstream_status and upstream_body have the details. 413 and 422 from the provider are passed through the same way. Change the request rather than retrying.
502upstream_errorThe provider failed (5xx), rejected the provider key, or doesn't know the model. Body includes upstream_status and a truncated upstream body. Provider 429s are returned as 429.

See also: Model catalog & pricing · Integration guides · Compliance · Home