Using your key
A Relaybee key is a bearer token for an OpenAI-shaped API. There is nothing to install and no account. Every example on this page is filled in with your own key, so you can copy one and run it.
Your key
Read from this browser. It is the same key the home page gave you.
1. The call that needs no provider key
Two model strings, and the difference is whose machine answers. claude-code goes
to a supporter node running under this same key, so the job is only ever offered to your own
machines. claude-code/public offers it to anyone who has opted a node into the shared
pool, which is how you get an answer without running anything yourself, and it means a stranger
reads your prompt and writes what comes back. Your key is the only credential either way.
The examples below send claude-code/public, because that is the one somebody else
can answer. Drop the /public once you are running a node of your own.
Send "stream": true for either of them. Not for the typing effect: a node takes
20 to 30 seconds on a real question, and a buffered response has to give up before then because
the platform requires one to start within 25 seconds. A streaming response starts immediately and
then holds for up to about 110 seconds, which is the only window long enough to actually receive
an answer.
curl -N __ORIGIN__/api/v1/chat/completions \
-H "Authorization: Bearer __KEY__" \
-H "Content-Type: application/json" \
-d '{"model":"claude-code/public",
"stream":true,
"messages":[{"role":"user","content":"Say hello in one sentence."}]}'
$body = @{
model = 'claude-code/public'
stream = $true
messages = @(@{ role = 'user'; content = 'Say hello in one sentence.' })
} | ConvertTo-Json -Depth 5
curl.exe -N __ORIGIN__/api/v1/chat/completions `
-H "Authorization: Bearer __KEY__" `
-H "Content-Type: application/json" `
-d $body
Use curl.exe, not curl: the bare name is an alias for
Invoke-WebRequest, which takes different flags. The single quotes in the curl version do not
survive PowerShell, which is why the body is built as an object here.
2. Or run it right here
Same request, same key, sent from this page. If it answers, your key works. It sends
claude-code/public unless a node of your own is online, in which case it sends
claude-code and the prompt stays on your machine. The public pool means a stranger's
machine answers it and reads what you type here, so treat this box as public.
3. The same call from code
Relaybee speaks OpenAI's wire format, so any OpenAI client works. Point baseURL at
Relaybee and pass your key where the OpenAI key would go.
import OpenAI from 'openai'
const relaybee = new OpenAI({
baseURL: '__ORIGIN__/api/v1',
apiKey: '__KEY__',
})
const stream = await relaybee.chat.completions.create({
model: 'claude-code/public',
messages: [{ role: 'user', content: 'Say hello in one sentence.' }],
stream: true,
})
for await (const part of stream) {
process.stdout.write(part.choices[0]?.delta?.content ?? '')
}
from openai import OpenAI
relaybee = OpenAI(base_url="__ORIGIN__/api/v1", api_key="__KEY__")
stream = relaybee.chat.completions.create(
model="claude-code/public",
messages=[{"role": "user", "content": "Say hello in one sentence."}],
stream=True,
)
for part in stream:
print(part.choices[0].delta.content or "", end="", flush=True)
Most tools that already speak OpenAI need no code at all, just these two.
OPENAI_BASE_URL=__ORIGIN__/api/v1 OPENAI_API_KEY=__KEY__
These send claude-code/public, the shared pool. Use plain
claude-code to keep a job on the nodes running under your own key.
4. Bringing your own provider key
The other path. Instead of a supporter, Relaybee calls Anthropic, OpenAI, or Groq with a credential you supply. Relaybee does not store it: the key comes back to you encrypted into a blob that only your Relaybee key can open. Two calls, seal once and then send that blob on every request.
# 1. Seal your provider key. Keep the "connection" value it returns.
curl __ORIGIN__/api/connect \
-H "Authorization: Bearer __KEY__" \
-H "Content-Type: application/json" \
-d '{"provider":"anthropic","apiKey":"sk-ant-...","label":"personal"}'
# 2. Send it on every call, in a header.
curl __ORIGIN__/api/v1/chat/completions \
-H "Authorization: Bearer __KEY__" \
-H "X-Relaybee-Connection: <the connection value>" \
-H "Content-Type: application/json" \
-d '{"model":"anthropic/claude-opus-5",
"messages":[{"role":"user","content":"hi"}]}'
# 1. Seal your provider key, and keep the connection value it returns.
$seal = @{ provider = 'anthropic'; apiKey = 'sk-ant-...'; label = 'personal' } | ConvertTo-Json
$conn = (curl.exe __ORIGIN__/api/connect `
-H "Authorization: Bearer __KEY__" `
-H "Content-Type: application/json" `
-d $seal | ConvertFrom-Json).connection
# 2. Send it on every call, in a header.
$body = @{
model = 'anthropic/claude-opus-5'
messages = @(@{ role = 'user'; content = 'hi' })
} | ConvertTo-Json -Depth 5
curl.exe __ORIGIN__/api/v1/chat/completions `
-H "Authorization: Bearer __KEY__" `
-H "X-Relaybee-Connection: $conn" `
-H "Content-Type: application/json" `
-d $body
Comma-separate up to 8 connections in that header to pool them. Relaybee starts at a random one
and fails over to the next on 401, 403, 429, or 5xx, so a pool behaves like one key with the
combined quota. The X-Relaybee-Pool-Health response header reports how each attempt
went, in the order tried.
Models
| Model string | Goes to | Needs |
|---|---|---|
claude-code | A node running under your own key | Your key, and a node of your own |
claude-code/public | Any node that opted into the shared pool | Your key only |
anthropic/<model> | Anthropic | A sealed connection |
openai/<model> | OpenAI | A sealed connection |
groq/<model> | Groq | A sealed connection |
On a provider model the part after the slash is passed through untouched, so
anthropic/claude-opus-5 and groq/llama-3.3-70b-versatile both work.
claude-code is the exception: its slash names a pool, not a model.
GET /api/v1/models lists the models you can call without bringing anything, and the providers you can route to if you do.
When it does not work
| Status | What happened | What to do |
|---|---|---|
| 401 | The key is missing, malformed, or expired. | Keys last 90 days. Mint another above. |
| 400 | Bad model string, empty messages, or an oversized body. | The message says which. Bodies cap at 256KB, relay messages at 32KB. |
| 403 | A connection blob was sealed by a different key. | Blobs are bound to their owner. Reseal with the key you are using now. |
| 429 | Rate limited. | 20 requests a minute per key, 60 per source address. X-RateLimit-Reset says when. |
| 502 | The relay queue is unreachable. | Transient. Retry shortly. |
| 504 | Nobody answered in time. | The message says which: no node of your own for claude-code, nobody opted into the pool for claude-code/public, or a node that is still writing. For the last, use "stream": true. |
| 503 | Relaybee itself is missing a server secret. | Not your side. Nothing to retry. |
Errors come back in the OpenAI envelope, {"error":{"message":"…","type":"…"}},
with a message written to be read rather than looked up.
Everything else
| Endpoint | What it does |
|---|---|
POST /api/keys/issue | Mint a key. No auth, 10 per minute per source. |
POST /api/connect | Seal a provider key into a blob you keep. |
POST /api/v1/chat/completions | The one that answers questions. |
GET /api/v1/models | List callable models, and the providers you can route to. |
GET /api/work/status | Whether a node of your own is online, and how many are online in total. |
GET /api/health | Liveness, queue backend, deployed commit. |
POST /api/work/next, POST /api/work/stream, and POST /api/work/complete are the supporter
side. You do not call those to use Relaybee; a supporter node does. The whole loop is at
/llms.txt.
Worth knowing
- Relaybee keeps no record of your key, so a lost key cannot be shown again. Copy it somewhere.
- A
claude-code/publicanswer is written by a stranger's machine, and that stranger can read your prompt. It is a disclosed trust relationship in both directions. Plainclaude-codenever leaves the nodes running under your own key. - Either way somebody has to be running a node. For
claude-codethat is your own, which the light above reports directly. Forclaude-code/publicthe count is a ceiling rather than a promise: watching the shared pool is opt-in, and the count cannot see who opted in. - This is a demo on free hosting, not a production service.