Anthropic API

Upthos Relay exposes a drop-in compatible Anthropic Messages API. Any Anthropic client that lets you set a custom base URL (official SDKs, Claude Code, third-party apps) works directly against this endpoint.

Basics

Field Value
Base URL https://relay.upthos.com
Protocol Anthropic Messages API
anthropic-version 2023-06-01 (stable)
Content type application/json for request/response; text/event-stream for streaming

Authentication

Pass your API key via one of the following headers (in priority order):

Authorization: Bearer sk-...
x-api-key: sk-...
x-goog-api-key: sk-...

Create keys at Console → API Keys. The key must belong to an Anthropic-protocol group to call the endpoints below.

Security: treat API keys like passwords. Never commit them or share them publicly.

Endpoints

POST /v1/messages

Send a chat request. Request body, response body, and SSE event stream match the upstream Anthropic spec exactly.

Required: model, max_tokens, messages
Common optional: system, temperature, top_p, stop_sequences, tools, tool_choice, stream, thinking

Non-streaming:

curl https://relay.upthos.com/v1/messages \
  -H "Authorization: Bearer $UPTHOS_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-sonnet-4-5",
    "max_tokens": 1024,
    "messages": [
      { "role": "user", "content": "Hello" }
    ]
  }'

Streaming (SSE):

curl -N https://relay.upthos.com/v1/messages \
  -H "Authorization: Bearer $UPTHOS_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-sonnet-4-5",
    "max_tokens": 1024,
    "stream": true,
    "messages": [{ "role": "user", "content": "Introduce yourself in one sentence" }]
  }'

Official SDKs:

import Anthropic from '@anthropic-ai/sdk'

const client = new Anthropic({
  baseURL: 'https://relay.upthos.com',
  apiKey: process.env.UPTHOS_API_KEY,
})

const msg = await client.messages.create({
  model: 'claude-sonnet-4-5',
  max_tokens: 1024,
  messages: [{ role: 'user', content: 'Hello' }],
})
from anthropic import Anthropic

client = Anthropic(
    base_url="https://relay.upthos.com",
    api_key=os.environ["UPTHOS_API_KEY"],
)

msg = client.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Hello"}],
)

POST /v1/messages/count_tokens

Estimate input token count. Same request body shape as /v1/messages. Does not invoke the model and is not billed.

GET /v1/models

Lists models available to the current key's group:

{
  "object": "list",
  "data": [
    { "id": "claude-sonnet-4-5", "type": "model", "display_name": "claude-sonnet-4-5", "created_at": "2024-01-01T00:00:00Z" }
  ]
}

GET /v1/usage

Returns balance and aggregate usage for the current key. Primarily used by clients like CC Switch to show remaining quota.

Error format

Errors follow the upstream Anthropic shape:

{
  "type": "error",
  "error": {
    "type": "authentication_error",
    "message": "API key is required in Authorization header (Bearer scheme), x-api-key header, or x-goog-api-key header"
  }
}

Common error.type values:

type HTTP Meaning
authentication_error 401 Missing or invalid API key
permission_error 403 Key has no group assigned, or insufficient permission
not_found_error 404 Path or resource does not exist
rate_limit_error 429 Rate / concurrency limit exceeded
overloaded_error 503 Upstream overloaded or no account available
api_error 5xx Gateway or upstream internal error

Limits & differences

  • Request body size is bounded by the gateway's Gateway.MaxBodySize setting — relevant for image and long-context payloads.
  • Rate and concurrency limits are stacked between the group and the key. Excess requests return rate_limit_error.
  • model IDs follow the group's model_mapping and may differ from upstream names. Trust GET /v1/models as the source of truth.
  • When the key's balance is exhausted, /v1/messages returns permission_error. Top up in advance or handle the error in your client.