Files
routstr-core/docs/api/endpoints.md
T
9qeklajc f96acbb99c fix: address model-paths review findings
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.
2026-07-26 13:23:31 +02:00

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-... or Authorization: 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