relay

Documentation

Providers

Anthropic, OpenAI, and any OpenAI-compatible endpoint. Routing is automatic by model prefix; per-tenant credentials are encrypted at rest.

Routing by model

The model string in createAgent({ model }) determines the provider. No separate option to set.

PatternProviderExamples
claude-*anthropicclaude-sonnet-4-6, claude-opus-4-7, claude-haiku-4-5
gpt-*, chatgpt-*openaigpt-4o, gpt-4o-mini, gpt-4.1, gpt-4.1-mini
o1-*, o3-*, o4-*openaio3, o3-mini, o4-mini
anthropic:<model>anthropicanthropic:claude-sonnet-4-6
openai:<model>openaiopenai:llama3.1, openai:mistral-7b

Upload credentials (BYOK)

Per-tenant credentials. AES-256-GCM at rest. The runtime never sees a Relay key and the credentials never leave the control plane in plain text.

Anthropic

curl -X PUT $RELAY_URL/v1/credentials/anthropic \
  -H "authorization: Bearer $RELAY_API_KEY" \
  -H "content-type: application/json" \
  -d '{"apiKey":"sk-ant-..."}'

OpenAI

curl -X PUT $RELAY_URL/v1/credentials/openai \
  -H "authorization: Bearer $RELAY_API_KEY" \
  -H "content-type: application/json" \
  -d '{"apiKey":"sk-..."}'

OpenAI-compatible (Ollama, vLLM, Groq, Together, OpenRouter…)

Any service that speaks the OpenAI Chat Completions API works. Configure baseUrl in the credential.

# Ollama on localhost
curl -X PUT $RELAY_URL/v1/credentials/openai \
  -H "authorization: Bearer $RELAY_API_KEY" \
  -H "content-type: application/json" \
  -d '{"apiKey":"ollama","baseUrl":"http://localhost:11434/v1"}'

# Then use any model the endpoint serves:
RELAY_MODEL=openai:llama3.1 pnpm example

Rotation & deletion

PUT overwrites the existing credential for that (tenant, provider) pair. There's no separate “update” — same endpoint, new payload.

# List (never returns secrets)
curl -H "authorization: Bearer $RELAY_API_KEY" $RELAY_URL/v1/credentials

# Revoke
curl -X DELETE -H "authorization: Bearer $RELAY_API_KEY" \
  $RELAY_URL/v1/credentials/openai

Models with good autocomplete

The SDK union types know about common Anthropic + OpenAI models, but accepts any string (escape-hatched with (string & {})) so new releases don't require an SDK bump.

import type { AnthropicModel, OpenAIModel, ModelId } from "@relayhq/sdk";

const m1: AnthropicModel = "claude-sonnet-4-6";
const m2: OpenAIModel    = "gpt-4o-mini";
const m3: ModelId        = "openai:llama3.1"; // any string also valid

Add a new provider

Adding Gemini, Cohere, or Bedrock-native is one Go file plus a router entry. See CONTRIBUTING.md for the step-by-step.