One gateway, every client. Anthropic & OpenAI-compatible access to Claude Opus 5, Opus 4.8 and GPT 5.6.
sk-mvx-…) is on the dashboard. Keep it secret; rotate anytime./v1/messages). OpenAI-style SDKs want /v1. Domain is always ohhmyagent.com.https://ohhmyagent.com/v1/messages # Anthropic Messages API
https://ohhmyagent.com/v1/chat/completions # OpenAI Chat Completions
https://ohhmyagent.com/v1/responses # OpenAI Responses API (Codex)
https://ohhmyagent.com/v1/models # list available modelsohh/claude-fable-5 # Claude Fable 5 (Fable Only wallet)
ohh/claude-opus-5 # Claude Opus 5 (GPT + Opus wallet)
ohh/claude-opus-4.8 # Claude Opus 4.8 (GPT + Opus wallet)
ohh/gpt-5.6 # GPT 5.6 auto-burst (Sol -> Terra -> Luna)
ohh/gpt-5.6-sol # pin GPT to the Sol deployment
ohh/gpt-5.6-terra # pin GPT to the Terra deployment
ohh/gpt-5.6-luna # pin GPT to the Luna deploymentUse ohh/gpt-5.6 for automatic burst routing across Sol → Terra → Luna. Add -sol/-terra/-luna only to pin a route. Fable is available only through ohh/claude-fable-5 and never falls back to GPT or Opus.
Purchases and admin grants create an entitlement in exactly one wallet scope. Grant Plan uses the same rules as checkout; it does not create a global balance.
| Plan / grant | Models unlocked | Eligible balance |
|---|---|---|
| GPT + Opus | ohh/gpt-5.6*, ohh/claude-opus-5, ohh/claude-opus-4.8 | GPT + Opus lots (all) |
| GPT Only | ohh/gpt-5.6* | GPT Only lots first; then eligible GPT + Opus lots |
| Fable Only | ohh/claude-fable-5 | Fable lots only (fable) |
Token allowances: GPT + Opus and Fable Only offer 30M / 90M / 150M / 300M / 450M. GPT Only receives its separately advertised allowance. Every token pack is stored as an independent 30-day lot; Unlimited extends only the selected scope.
Every request needs your API key (sk-mvx-…). Both header styles are accepted on every endpoint — send whichever your SDK produces:
# Anthropic style
x-api-key: sk-mvx-your-key
anthropic-version: 2023-06-01
# OpenAI / Bearer style
Authorization: Bearer sk-mvx-your-keyThe gateway is a transparent proxy: send the native body of whichever API you call. Common fields:
| Field | API | Description |
|---|---|---|
model | both | One of the model IDs above. Required. |
messages | both | Conversation array (role + content). Required. |
max_tokens | Anthropic | Max output tokens. Required on /v1/messages. |
max_completion_tokens | OpenAI | Max output tokens (GPT). Optional. |
stream | both | true = SSE stream. Default false. |
system | Anthropic | System prompt (string or blocks). |
temperature / top_p | both | Sampling. Ignored for Opus (thinking models strip it). |
tools | both | Function/tool definitions — see Tool calling. |
reasoning_effort | OpenAI | GPT thinking depth: none·low·medium·high·xhigh. |
output_config.effort | Anthropic | Opus thinking depth: low·medium·high·xhigh·max. |
You get back the native shape of the endpoint you called. The model field is our public slug (never the upstream deployment). Non-stream Anthropic example:
{
"id": "msg_01…",
"type": "message",
"role": "assistant",
"model": "ohh/claude-opus-5",
"content": [{ "type": "text", "text": "Hello!" }],
"stop_reason": "end_turn",
"usage": { "input_tokens": 12, "output_tokens": 6 }
}input_tokens + cache_creation_input_tokens + cache_read_input_tokens. GPT follows OpenAI semantics, where prompt_tokens already includes cached input. Upstream components are retained for auditing.Set the stream field to true. You receive Server-Sent Events. Anthropic emits message_start → content_block_delta … → message_delta → message_stop; OpenAI emits chat.completion.chunk objects ending with [DONE]. The gateway translates transparently, so an Anthropic client streaming GPT still gets Anthropic-shaped events.
curl -N https://ohhmyagent.com/v1/messages \
-H "x-api-key: sk-mvx-your-key" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{"model":"ohh/claude-opus-5","max_tokens":256,"stream":true,
"messages":[{"role":"user","content":"Stream a haiku"}]}'The /v1/responses endpoint speaks the OpenAI Responses API (used by OpenAI Codex). Send an input (string or item array) plus optional instructions; set reasoning.effort for thinking depth. Both Opus and GPT model IDs work.
curl https://ohhmyagent.com/v1/responses \
-H "authorization: Bearer sk-mvx-your-key" \
-H "content-type: application/json" \
-d '{"model":"ohh/gpt-5.6",
"input":"Write a haiku about the sea",
"reasoning":{"effort":"medium"}}'Regular response (non-stream) — one response object; the text is in output[].content[].text (also mirrored in output_text):
{
"id": "resp_…",
"object": "response",
"status": "completed",
"model": "ohh/gpt-5.6",
"output": [
{ "type": "message", "role": "assistant",
"content": [{ "type": "output_text", "text": "Waves…" }] }
],
"output_text": "Waves…",
"usage": { "input_tokens": 9, "output_tokens": 17, "total_tokens": 26 }
}Streaming version — add "stream": true. You receive Responses SSE events in this order:
event: response.created
event: response.in_progress
event: response.output_item.added
event: response.content_part.added
event: response.output_text.delta # ← repeated, the tokens
event: response.output_text.done
event: response.content_part.done
event: response.output_item.done
event: response.completed # ← final, carries usageresponse.function_call_arguments.delta/.done between item events. GPT 5.6 also supports the Responses built-in web_search tool and emits response.web_search_call.* events; web_search_preview is accepted as a compatibility alias. Other unnamed built-in tools are not advertised as supported. Base URL for Codex is https://ohhmyagent.com/v1 with wire_api = responses — see the Codex setup under CLI Tools.Full function calling on both endpoints, both models. The gateway maps tool_use ↔ tool_calls automatically. Anthropic form:
{
"model": "ohh/claude-opus-5",
"max_tokens": 1024,
"tools": [{
"name": "get_weather",
"description": "Get current weather for a city",
"input_schema": {
"type": "object",
"properties": { "city": { "type": "string" } },
"required": ["city"]
}
}],
"messages": [{ "role": "user", "content": "Weather in Jakarta?" }]
}OpenAI form uses a tools array of type:function objects and returns tool_calls. Send the tool result back as a tool_result (Anthropic) or a role:tool (OpenAI) message to continue.
For image requests, use an image-capable model. Anthropic uses a base64 image block; OpenAI uses image_url (data URL or https URL).
{
"model": "ohh/claude-opus-5",
"max_tokens": 512,
"messages": [{ "role": "user", "content": [
{ "type": "image", "source": {
"type": "base64", "media_type": "image/png", "data": "<BASE64>" } },
{ "type": "text", "text": "What is in this image?" }
]}]
}Control how hard the model thinks. Higher = deeper reasoning + more tokens.
| Model | Field | Valid values |
|---|---|---|
| Opus 5 / 4.8 | output_config.effort | low · medium · high · xhigh · max |
| GPT 5.6 | reasoning_effort | none · low · medium · high · xhigh |
{ "model":"ohh/claude-opus-5", "max_tokens":1024,
"output_config": { "effort": "max" },
"messages":[{"role":"user","content":"Prove there are infinitely many primes."}] }Prompt caching runs automatically upstream and speeds up repeated context. Billing is full-uncached and uniform across every model: wallet input equals the total prompt tokens the upstream reports — fresh input plus any cache creation and cache reads — with no cache discount. For Opus we automatically place cache breakpoints on stable prompt sections (system prompt, tools, older turns) and for GPT Azure caching is automatic; caching improves latency and upstream cost, but the wallet is charged on the full prompt_tokens the model processed. Keep the deployment, system prompt, tool order and older history stable for the best cache hit.
| Code | Meaning | Fix |
|---|---|---|
400 | Bad request / invalid JSON | Check body & required fields. |
401 | Invalid or missing key | Verify key; rotate on dashboard. |
402 | Insufficient balance | Top up your token wallet. |
403 | Account suspended / banned | Open a support ticket. |
404 | Wrong base URL | Claude Code = root; SDKs = /v1. Never /v1/v1. |
413 | Body exceeds the 16 MiB authenticated request safety boundary | Reduce unusually large binary attachments; ordinary long agent context is accepted. |
429 | ChatRateLimited / Rate limit exceeded | The service automatically waits and retries for up to 95 seconds. If it still appears, reduce concurrency and avoid parallel bursts. |
502/503 | Upstream hiccup | Auto-retried; try again shortly. |
529 | Upstream overloaded | Auto-retried with backoff. |
Scoped billing. Fable uses only Fable lots. GPT uses GPT Only lots first, then eligible GPT + Opus lots. Opus uses only GPT + Opus lots. Wallets never cross-spend outside these rules.
Rate limits. 50 requests/minute per account (all keys share it) + 200 req/min per IP. Authenticated request body max 16 MiB. ChatRateLimited: Rate limit exceeded means your request rate exceeded the RPM controlled by our service; it is not an upstream incident.
Retries. For 429, the service honors Retry-After, waits with jitter, and retries automatically for up to 95 seconds. Transient 502/503/529 use exponential backoff.
Expiry. Token packs last 30 days as independent lots, consumed nearest-expiry first. Unlimited stacks an access window instead of tokens.
Pick your tool. Anthropic-native tools use the root URL; OpenAI-compatible tools use /v1.
CLI — root URL only; Claude Code appends /v1/messages.
export ANTHROPIC_BASE_URL="https://ohhmyagent.com"
export ANTHROPIC_AUTH_TOKEN="sk-mvx-your-key"
export ANTHROPIC_DEFAULT_OPUS_MODEL="ohh/claude-opus-5"
claude --model opusVS Code / Cursor extension — Windows, macOS, Linux
Ctrl+Shift+P) → Preferences: Open User Settings (JSON).claudeCode.environmentVariables inside itself.{
"claudeCode.disableLoginPrompt": true,
"claudeCode.environmentVariables": [
{ "name": "ANTHROPIC_BASE_URL", "value": "https://ohhmyagent.com" },
{ "name": "ANTHROPIC_AUTH_TOKEN", "value": "«redacted:sk-…»" },
{ "name": "ANTHROPIC_MODEL", "value": "ohh/claude-opus-5" },
{ "name": "ANTHROPIC_DEFAULT_OPUS_MODEL", "value": "ohh/claude-opus-5" },
{ "name": "ANTHROPIC_DEFAULT_SONNET_MODEL", "value": "ohh/claude-opus-5" },
{ "name": "ANTHROPIC_DEFAULT_HAIKU_MODEL", "value": "ohh/claude-opus-4.8" }
]
}/v1). Claude Code appends /v1/messages; adding /v1 here creates a 404 at /v1/v1/messages. For GPT set DEFAULT_* values to ohh/gpt-5.6.npm i -g @openai/codexexport OHH_API_KEY="sk-mvx-your-key"~/.codex/config.toml:# ~/.codex/config.toml
model = "ohh/gpt-5.6"
model_provider = "ohh"
[model_providers.ohh]
name = "OhhMyAgent"
base_url = "https://ohhmyagent.com/v1"
env_key = "OHH_API_KEY"
wire_api = "responses"codex --model ohh/gpt-5.6 "Refactor this module"
codex --model ohh/claude-opus-5 "Review this diff"Windows / VS Code integrated terminal
# %USERPROFILE%\.codex\config.toml
model = "ohh/claude-opus-5"
model_provider = "ohh"
[model_providers.ohh]
name = "OhhMyAgent"
base_url = "https://ohhmyagent.com/v1"
env_key = "OHH_API_KEY"
wire_api = "responses"
# PowerShell (current terminal)
$env:OHH_API_KEY = "«redacted:sk-…»"
# Persist for new terminals (reopen VS Code after this)
[Environment]::SetEnvironmentVariable("OHH_API_KEY", "«redacted:sk-…»", "User")wire_api = responses). On Windows, the integrated VS Code terminal uses the same %USERPROFILE%\.codex\config.toml and user environment variable. Do not use https://ohhmyagent.com here; OpenAI-compatible Codex requires https://ohhmyagent.com/v1.https://ohhmyagent.com/v1sk-mvx-your-keyohh/gpt-5.6 or ohh/claude-opus-5, then click Verify.https://ohhmyagent.com/v1sk-mvx-your-keyohh/claude-opus-5 / ohh/gpt-5.6.https://ohhmyagent.com/v1 · API Key: sk-mvx-your-key.ohh/gpt-5.6 or ohh/claude-opus-5 and enable it in the model list.https://ohhmyagent.com/v1 · API Key: sk-mvx-your-key.ohh/claude-opus-5, ohh/gpt-5.6.attachment: true and modalities.input: ["text", "image"]. The model is vision-capable; this tells Kilo to expose the attachment UI."claude-opus-4.8": {
"name": "Claude Opus 4.8",
"attachment": true,
"modalities": { "input": ["text", "image"], "output": ["text"] }
}https://ohhmyagent.com/v1 — Kilo calls /v1/messages. Same model IDs work.{
"$schema": "https://opencode.ai/config.json",
"provider": {
"ohh": {
"npm": "@ai-sdk/openai-compatible",
"name": "OhhMyAgent",
"options": { "baseURL": "https://ohhmyagent.com/v1", "apiKey": "{env:OHH_API_KEY}" },
"models": {
"claude-opus-5": { "name": "Claude Opus 5" },
"gpt-5.6": { "name": "GPT 5.6 · Auto Burst" }
}
}
}
}export OHH_API_KEY="sk-mvx-your-key"
opencode run --model "ohh/claude-opus-5" "Review this code"
opencode run --model "ohh/gpt-5.6" "Review this code"export OPENAI_API_BASE="https://ohhmyagent.com/v1"
export OPENAI_API_KEY="sk-mvx-your-key"
aider --model openai/ohh/gpt-5.6
aider --model openai/ohh/claude-opus-5openai/ so Aider routes it through the OpenAI-compatible driver to our /v1 base.models:
- name: Opus 5
provider: openai
model: ohh/claude-opus-5
apiBase: https://ohhmyagent.com/v1
apiKey: sk-mvx-your-key
- name: GPT 5.6
provider: openai
model: ohh/gpt-5.6
apiBase: https://ohhmyagent.com/v1
apiKey: sk-mvx-your-keyohh · Base URL: https://ohhmyagent.com/v1 · API Key: sk-mvx-your-key.claude-opus-5, claude-opus-4.8, gpt-5.6. 9Router exposes them as ohh/claude-opus-5 etc./v1 base — 9Router will call /v1/messages.# 9router provider (conceptual)
provider: ohh
type: openai_compatible
base_url: https://ohhmyagent.com/v1
api_key: sk-mvx-your-key
models: [claude-opus-5, claude-opus-4.8, gpt-5.6]9Router can transparently intercept a tool that hard-codes api.anthropic.com / api.openai.com by installing its MITM CA and rewriting the upstream. Point the intercepted upstream to us:
api.anthropic.com → https://ohhmyagent.com (root, Anthropic) and api.openai.com/v1 → https://ohhmyagent.com/v1.x-api-key: sk-mvx-your-key (or Bearer) on the rewritten request.ohh/… ID if the tool sends an upstream-only name.# litellm config.yaml
model_list:
- model_name: claude-opus-5
litellm_params:
model: openai/ohh/claude-opus-5
api_base: https://ohhmyagent.com/v1
api_key: sk-mvx-your-key
- model_name: gpt-5.6
litellm_params:
model: openai/ohh/gpt-5.6
api_base: https://ohhmyagent.com/v1
api_key: sk-mvx-your-key# Python · Anthropic SDK
from anthropic import Anthropic
client = Anthropic(api_key="sk-mvx-your-key", base_url="https://ohhmyagent.com")
msg = client.messages.create(
model="ohh/claude-opus-5", max_tokens=512,
messages=[{"role":"user","content":"Hello"}])
print(msg.content[0].text)// Node · OpenAI SDK
import OpenAI from "openai";
const client = new OpenAI({ apiKey: "sk-mvx-your-key", baseURL: "https://ohhmyagent.com/v1" });
const r = await client.chat.completions.create({
model: "ohh/gpt-5.6",
messages: [{ role: "user", content: "Hello" }],
});
console.log(r.choices[0].message.content);curl https://ohhmyagent.com/v1/messages \
-H "x-api-key: sk-mvx-your-key" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{"model":"ohh/claude-opus-5","max_tokens":1024,
"messages":[{"role":"user","content":"Hello!"}]}'curl https://ohhmyagent.com/v1/chat/completions \
-H "authorization: Bearer sk-mvx-your-key" \
-H "content-type: application/json" \
-d '{"model":"ohh/gpt-5.6",
"messages":[{"role":"user","content":"Hello!"}]}'Which prefix — ohh/ or oma/?
Use ohh/. Bare canonical IDs such as claude-opus-5 / gpt-5.6 also resolve. Legacy shortened Opus IDs remain compatible, but are no longer advertised. There is no oma/.
Is GPT 5.6 OpenAI-only?
No — it works on both endpoints; we translate transparently. Pick the endpoint your SDK expects.
One key for all models?
One key can address every model ID, but the request is authorized and billed only from a wallet eligible for that model. Fable, GPT Only, and GPT + Opus balances remain separate.
Sol / Terra / Luna?
Three GPT 5.6 routes, same flat rate. ohh/gpt-5.6 auto-bursts; pin with -sol/-terra/-luna only if you want a fixed route.
Is my content stored?
No. We store only usage metadata (token counts, time, model). Conversation content is forwarded and not retained.
401 — check the key is correct & active; rotate on dashboard.
404 — wrong base URL. Claude Code = root (no /v1); SDKs = /v1. Never /v1/v1.
402 — top up your token wallet.
429 / ChatRateLimited — the request rate exceeded the service RPM limit, not an upstream issue. The service automatically waits and retries for up to 95 seconds. If it still appears, reduce concurrency, queue requests, and avoid parallel bursts.
529 — upstream busy; auto-retried — try again shortly.
wrong domain — always use ohhmyagent.com.