API Reference
ZetaAPI endpoints, authentication, compatible formats, error codes and rate limits. OpenAI and Anthropic dual-format passthrough — no SDK changes.
Updated 2026-04-17
Base URL
https://api.staging.cosmos-router.com
- OpenAI-compatible endpoints live under
/v1/* - The Anthropic-compatible endpoint is
/v1/messages - Both formats share the same API key
Authentication
Every request must carry Authorization: Bearer sk-xxxxx:
curl https://api.staging.cosmos-router.com/v1/chat/completions \
-H "Authorization: Bearer sk-xxxxx" \
-H "Content-Type: application/json" \
-d '{"model": "gpt-4o", "messages": [{"role": "user", "content": "hi"}]}'
The Anthropic format also accepts x-api-key (same as official):
curl https://api.staging.cosmos-router.com/v1/messages \
-H "x-api-key: sk-xxxxx" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{"model": "claude-sonnet-4-6", "max_tokens": 1024, "messages": [{"role": "user", "content": "hi"}]}'
Endpoint overview
| Endpoint | Protocol | Notes |
|---|---|---|
POST /v1/chat/completions | OpenAI | Chat completion, SSE streaming supported |
POST /v1/completions | OpenAI | Legacy text completion (older models) |
POST /v1/embeddings | OpenAI | Vector embeddings |
POST /v1/messages | Anthropic | Claude native format, prompt cache supported |
GET /v1/models | OpenAI | Models available to the current account |
GET /api/v1/key/quota | ZetaAPI | Remaining balance and usability of this key |
Supported model families
- Claude:
claude-opus-4-8,claude-opus-4-7,claude-sonnet-4-6 - GPT:
gpt-5.5,gpt-5.3-chat,gpt-5.3-codex,gpt-5.2-codex,gpt-4o,o3,o4-mini - Gemini:
gemini-3-pro-preview,gemini-2.5-pro,gemini-3-flash-preview,gemini-flash-latest - DeepSeek / Qwen / Kimi / MiniMax and other open-source and Chinese models
Models and prices are updated with each deploy; the lists above are representative only. The full model list and current price multipliers are authoritative on the pricing page.
Streaming responses (SSE)
Set "stream": true in the request:
stream = client.chat.completions.create(
model="claude-sonnet-4-6",
messages=[{"role": "user", "content": "Write a quicksort in Python"}],
stream=True,
)
for chunk in stream:
print(chunk.choices[0].delta.content or "", end="", flush=True)
SSE returns the data: {...}\n\n format and ends with data: [DONE] — exactly as in the official OpenAI / Anthropic APIs.
Prompt Cache
OpenAI models
Cached automatically, no extra parameters. Repeated prefixes are billed at the cache-hit rate (50% of the input price or lower, depending on the model).
Claude (Anthropic format)
Mark it explicitly on a system or messages block:
{
"model": "claude-sonnet-4-6",
"max_tokens": 1024,
"system": [
{
"type": "text",
"text": "Long system prompt...",
"cache_control": { "type": "ephemeral" }
}
],
"messages": [...]
}
The cache-hit rate is 10% of the input price, same as official. See Prompt Cache cost benchmark.
Checking your balance
The key itself is enough to query how much it can still spend and whether it currently works:
curl https://api.staging.cosmos-router.com/api/v1/key/quota \
-H "Authorization: Bearer sk-xxxxx"
{
"success": true,
"data": {
"available_usd": 12.5,
"available_quota": 6250000,
"usable": true,
"blockers": [],
"message": "可用。",
"account_balance_usd": 12.5,
"key": {
"name": "production",
"unlimited_quota": false,
"remaining_usd": 50.0,
"used_usd": 3.2,
"status": "enabled",
"expires_at": null
}
}
}
Which field to read
Use available_usd for both decisions and display. It is what this key can actually spend: the smaller of your account balance and the key’s own spending cap.
| Field | Meaning |
|---|---|
available_usd | Amount actually spendable (account balance and key allowance, whichever is lower) |
available_quota | The same figure as an integer (500000 = $1) — use it for exact comparisons, free of floating-point error |
account_balance_usd | Account wallet balance, shared by all keys |
key.remaining_usd | This key’s own remaining allowance; null when the key has no cap |
message is a human-readable summary in Chinese, consistent with the rest of the platform’s API messages. For programmatic handling, branch on usable and blockers, never on message.
In the example above the account holds $12.5 while the key’s cap still allows $50 — $12.5 is what can actually be spent. Reading key.remaining_usd alone would overstate it.
When the key is not usable
When usable is false, blockers lists every reason, not just the first — so you don’t fix one and still get rejected:
| blocker | Meaning | What to do |
|---|---|---|
insufficient_account_balance | Account balance is depleted | Top up in the console |
key_quota_exhausted | This key’s own allowance is used up | Raise the key’s limit in the console |
key_expired | The key has expired | Extend it or create a new key |
key_disabled | The key is disabled | Re-enable it, or use another key |
account_suspended | The account is suspended | Contact support |
Exhausted, expired and disabled keys can still call this endpoint — the moment you most need to know why a key stopped working is precisely when it no longer works. Only a non-existent or deleted key returns 401.
Rate limit: 120 requests/minute per key. Poll no more often than every 30 seconds.
⚠️ Do not use
/v1/dashboard/billing/subscriptionto check your balance. That legacy OpenAI-compatible endpoint reportshard_limit_usdas the total granted amount rather than what remains, returns a fixed placeholder for keys without a cap, and does not reflect your account balance at all. Use/api/v1/key/quotaabove.
Error codes
| HTTP | Code | Meaning | Suggestion |
|---|---|---|---|
| 400 | invalid_request_error | Bad parameters (missing field, wrong format, bad model name) | Check the request body |
| 401 | authentication_error | Key invalid or revoked | Regenerate the key |
| 402 | insufficient_quota | Insufficient balance | Top up in the console; use GET /api/v1/key/quota to query the remaining amount programmatically |
| 403 | permission_error | The key can’t access this model | Check the key’s permissions |
| 404 | not_found_error | Model name misspelled | See /v1/models |
| 429 | rate_limit_error | Rate limit hit | Retry with exponential backoff |
| 500 | internal_error | Platform internal error | Counted toward incident stats; compensation claimable under the published rules |
| 502 / 503 | upstream_error | Upstream failure, switching channels | Client may retry immediately |
| 504 | timeout_error | Upstream timeout | Client may retry immediately |
The error body matches OpenAI’s format:
{
"error": {
"type": "invalid_request_error",
"message": "model 'gpt-4-vision' not found",
"code": null
}
}
Rate limits
- Default: 600 RPM / 300k TPM (per key, not per account)
- Enterprise or heavy users can request higher limits in the console
- On limit, returns
429+ aRetry-Afterheader (seconds)
Automatic failover
When an upstream channel’s availability degrades, the platform automatically shifts traffic to a backup channel — transparent to the client in the vast majority of cases.
SLA compensation is computed per calendar month + SKU group; compensation is currently claim-based (manually reviewed); how to file and the tiers: Service compensation claims (design background: Refund rules as product).
SDK support
- Python: the official
openaiandanthropicSDKs work directly — just changebase_url - Node.js:
openai/@anthropic-ai/sdk, same as above - Go / Rust / Java: any OpenAI-compatible library that supports a custom base URL