Integration guide
Connecting to BestRelay, in a preface and six chapters
Two settings decide everything: where your client sends requests, and which key it sends with them. This guide gives the exact values for each protocol.
Preface: what this guide covers
Whichever client you use comes down to the same two settings: the address requests go to, and the key that goes with them. The chapters below give the values for each protocol, then explain how calls are billed and which status codes you may meet.
Read the first chapter whatever you use; after that, turn to the chapter for your tool.
I. The key and the base address
Create a key under API keys in the dashboard. All API traffic goes to one host, kept apart from the website:
https://api.bestapirelay.com
How the host is written depends on the protocol your client speaks:
- OpenAI-compatible clients and SDKs: the host plus /v1, with the key sent as a Bearer token.
- Anthropic clients such as Claude Code and Claude Desktop: the bare host, with the key in x-api-key or ANTHROPIC_AUTH_TOKEN.
- Gemini clients: the bare host, with the key in x-goog-api-key.
II. OpenAI-compatible calls: cURL, SDKs and Codex
Chat requests go to /v1/chat/completions and the Responses API to /v1/responses. A first call from a terminal confirms the key works:
curl https://api.bestapirelay.com/v1/chat/completions \
-H "Authorization: Bearer bsr_your_key_here" -H "Content-Type: application/json" \
-d '{"model": "gpt-6.1-sol", "messages": [{"role": "user", "content": "Describe a well-made fountain pen in one sentence."}]}'In code, point any OpenAI SDK at the same base. With the asynchronous Python client it reads like this:
import asyncio
from openai import AsyncOpenAI
bestrelay_client = AsyncOpenAI(base_url="https://api.bestapirelay.com/v1", api_key="bsr_your_key_here")
async def ask_the_atelier():
fountain_pen = await bestrelay_client.chat.completions.create(
model="gpt-6.1-sol",
messages=[{"role": "user", "content": "Describe a well-made fountain pen in one sentence."}],
)
print(fountain_pen.choices[0].message.content)
asyncio.run(ask_the_atelier())Codex reads its provider from a configuration file:
# ~/.codex/config.toml (BestRelay as the provider)
model = "gpt-6.1-sol" # any GPT id from the rate card
model_provider = "bestrelay"
[model_providers.bestrelay]
name = "BestRelay"
base_url = "https://api.bestapirelay.com/v1"
env_key = "BESTRELAY_API_KEY" # export BESTRELAY_API_KEY=bsr_your_key_here
wire_api = "responses" # Codex speaks the Responses APIRecommended GPT ids: gpt-6.1-sol, gpt-6-astra, gpt-5.6-sol
III. Gemini's native route
Gemini CLI takes the bare host as its base URL (do not append /v1beta) and your BestRelay key as GEMINI_API_KEY:
export GOOGLE_GEMINI_BASE_URL=https://api.bestapirelay.com
export GEMINI_API_KEY=bsr_your_key_here
geminiDirect calls use the native generateContent route, with the key in an x-goog-api-key header:
curl "https://api.bestapirelay.com/v1beta/models/gemini-3.8-flash:generateContent" \
-H "x-goog-api-key: bsr_your_key_here" -H "Content-Type: application/json" \
-d '{"contents": [{"role": "user", "parts": [{"text": "Which printing press came first?"}]}]}'Gemini models speak only their native protocol. For streaming, call :streamGenerateContent?alt=sse; the OpenAI-style /v1/chat/completions route does not reach them.
Gemini model ids to send: gemini-3.1-pro, gemini-4-argon, gemini-3.8-flash, gemini-2.5-flash
IV. Claude Code and Claude Desktop
Set two environment variables and start Claude Code as usual. The base URL is the bare host, without /v1:
export ANTHROPIC_BASE_URL=https://api.bestapirelay.com
export ANTHROPIC_AUTH_TOKEN=bsr_your_key_here
claudeOn Windows (PowerShell or cmd), keep the same two variables with setx, then open a new terminal:
setx ANTHROPIC_BASE_URL https://api.bestapirelay.com
setx ANTHROPIC_AUTH_TOKEN bsr_your_key_hereClaude models are served only to the official Claude Code and Claude Desktop clients, and the upstream requires Claude Code 2.1.285 or newer. GPT, Gemini and the other families work with any compatible client or SDK.
V. How a call is billed
Each call is charged once, after the response ends, from the input, output and cache tokens the provider reports, at the prices on the rate card. Nothing is held in advance.
If a successful call arrives without any usage figures, it is charged as an estimate of 2,000 input and 2,000 output tokens, and the ledger line says so. If your client disconnects part-way through a stream, the call is still billed from what the provider reports.
Requests the provider rejects, and token-counting requests, are recorded at zero. A final call may take the balance a little below zero; requests then return 402 until you top up.
VI. Status codes you may meet
Errors come back in the familiar JSON envelope, with a message written by BestRelay:
- 400
- The request names no model or an unknown one, or uses a route that does not match the model's protocol.
- 401
- No key was sent, or the key is unknown or void.
- 402
- The balance is used up; top up to continue.
- 403
- The account behind the key is paused.
- 404
- No route exists at that path.
- 413
- The request body is larger than 25 MB.
- 429
- More than 120 requests a minute on one key, or eight calls already in flight on one account.
- 502
- The provider could not be reached; nothing was charged.
- 503
- The upstream line for that model is not configured yet.