SaveRouter.
Log in with Telegram

SaveRouter API

SaveRouter - a unified, Anthropic-compatible API to top Claude models. Strictly pay-as-you-go by tokens, instant start, no minimums and no fixed plans. Compatible with the Anthropic Messages API - works with any client: Anthropic SDK, OpenClaw, curl, any HTTP.

Overview

SaveRouter gives you a unified, Anthropic-compatible API to top Claude models. You pay only for the tokens you use - no minimums, no fixed plans. Compatibility with the Anthropic Messages API means zero migration: any existing Anthropic SDK code works after changing the base_url.

🔗

Single endpoint

One URL and one format for every Claude model. No per-model plumbing.

🧩

Anthropic compatible

The same Messages API. Anthropic SDK, curl, any HTTP client work without code changes.

🪙

Pay per token

You pay strictly for the tokens you consume. No minimums, no fixed plans - instant start.

High availability

Built for stable operation under load with fast response times.

Quickstart

Three ways to connect in a minute. Base URL is https://api.saverouter.com, path is /v1/messages, header is x-api-key.

Direct API (curl)

A minimal HTTP request - nothing but curl:

curl
# request
curl https://api.saverouter.com/v1/messages \
  -H "x-api-key: sk-sr-v1-YOUR_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-opus-4-8",
    "max_tokens": 1024,
    "messages": [{"role": "user", "content": "Hi!"}]
  }'

Anthropic SDK

The official Anthropic SDK (Python / Node) - only base_url changes:

Python
from anthropic import Anthropic

client = Anthropic(
    api_key="sk-sr-v1-YOUR_KEY",
    base_url="https://api.saverouter.com",
)
msg = client.messages.create(
    model="claude-opus-4-8",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Hi!"}],
)
print(msg.content[0].text)
Node.js
import Anthropic from '@anthropic-ai/sdk';

const client = new Anthropic({
  apiKey: 'sk-sr-v1-YOUR_KEY',
  baseURL: 'https://api.saverouter.com',
});
const msg = await client.messages.create({
  model: 'claude-opus-4-8',
  max_tokens: 1024,
  messages: [{ role: 'user', content: 'Hi!' }],
});
console.log(msg.content[0].text);

OpenClaw agent

Connect via a provider in OpenClaw (see the “OpenClaw agent” section):

models.json
// ~/.openclaw/openclaw.json (JSON5 — comments allowed)
{
  "models": {
    "providers": {
      "saverouter": {
        "baseUrl": "https://api.saverouter.com",
        "api": "anthropic-messages",
        "apiKey": "sk-sr-v1-YOUR_KEY",
        "authHeader": false,
        "headers": { "x-api-key": "sk-sr-v1-YOUR_KEY" },
        "models": [
          { "id": "claude-opus-4-8", "name": "Opus 4.8" },
          { "id": "claude-sonnet-4-6", "name": "Sonnet 4.6" }
        ]
      }
    }
  },
  "agents": {
    "defaults": {
      "model": { "primary": "saverouter/claude-opus-4-8" }
    }
  }
}

Authentication

Requests are authenticated with the x-api-key header carrying your key in the sk-sr-v1-... format. Keys are issued in your dashboard (Telegram login).

  • Key header: x-api-key: sk-sr-v1-xxxxx
  • API version: anthropic-version: 2023-06-01
  • Content type: content-type: application/json
⚠️
Use x-api-key, not Authorization: Bearer - this is the most common integration mistake (returns 403). Tip: keep the key in an environment variable, never commit it.

Endpoint

All requests use a single method:

endpoint
POST https://api.saverouter.com/v1/messages

The request body is the standard Anthropic Messages API format. The response is JSON in the same format (see “Response format”).

claude-opus-4-8top tier, most powerful
claude-sonnet-4-6faster & cheaper
claude-haiku-4-5cheapest & fastest

Request parameters

Body fields for /v1/messages (Anthropic Messages API format):

modelstringrequiredModel identifier, e.g. claude-opus-4-8.
max_tokensintrequiredMaximum number of tokens to generate.
messagesarrayrequiredConversation history: an array of {role, content} objects, roles user/assistant.
systemstringoptionalSystem prompt - sets the model behavior and context.
temperature0..1optionalResponse creativity. Lower is more deterministic, higher is more varied.
top_p0..1optionalNucleus sampling. An alternative to temperature.
top_kintoptionalRestricts sampling to the k most likely tokens.
stop_sequencesarrayoptionalStrings that, once produced, stop generation.
streambooloptionalIf true, the response is streamed in chunks via SSE.
toolsarrayoptionalTool definitions for function calling (see “Tool calling”).

Response format

A successful response is JSON in the Anthropic Messages format. The model text is in content[].text:

JSON
{
  "id": "msg_01ABC...",
  "type": "message",
  "role": "assistant",
  "model": "claude-opus-4-8",
  "content": [
    { "type": "text", "text": "Hi! How can I help?" }
  ],
  "stop_reason": "end_turn",
  "stop_sequence": null,
  "usage": { "input_tokens": 12, "output_tokens": 8 }
}
📊
The usage field (input_tokens / output_tokens) is what billing is based on. The sum of request and response tokens is charged against your balance at the model rate. stop_reason values: end_turn, max_tokens, stop_sequence, tool_use.

Streaming responses

Streaming (SSE) is supported, just like the Anthropic API. Add "stream": true to the body - the response arrives as a stream of text/event-stream events: message_start, a series of content_block_delta, then message_stop. The SDKs provide a convenient client.messages.stream(...) helper.

curl · stream
curl https://api.saverouter.com/v1/messages \
  -H "x-api-key: sk-sr-v1-YOUR_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-opus-4-8",
    "max_tokens": 1024,
    "stream": true,
    "messages": [{"role": "user", "content": "Write a haiku"}]
  }'
Python · stream
from anthropic import Anthropic

client = Anthropic(
    api_key="sk-sr-v1-YOUR_KEY",
    base_url="https://api.saverouter.com",
)
with client.messages.stream(
    model="claude-opus-4-8",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Hi!"}],
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)

Working with images (vision)

The Opus and Sonnet models accept images. Add a type:"image" block to the message content with a base64 source alongside a text block. You can mix text and images in a single message.

request body
{
  "model": "claude-opus-4-8",
  "max_tokens": 1024,
  "messages": [{
    "role": "user",
    "content": [
      {
        "type": "image",
        "source": {
          "type": "base64",
          "media_type": "image/jpeg",
          "data": "/9j/4AAQSkZJRg..."
        }
      },
      { "type": "text", "text": "What is in this image?" }
    ]
  }]
}
🖼️
Supported formats: JPEG, PNG, GIF, WebP. The image is base64-encoded and passed in source.data, with the type in media_type.

Tool calling

Function calling - works

Pass a tools array describing your functions. If the model decides to call a tool, it returns a type:"tool_use" block with name and input, and stop_reason becomes tool_use. Your client executes the tool and sends the result back as a type:"tool_result" block.

Request with tools
{
  "model": "claude-opus-4-8",
  "max_tokens": 1024,
  "tools": [{
    "name": "get_weather",
    "description": "Current weather for a city",
    "input_schema": {
      "type": "object",
      "properties": {
        "city": { "type": "string" }
      },
      "required": ["city"]
    }
  }],
  "messages": [
    { "role": "user", "content": "Weather in Dubai?" }
  ]
}
Response: tool_use
{
  "role": "assistant",
  "stop_reason": "tool_use",
  "content": [
    {
      "type": "tool_use",
      "id": "toolu_01ABC...",
      "name": "get_weather",
      "input": { "city": "Dubai" }
    }
  ]
}
🔧
After receiving tool_use, append the assistant message and a new user message with a tool_result block (same tool_use_id) - then repeat the request.
⚠️
SaveRouter is built for maximum intelligence and real agentic work. We recommend running with extended thinking enabled - that is where the models perform best in agentic scenarios. Accordingly, forced tool-use (tool_choice:{type:"tool"}) is incompatible with thinking and not recommended for agentic tasks. For strict JSON, use tool_choice:{type:"auto"} together with thinking - the model will still call your tool and return a valid tool_use. Non-reasoning modes (forced-tool without thinking, especially on large prompts) are not guaranteed and may hit short-window limits.

Limits & reliability

The service is built for high availability. On a transient error (429 or 5xx) an automatic retry with exponential backoff is recommended on the client side. The official Anthropic SDKs do this out of the box; for a custom HTTP client, a simple example is below.

retry with backoff
import time, httpx

def call_with_retry(payload, tries=5):
    for i in range(tries):
        r = httpx.post("https://api.saverouter.com/v1/messages",
                      headers={"x-api-key": KEY,
                               "anthropic-version": "2023-06-01"},
                      json=payload, timeout=60)
        if r.status_code not in (429, 500, 502, 503):
            return r
        time.sleep(2 ** i)  # 1, 2, 4, 8, 16s
    return r

Error codes

401
Invalid or revoked key. Check the x-api-key header.
402
Zero balance. Top up your account (USDT TRC-20) - access is restored immediately.
429
Rate limit exceeded. Retry with exponential backoff.
403
Request rejected. Most often the key was sent as Authorization: Bearer instead of x-api-key.

Pricing

Strictly per-token pricing (USD per 1M tokens):

Model
Input
Output
Cache write
Cache read
Opus
$5.00
$25.00
$6.25
$0.50
Sonnet
$3.00
$15.00
$3.75
$0.30
Haiku
$1.00
$5.00
$1.25
$0.10
💳
1 USDT = 1 credit. Top up with USDT (TRC-20) in your dashboard. At zero balance access is blocked (HTTP 402) - keep your balance positive.

Connecting an OpenClaw agent

Most important for agents

The easiest path is the OpenClaw CLI (it writes the provider into ~/.openclaw/openclaw.json for you):

terminal
# 1) add provider + key (edits openclaw.json for you)
openclaw models auth login --provider saverouter \
  --base-url https://api.saverouter.com \
  --api anthropic-messages \
  --api-key sk-sr-v1-YOUR_KEY

# 2) set it as the primary model
openclaw models set saverouter/claude-opus-4-8

# 3) verify the model is listed
openclaw models list

Or edit the config manually

Add the provider to ~/.openclaw/openclaw.json (the models.providers section) and set the primary model under agents.defaults.model:

openclaw.json
// ~/.openclaw/openclaw.json (JSON5 — comments allowed)
{
  "models": {
    "providers": {
      "saverouter": {
        "baseUrl": "https://api.saverouter.com",
        "api": "anthropic-messages",
        "apiKey": "sk-sr-v1-YOUR_KEY",
        "authHeader": false,
        "headers": { "x-api-key": "sk-sr-v1-YOUR_KEY" },
        "models": [
          { "id": "claude-opus-4-8", "name": "Opus 4.8" },
          { "id": "claude-sonnet-4-6", "name": "Sonnet 4.6" }
        ]
      }
    }
  },
  "agents": {
    "defaults": {
      "model": { "primary": "saverouter/claude-opus-4-8" }
    }
  }
}

Then in openclaw.json set the primary model to saverouter/claude-opus-4-8.

⚠️
The key is passed explicitly via headers: { x-api-key } with authHeader: false - otherwise the gateway sends Authorization: Bearer and gets a 403.
🔄
After editing the config, restart the gateway - a running process keeps the old model list in memory and won't re-read the file on the fly.
💡
Only an old model (e.g. 4.6) shows up in the picker? Most common causes: (1) you edited the wrong file - the provider must live in ~/.openclaw/openclaw.jsonmodels.providers, not the generated agents/main/agent/models.json; (2) an allowlist agents.defaults.models is set - add saverouter/claude-opus-4-8 to it; (3) the gateway wasn't restarted. Check with: openclaw models list.

Connecting agents

SaveRouter is an Anthropic-compatible endpoint, so it plugs into any agent that can talk to the Anthropic API: just switch the baseURL to https://api.saverouter.com and pass your key in the x-api-key: sk-sr-v1-... header. Below are examples for four popular coding agents.

SaveRouter works with any tool that speaks the Anthropic Messages API. Verified clients: Cursor, Cline, Roo Code, Kilo Code, Aider, Zed, Continue, OpenCode, Crush, Droid, Pi, Hermes, OpenClaw, plus the official Anthropic SDKs (Python / TypeScript), LangChain, LlamaIndex and any HTTP client. The principle is always the same: baseURL https://api.saverouter.com + the x-api-key header.

OCPlatform

Add a provider to models.json, then set the primary model to saverouter/claude-opus-4-8 in openclaw.json. The key is passed explicitly via headers: { x-api-key } with authHeader: false (see the “OpenClaw agent” section).

models.json
// ~/.openclaw/openclaw.json (JSON5 — comments allowed)
{
  "models": {
    "providers": {
      "saverouter": {
        "baseUrl": "https://api.saverouter.com",
        "api": "anthropic-messages",
        "apiKey": "sk-sr-v1-YOUR_KEY",
        "authHeader": false,
        "headers": { "x-api-key": "sk-sr-v1-YOUR_KEY" },
        "models": [
          { "id": "claude-opus-4-8", "name": "Opus 4.8" },
          { "id": "claude-sonnet-4-6", "name": "Sonnet 4.6" }
        ]
      }
    }
  },
  "agents": {
    "defaults": {
      "model": { "primary": "saverouter/claude-opus-4-8" }
    }
  }
}

Pi

Pi and Claude-compatible clients pick up the endpoint from environment variables. Since SaveRouter mirrors the Anthropic API, any client that reads ANTHROPIC_BASE_URL + x-api-key works with no code changes:

bash
export ANTHROPIC_BASE_URL="https://api.saverouter.com"
export ANTHROPIC_API_KEY="sk-sr-v1-YOUR_KEY"
# Pi / Claude-compatible clients pick up the endpoint automatically

Hermes

In the Hermes provider settings point the Anthropic-compatible baseURL and the x-api-key header at SaveRouter. The exact field names depend on your Hermes version - the essence is an Anthropic-compatible baseURL + key:

yaml
provider:
  type: anthropic
  base_url: https://api.saverouter.com
  api_key: sk-sr-v1-YOUR_KEY
  # sent as the x-api-key header
model: claude-opus-4-8

Kilo Code

In Kilo Code (VS Code) settings pick the “Anthropic” provider (or “Anthropic-compatible / Custom”), set Base URL https://api.saverouter.com, API Key sk-sr-v1-... and model claude-opus-4-8. Example settings.json fragment (setting names may differ by version):

settings.json
{
  "kilocode.apiProvider": "anthropic",
  "kilocode.anthropicBaseUrl": "https://api.saverouter.com",
  "kilocode.apiKey": "sk-sr-v1-YOUR_KEY",
  "kilocode.model": "claude-opus-4-8"
}
ℹ️
For Pi / Hermes / Kilo Code the exact config field names depend on the agent version. What stays the same everywhere: baseURL https://api.saverouter.com, the x-api-key header with an sk-sr-v1-... key, and a model name (e.g. claude-opus-4-8).
⚠️
Claude Code (Anthropic’s official CLI) is not supported.

FAQ

QIs it compatible with the Anthropic SDK?
Yes, fully. Use the official SDK and set base_url = https://api.saverouter.com. No code changes needed.
QWhat is the key format?
Keys look like sk-sr-v1-... and are passed in the x-api-key header.
QHow is it better than the direct Anthropic API?
Same API and request/response format. Strictly pay-as-you-go by tokens with no minimums, and instant start right after topping up.
QHow do I top up the balance?
Via USDT (TRC-20) in your dashboard. 1 USDT = 1 credit.
QWhat happens at zero balance?
Requests return HTTP 402. Top up your balance and access is restored immediately.
QAre streaming, tools and vision supported?
Yes, all of them. Streaming via SSE, function calling via tools, images via a type:"image" block.