Provider scoping (items 1/2/6): - Key visibility maps on (model_id.lower(), upstream_provider_id), matching refresh_model_maps, so a disable/override row on one provider never leaks onto another provider's model, and matching is case-insensitive. Data safety (items 3/5): - Degraded OpenRouter fetches (network error, 429, non-200, bad payload) return None (unknown) instead of []; a provider whose path set is unknown keeps its previously persisted rows instead of being wiped. - Endpoint payload parsing moved fully inside try, with a list guard, so endpoints:null or non-list shapes are swallowed as documented. - refresh with an empty live upstream list is a no-op; the unfiltered DELETE in the prune path is gone (prune now keys off enabled DB rows). Hot path (items 4/12/14): - Persist uses chunked bulk INSERTs (one statement per 500 rows) instead of per-row ORM adds; redundant ix_model_paths_model_id index dropped. - Read routes filter in SQL instead of materializing the whole table, and output ordering is deterministic (public id + path), independent of rowid. - Visibility no longer rebuilds fully priced Model objects per override row; it reads id/forwarded_model_id/canonical_slug straight off ModelRow. Path/id contract (items 7/8/9/11): - discovery_path_for_subprovider/discovery_base_paths hooks on BaseUpstreamProvider, overridden by OpenRouterUpstreamProvider, mirror _apply_provider_field so discovery and response stamping cannot drift (openrouter:OpenRouter now correctly maps to unknown). - openrouter_author_slug falls back to a slash-containing forwarded_model_id, so admin-created alias rows are discoverable. - public_model_id splits on the first slash, same as get_base_model_id, so discovery ids can be sent to chat completions verbatim. Lifecycle (items 10/13): - ENABLE_MODEL_PATHS_REFRESH kill switch; interval and flag re-read every loop iteration, and the task idles (not exits) while disabled. - First 429 latches and aborts the remaining fan-out for the cycle; a per-cycle cache dedupes fetches across providers sharing a base URL. - refresh_model_maps prunes paths of disabled/deleted providers so admin mutations take effect immediately; rows carry updated_at and both endpoints expose it. Tests (item 15) rewritten through the public refresh entry point with transport-level httpx.MockTransport fakes, FK enforcement on, and coverage for the periodic loop. Migration re-chained onto 9c4d8e2f1a6b.
12 KiB
API Endpoints
Complete reference for all Routstr API endpoints.
Overview
Routstr provides OpenAI-compatible endpoints with Bitcoin/eCash payment integration.
Base URL
All endpoints use the base URL:
https://api.routstr.com/v1
Authentication
All endpoints require authentication via:
- Bearer Token:
Authorization: Bearer sk-...orAuthorization: Bearer cashuAeyJ0... - X-Cashu Header:
X-Cashu: cashuAeyJ0...(for direct eCash payments)
See Authentication for details.
Chat
Create Chat Completion
Send messages to generate model responses.
POST /v1/chat/completions
Request Body:
{
"model": "gpt-4",
"messages": [
{
"role": "system",
"content": "You are a helpful assistant."
},
{
"role": "user",
"content": "Hello!"
}
],
"temperature": 0.7,
"stream": false
}
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
model |
string | Yes | - | Model ID to use |
messages |
array | Yes | - | Array of message objects |
temperature |
number | No | 1.0 | Sampling temperature (0-2) |
max_tokens |
integer | No | Model default | Maximum tokens to generate |
stream |
boolean | No | false | Stream partial responses |
top_p |
number | No | 1.0 | Nucleus sampling |
n |
integer | No | 1 | Number of completions |
stop |
string/array | No | null | Stop sequences |
presence_penalty |
number | No | 0 | Presence penalty (-2 to 2) |
frequency_penalty |
number | No | 0 | Frequency penalty (-2 to 2) |
Response:
{
"id": "chatcmpl-123",
"object": "chat.completion",
"created": 1677652288,
"model": "gpt-4",
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": "Hello! How can I help you today?"
},
"finish_reason": "stop"
}],
"usage": {
"prompt_tokens": 13,
"completion_tokens": 9,
"total_tokens": 22
}
}
Streaming Response
When stream: true:
data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1677652288,"model":"gpt-3.5-turbo","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1677652288,"model":"gpt-3.5-turbo","choices":[{"index":0,"delta":{"content":"Hello"},"finish_reason":null}]}
data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1677652288,"model":"gpt-3.5-turbo","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
data: [DONE]
Completions (Coming Soon)
Create Completion
Note: This endpoint is coming soon and not yet available.
Generate text completion (legacy endpoint).
POST /v1/completions
Request Body:
{
"model": "gpt-3.5-turbo-instruct",
"prompt": "Once upon a time",
"max_tokens": 50,
"temperature": 0.7
}
Response:
{
"id": "cmpl-123",
"object": "text_completion",
"created": 1677652288,
"model": "gpt-3.5-turbo-instruct",
"choices": [{
"text": " in a faraway land, there lived a brave knight...",
"index": 0,
"logprobs": null,
"finish_reason": "length"
}],
"usage": {
"prompt_tokens": 4,
"completion_tokens": 50,
"total_tokens": 54
}
}
Embeddings
Create Embeddings (Coming Soon)
Note: This endpoint is coming soon and not yet available.
Generate vector representations of text.
POST /v1/embeddings
Request Body:
{
"model": "text-embedding-3-small",
"input": "The quick brown fox jumps over the lazy dog",
"encoding_format": "float"
}
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
model |
string | Yes | - | Embedding model ID |
input |
string/array | Yes | - | Text(s) to embed |
encoding_format |
string | No | "float" | Format: "float" or "base64" |
dimensions |
integer | No | Model default | Output dimensions |
Response:
{
"object": "list",
"data": [{
"object": "embedding",
"index": 0,
"embedding": [0.0023064255, -0.009327292, ...]
}],
"model": "text-embedding-3-small",
"usage": {
"prompt_tokens": 9,
"total_tokens": 9
}
}
Images (Coming Soon)
Create Image
Note: This endpoint is coming soon and not yet available.
Generate images from text prompts.
POST /v1/images/generations
Request Body:
{
"model": "dall-e-3",
"prompt": "A white siamese cat wearing a space helmet",
"n": 1,
"size": "1024x1024",
"quality": "standard"
}
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
model |
string | Yes | - | Model: dall-e-2, dall-e-3 |
prompt |
string | Yes | - | Text description |
n |
integer | No | 1 | Number of images |
size |
string | No | "1024x1024" | Image dimensions |
quality |
string | No | "standard" | Quality: standard, hd |
style |
string | No | "vivid" | Style: vivid, natural |
response_format |
string | No | "url" | Format: url, b64_json |
Response:
{
"created": 1677652288,
"data": [{
"url": "https://generated-image-url.com/image.png",
"revised_prompt": "A white Siamese cat wearing a detailed space helmet..."
}]
}
Audio (Coming Soon)
Create Transcription
Note: This endpoint is coming soon and not yet available.
Convert audio to text.
POST /v1/audio/transcriptions
Content-Type: multipart/form-data
Form Data:
| Field | Type | Required | Description |
|---|---|---|---|
file |
file | Yes | Audio file (mp3, mp4, mpeg, mpga, m4a, wav, webm) |
model |
string | Yes | Model ID (whisper-1) |
language |
string | No | Language code (ISO-639-1) |
prompt |
string | No | Context prompt |
response_format |
string | No | Format: json, text, srt, verbose_json, vtt |
temperature |
number | No | Sampling temperature |
Response:
{
"text": "Hello, this is the transcribed audio content."
}
Create Translation
Note: This endpoint is coming soon and not yet available.
Translate audio to English.
POST /v1/audio/translations
Content-Type: multipart/form-data
Same parameters as transcription, but always translates to English.
Models
List Models
Get available models and pricing.
GET /v1/models
Response:
{
"object": "list",
"data": [
{
"id": "gpt-3.5-turbo",
"object": "model",
"created": 1677610602,
"owned_by": "openai",
"permission": [...],
"root": "gpt-3.5-turbo",
"parent": null,
"pricing": {
"prompt": 0.001,
"completion": 0.002,
"unit": "1k tokens"
}
}
]
}
List Model Paths
Get the upstream provider paths each advertised model can be reached through. This is discovery data only; routing still chooses the provider per request.
GET /v1/models/paths
Response:
{
"data": [
{
"id": "claude-sonnet-4",
"paths": [
{"path": "anthropic"},
{"path": "openrouter:Anthropic"}
]
}
]
}
List Paths for One Model
Use a query parameter so model IDs containing / are handled safely. Lookup is
by the public, unqualified model ID: glm-5v-turbo resolves
z-ai/glm-5v-turbo, and deepseek-v4-pro and deepseek/deepseek-v4-pro
return the same merged path set.
GET /v1/models/paths/model?model_id=anthropic/claude-sonnet-4
Response:
{
"data": [
{"path": "anthropic"},
{"path": "openrouter:Anthropic"}
]
}
Model IDs in responses are base model IDs: the leading provider prefix such as
z-ai/ or openai/ is stripped (the same rule routing uses, so the ID can be
sent back to /v1/chat/completions verbatim). Path values match the provider
string stamped on chat-completion responses, such as anthropic,
generic:Anthropic, openrouter:Anthropic, or unknown (native OpenRouter
with no usable sub-provider). Responses also carry an updated_at Unix
timestamp of the last successful refresh (null when no refresh has run).
Wallet Management
Create Wallet (Coming Soon)
Note: This endpoint is coming soon. Currently, you can use Cashu tokens directly as API keys.
Create a new wallet with eCash deposit.
POST /v1/wallet/create
Request Body:
{
"cashu_token": "cashuAeyJ0...",
"admin_key": "optional-admin-key"
}
Response:
{
"api_key": "sk-1234567890abcdef",
"admin_key": "radmin_fedcba0987654321",
"balance": 10000,
"mint": "https://mint.example.com",
"unit": "sat"
}
Get Key Information
Get current balance, consumption data, and child keys for an API key.
GET /v1/balance/info
Authorization: Bearer sk-...
Response:
{
"api_key": "sk-abc...",
"balance": 8500000,
"reserved": 0,
"is_child": false,
"parent_key": null,
"total_requests": 42,
"total_spent": 1500000,
"balance_limit": null,
"balance_limit_reset": null,
"validity_date": null,
"child_keys": [
{
"api_key": "sk-child1...",
"total_requests": 10,
"total_spent": 500000,
"balance_limit": 1000000,
"balance_limit_reset": "daily",
"validity_date": 1738000000
}
]
}
balance is the spendable balance used by request admission.
Check Balance
Get current wallet balance.
GET /v1/wallet/balance
Authorization: Bearer sk-...
Response:
{
"balance": 8500,
"currency": "sat",
"reserved": 0
}
Top Up Wallet
Add funds to existing wallet.
POST /v1/wallet/topup
Authorization: Bearer sk-...
Request Body:
{
"cashu_token": "cashuAeyJ0..."
}
Response:
{
"balance": 18500,
"amount_added": 10000,
"currency": "sat"
}
Withdraw Funds
Withdraw balance as eCash.
POST /v1/wallet/withdraw
Authorization: Bearer sk-...
Request Body:
{
"amount": 5000,
"mint": "https://mint.example.com"
}
Response:
{
"cashu_token": "cashuAeyJ0...",
"amount": 5000,
"mint": "https://mint.example.com"
}
Create Child Key
Creates one or more child API keys that share the parent's balance. Each child key creation costs a fixed amount (configurable).
POST /v1/balance/child-key
Authorization: Bearer sk-...
Request Body:
{
"count": 1
}
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
count |
integer | Yes | - | Number of child keys to create (1-50) |
Response:
{
"api_keys": ["sk-abc...", "sk-def..."],
"count": 2,
"cost_msats": 2000,
"cost_sats": 2,
"parent_balance": 98000,
"parent_balance_sats": 98
}
Provider Discovery
Admin Settings
These endpoints are protected by the Admin cookie (admin_password set to your configured admin password).
Get Settings
GET /admin/api/settings
Returns the current application settings (sensitive values may be redacted).
Update Settings
PATCH /admin/api/settings
Content-Type: application/json
Body is a partial JSON of settings fields to update. Validated and persisted to the database.
List Providers
Get available upstream providers.
GET /v1/providers
Response:
{
"providers": [
{
"name": "openai",
"models": ["gpt-4", "gpt-3.5-turbo"],
"endpoints": ["chat/completions", "completions"],
"status": "active"
}
]
}
Provider Info
Get specific provider details.
GET /v1/providers/{provider_name}
Response:
{
"name": "openai",
"display_name": "OpenAI",
"description": "Official OpenAI API",
"models": [
{
"id": "gpt-4",
"name": "GPT-4",
"context_window": 8192,
"pricing": {
"prompt": 0.03,
"completion": 0.06,
"unit": "1k tokens"
}
}
],
"endpoints": ["chat/completions", "completions", "embeddings"],
"features": ["streaming", "function_calling"],
"status": "active"
}
Rate Limiting
All endpoints are subject to rate limiting:
- Per minute: 60 requests
- Per hour: 1000 requests
- Per day: 10000 requests
Rate limit information is included in response headers.
Next Steps
- Errors - Error handling reference
- Authentication - Auth details
- Integration Guide - Code examples