Platform Integration

Upthos Relay is fully compatible with the official Anthropic, OpenAI, and Gemini API protocols. Any official SDK that supports a custom base URL drops in without changing your business code. This page lists the minimum runnable configuration for each common SDK plus the gotchas you need to know.

Prerequisites

  1. Create an API key at API Keys. The key must be assigned to a group whose platform matches the protocol you'll call:
    • Claude traffic → Anthropic-protocol group (Claude Max, Claude Starter/Standard/Advanced, etc.)
    • OpenAI / Codex traffic → OpenAI-protocol group (Codex Basic/Standard, OpenAI Enterprise, etc.)
    • Gemini traffic → Google-protocol group
  2. Hitting the wrong protocol with a key bound to a different platform returns 403 permission_error.
  3. Any of three auth headers works, in priority order: Authorization: Bearer → x-api-key → x-goog-api-key.

1. Anthropic / Claude Agent SDK

Set two env vars and the official Anthropic SDK, Claude Agent SDK, and Claude Code all work without code changes.

export ANTHROPIC_BASE_URL=https://relay.upthos.com
export ANTHROPIC_AUTH_TOKEN=sk-...

ANTHROPIC_BASE_URL does not include /v1 — the SDK appends it.
ANTHROPIC_AUTH_TOKEN uses Bearer auth (default for Agent SDK / Claude Code). Older SDKs that read ANTHROPIC_API_KEY (sent as x-api-key) also work.

Claude Agent SDK (recommended for embedding)

// npm install @anthropic-ai/claude-agent-sdk
import { query } from '@anthropic-ai/claude-agent-sdk'

for await (const msg of query({
  prompt: 'Summarize this repo structure',
  options: { model: 'claude-sonnet-4-6' },
})) {
  console.log(msg)
}
# pip install claude-agent-sdk
from claude_agent_sdk import query, ClaudeAgentOptions

async for msg in query(
    prompt="Summarize this repo structure",
    options=ClaudeAgentOptions(model="claude-sonnet-4-6"),
):
    print(msg)

Anthropic SDK (direct Messages API)

// npm install @anthropic-ai/sdk
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-6',
  max_tokens: 1024,
  messages: [{ role: 'user', content: 'Hello' }],
})
# pip install anthropic
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-6",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Hello"}],
)

Full endpoints (/v1/messages, /v1/messages/count_tokens, /v1/models, /v1/usage) are documented in Anthropic API.

2. OpenAI SDK

export OPENAI_BASE_URL=https://relay.upthos.com/v1     # note: this one DOES include /v1
export OPENAI_API_KEY=sk-...
// npm install openai
import OpenAI from 'openai'

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

// Chat Completions
const resp = await client.chat.completions.create({
  model: 'gpt-5.5',
  messages: [{ role: 'user', content: 'Hello' }],
})

// Responses API (agent / tool use)
const r = await client.responses.create({
  model: 'gpt-5.5',
  input: 'Hello',
})
# pip install openai
from openai import OpenAI

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

resp = client.chat.completions.create(
    model="gpt-5.5",
    messages=[{"role": "user", "content": "Hello"}],
)

Supported endpoints:

  • POST /v1/chat/completions — standard chat
  • POST /v1/responses — Responses API (agent / tool use / WebSocket bidirectional stream)
  • POST /v1/images/generations, POST /v1/images/edits — OpenAI-compatible sync images API, returns the standard {data: [{url|b64_json}]} shape. Drop-in for the OpenAI SDK.
  • POST /v1/images/tasks, GET /v1/images/tasks/:id, POST /v1/images/tasks/:id/cancel, POST /v1/images/tasks/batch, POST /v1/images/uploads — RayRelay async task model. Returns task_id immediately; poll for a stable R2 URL. Supports mid-flight cancel and img2img reference uploads.

Both paths bill identically (matrix price × fx_rate × flat 1.0). Pick sync for SDK compatibility, async for long-running jobs, mid-flight cancel, and persistent shareable URLs. The legacy /v1/tasks/:id, /v1/tasks/batch, /v1/tasks/:id/cancel aliases still work but emit Deprecation: true; migrate to /v1/images/tasks/* when convenient.

3. Codex CLI (@openai/codex)

Use Codex when the customer wants to embed a CLI agent as a child process inside their internal platform (instead of speaking the OpenAI HTTP protocol directly):

# ~/.codex/config.toml
model_provider = "upthos"
model = "gpt-5.6-sol"
review_model = "gpt-5.6-sol"
model_reasoning_effort = "high"
model_context_window = 272000

[model_providers.upthos]
name = "upthos"
base_url = "https://relay.upthos.com"
wire_api = "responses"
requires_openai_auth = true
// ~/.codex/auth.json
{ "OPENAI_API_KEY": "sk-..." }

Full walkthrough: Codex Quick Start.

For programmatic OpenAI-protocol calls without the CLI, use the OpenAI SDK above.

4. Gemini SDK

@google/genai (the new unified SDK) supports a custom endpoint:

// npm install @google/genai
import { GoogleGenAI } from '@google/genai'

const ai = new GoogleGenAI({
  apiKey: process.env.UPTHOS_API_KEY,
  httpOptions: { baseUrl: 'https://relay.upthos.com' },
})

const resp = await ai.models.generateContent({
  model: 'gemini-2.5-pro',
  contents: 'Hello',
})
# pip install google-genai
from google import genai

client = genai.Client(
    api_key=os.environ["UPTHOS_API_KEY"],
    http_options={"base_url": "https://relay.upthos.com"},
)

resp = client.models.generate_content(
    model="gemini-2.5-pro",
    contents="Hello",
)

Plain REST (no SDK):

curl https://relay.upthos.com/v1beta/models/gemini-2.5-pro:generateContent \
  -H "x-goog-api-key: $UPTHOS_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "contents": [{ "parts": [{ "text": "Hello" }] }]
  }'

Supported endpoints:

  • GET /v1beta/models
  • POST /v1beta/models/{model}:generateContent
  • POST /v1beta/models/{model}:streamGenerateContent

Things to know

  1. Use the official bare model IDs: claude-sonnet-4-6, claude-opus-4-7, claude-haiku-4-5, gpt-5.5, gemini-2.5-pro. Full list and routing in Supported Models.
  2. Streaming / SSE passes through unchanged. Set stream: true or call :streamGenerateContent; the gateway does not re-frame or buffer.
  3. Tool use and prompt caching pass through unchanged. No relay-specific adaptation needed.
  4. Request body size. The gateway enforces a 10 MB hard limit (returns 413 over). Some upstream suppliers also enforce a tighter byte ceiling (typically 5 MB) that hits before any model-side token limit — multi-image base64 payloads are the usual trigger. Prefer uploading via /v1/images/uploads and referencing the URL, or compress on the client.
  5. Treat API keys as account credentials. Strongly recommend proxying through your server side; do not ship them in frontend bundles, mobile binaries, or public repos.
  6. Error format follows the calling protocol. Anthropic paths return Anthropic errors, OpenAI paths return OpenAI errors, Gemini paths return Google errors. Existing SDK error handling works as-is.
  7. Models available are scoped by group. Calling a model the group doesn't support returns 404 not_found_error. Hit GET /v1/models (or /v1beta/models) first to confirm what's available for the current key.

Pre-flight checklist

  • API key assigned to a group on the correct platform
  • Base URL configured correctly (Anthropic without /v1, OpenAI with /v1, Gemini using /v1beta)
  • API key lives only in server-side env vars / secret manager — not in frontend code or git history
  • GET /v1/models (or /v1beta/models) confirms the model IDs you plan to call
  • At least one non-streaming and one streaming call verified
  • Long-context / multi-image requests stay under 10 MB (ideally ≤ 5 MB to avoid upstream byte ceilings)
  • Application-side handling for 401 / 403 / 429 / 503 (retry / fallback)

When filing an issue, include the x-request-id response header so support can locate the trace quickly.