API Gateway

https://gateway.agentsky.dev serves the Anthropic Messages API and the OpenAI Chat Completions, Responses and Embeddings APIs behind one AgentSky key, plus a run API for non-model endpoints (search, maps, email, speech, transcription, SEO data, image generation). Every response carries its price.

Base URLs

ClientBase URL
Anthropic SDK, Claude Code (ANTHROPIC_BASE_URL)https://gateway.agentsky.dev
OpenAI SDK, Codex (OPENAI_BASE_URL)https://gateway.agentsky.dev/v1

Authenticate with an AgentSky API key (ast_…, created under Settings → API keys) as x-api-key or Authorization: Bearer. Model calls and runs need the write scope; catalog and account reads need read.

Routes

MethodPathNotes
POST/v1/messagesAnthropic Messages API, streamed or not
POST/v1/messages/count_tokensforwarded unmetered
POST/v1/chat/completions, /v1/responses, /v1/embeddingsOpenAI APIs
GET/v1/models, /v1/models/{vendor}/{model}public catalog with per-token prices and providers
GET/v1/endpoints, /v1/providerspublic run catalog and provider list
POST/v1/run{provider, endpoint, input} → run object
GET/v1/runs/{runId}a run from the last hour
GET/v1/creditsbalance and total used
GET/v1/generation?id=one call's record: tokens, cost, provider

Model ids

Use the catalog id (anthropic/claude-sonnet-5, qwen/qwen-max), an accepted alias (glm/glm-5.2, kimi/k3), or the bare id (claude-sonnet-5). A vendor prefix that matches nothing is a 404.

Provider routing and failover

A model may be served by several providers. The gateway tries them in its default order and fails over to the next allowed provider when one is unreachable, times out before the first byte, or answers 408, 429, 401, 403 or 5xx; any other reply is returned as-is, and nothing is retried once response bytes have been sent.

  • Request header x-agentsky-provider: bedrock,anthropic — the allowed providers, in order (works on every wire and in Claude Code via ANTHROPIC_CUSTOM_HEADERS).
  • Body provider: { "order": [...], "only": [...], "sort": "cost" } (OpenRouter's field) or providerOptions.gateway (Vercel's). Accepted on both wires, stripped before forwarding.
  • Response header x-agentsky-provider names the provider that served the call; x-agentsky-provider-attempts lists skipped providers with their status. OpenAI-wire bodies also carry a top-level provider field.
  • A restriction no provider can meet is 400 provider_not_available naming the model's providers.

Cost in the response

Model calls: usage.cost (USD) on the final usage object (the usage-only last chunk of an OpenAI stream, response.completed on the Responses API, message_delta on the Anthropic wire, or the JSON body). Runs: price.amount plus billing.calculatedCost, billing.actualCost and billing.reportedCost. Prices are per token or per unit as listed in the catalog and may differ per provider; GET /v1/generation?id=<upstream id or call id> returns the record once it has landed.

Runs

text
POST /v1/run
{ "provider": "exa", "endpoint": "search", "input": { "query": "agent gateways", "numResults": 5 } }

200 { "runId": "run_…", "status": "COMPLETED", "provider": "exa", "endpoint": "search",
      "output": { … vendor response … },
      "price": { "type": "PER_CALL", "amount": { "value": 0.014, "currency": "USD" } },
      "billing": { "calculatedCost": { "value": 0.007, … }, "actualCost": { … }, "reportedCost": { "value": null, … } },
      "providerResponse": { "httpStatus": 200 }, … }

Every endpoint is synchronous. Binary outputs (audio, images) come back inline as { "data": "<base64>", "mediaType": "audio/mpeg", "bytes": n }. A failed run has status: FAILED or TIMED_OUT, error: { code, message } with the vendor's message, and is not charged.

Errors

Errors take the shape of the wire: Anthropic { "type": "error", "error": { "type", "message" } }, OpenAI { "error": { "message", "type", "param", "code" } }, and { "error": { "code", "message" } } on run and account routes. Codes you will see: model_not_found, endpoint_not_found, provider_not_available, pricing_unavailable (503, the SKU has no rate yet), upstream_unavailable, insufficient_credits / insufficient_quota (spend gate), rate_limited.

Limits

Request bodies up to 10 MB on the model wires and 1 MB on most run endpoints (35 MB for audio uploads). Media outputs up to 20 MB inline. Per-key rate limits apply.