Documentation
RouteHaven exposes an OpenAI-compatible API. Any OpenAI SDK works — change the base URL and API key.
Quickstart
- Create an account and organization, then create an API key under
Dashboard → API keys. - Add a provider key under
Dashboard → BYOK(OpenAI, Anthropic or Google), or try the freesandbox/echomodel first. - Send requests to
https://routehaven.ai/api/v1.
curl https://routehaven.ai/api/v1/chat/completions \
-H "Authorization: Bearer $ROUTEHAVEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "anthropic/claude-sonnet-5.5",
"messages": [{"role": "user", "content": "What is the meaning of life?"}]
}'Authentication
Send your key as a bearer token: Authorization: Bearer sk-rh-…. Keys are shown once at creation and stored only as SHA-256 hashes. Optional headers X-Title or HTTP-Referer label requests in your activity log.
Chat completions
POST /api/v1/chat/completions accepts the OpenAI Chat Completions body. Supported fields:
| Field | Notes |
|---|---|
model | Required. A model slug such as openai/gpt-6.1-sol. See GET /api/v1/models. |
models | Optional ordered fallback list of additional model slugs (max 8 total). |
messages | system, developer, user (text and image_url parts), assistant (with tool_calls), tool. |
stream | Server-sent events in OpenAI chunk format, terminated by data: [DONE]. |
max_tokens / max_completion_tokens | Output cap. Anthropic requires one; RouteHaven applies a default if omitted. |
temperature, top_p, stop, seed, presence_penalty, frequency_penalty | Forwarded when the target model accepts them; dropped for models that reject sampling parameters. |
tools, tool_choice, parallel_tool_calls | OpenAI function-calling format, translated for Anthropic and Gemini. |
response_format | json_object or json_schema (structured outputs where the provider supports it). |
reasoning_effort | Mapped to the provider's effort / thinking-level control. |
provider | Routing preferences: order, only, ignore, allow_fallbacks, sort. |
user | End-user identifier forwarded to the provider for abuse monitoring. |
Example response:
{
"id": "gen-2xYq…",
"object": "chat.completion",
"model": "anthropic/claude-sonnet-5.5",
"provider": "anthropic",
"choices": [{ "index": 0, "message": { "role": "assistant", "content": "…" }, "finish_reason": "stop" }],
"usage": { "prompt_tokens": 21, "completion_tokens": 118, "total_tokens": 139,
"prompt_tokens_details": { "cached_tokens": 0 }, "cost": 0.000035 }
}Streaming
Set "stream": true. Each event is a chat.completion.chunk. A final chunk with an empty choices array carries usage (including cost) unless you set stream_options.include_usage to false. Failover happens only before the first byte is sent; errors after that arrive as a data: {"error": …} event followed by [DONE].
Tool calling
{
"model": "google/gemini-3.8-flash",
"messages": [{"role": "user", "content": "What's the weather in Paris?"}],
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Current weather for a city",
"parameters": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]}
}
}]
}Return results with a tool message whose tool_call_id matches the call. Echo tool-call ids back unchanged: for Gemini they carry the provider's thought signature. Some newer models (for example Claude Opus 5.5, Sonnet 5.5, Fable 5.1) do not accept forced tool choice; RouteHaven downgrades "required" or a named tool to "auto" for those models.
Routing & failover
For each request RouteHaven builds an ordered list of attempts: every model in [model, ...models], every active provider endpoint for that model, and every credential you have for that provider. It moves to the next attempt on HTTP 401/403 (bad key), 404, 408, 429, 5xx, timeouts and network errors. Validation errors (400/422) are returned immediately.
{
"model": "sandbox/unavailable",
"models": ["anthropic/claude-haiku-5.5", "sandbox/echo"],
"provider": { "order": ["anthropic"], "allow_fallbacks": true },
"messages": [{"role": "user", "content": "hi"}]
}The full attempt chain for any request is visible in the dashboard activity log and via GET /api/v1/generation?id=….
Bring your own key (BYOK)
Add provider keys under Dashboard → BYOK. They are encrypted with AES-256-GCM (key version tracked for rotation) and bound to your organization; only the last four characters are ever displayed. When you hold several keys for a provider, they are tried in priority order. With BYOK the provider bills you directly for tokens; RouteHaven deducts only the plan's BYOK fee from your balance after the monthly free allowance.
Platform-billed access (RouteHaven's own provider keys) is disabled for every provider until a reseller agreement with that provider is on file. Requests for such models without a BYOK key return byok_required.
Limits & budgets
- Per-key rate limit (requests/minute), defaulting to your plan's limit. Responses include
x-ratelimit-*headers. - Per-key spend cap, optional model allow-list and expiry date.
- Organization monthly spend limit and team monthly budgets.
- Prepaid balance: requests that would be billed need sufficient balance (plus any credit line granted to your organization).
Usage & cost
Tokens are taken from the provider's usage report. If a provider omits usage (for example on an interrupted stream), RouteHaven estimates it and flags the record as usage_estimated. Cost is computed from list price per 1M tokens for uncached prompt, cached prompt and completion tokens, plus the applicable fee.
Other endpoints
GET /api/v1/models | Public catalog with pricing, context length, modalities and access type. |
GET /api/v1/key | Information about the calling key: usage, limit, rate limit, organization balance. |
GET /api/v1/generation?id= | Metadata, tokens, cost and fallback attempts for one request id (own organization only). |
Errors
Errors use the OpenAI shape { "error": { "message", "type", "code" } }.
| HTTP | code | Meaning |
|---|---|---|
| 400 | invalid_request_error | Malformed body or parameters. |
| 400 | byok_required | No credential for the model's provider. Add a BYOK key. |
| 401 | authentication_error | Missing, invalid, revoked or expired key. |
| 402 | insufficient_balance | Balance too low for the estimated charge. |
| 402 | key_spend_limit_exceeded / org_monthly_limit_exceeded / team_monthly_limit_exceeded | A budget was reached. |
| 403 | model_not_allowed / permission_error | Model not in key allow-list, or organization suspended. |
| 404 | model_not_found | Unknown model slug. |
| 429 | rate_limit_exceeded | Per-key rate limit hit; see retry-after. |
| 502 | upstream_unavailable / upstream_error | All attempts failed; details in error.attempts. |
| 503 | no_available_provider | No active endpoint could serve the request. |
Sandbox models
sandbox/echo and sandbox/unavailable never call a real provider and are never billed. echo repeats your last message, streams word by word, and emits a tool call when tools are supplied and the message mentions a tool. unavailable always fails with 503 so you can test failover.