AI Gatewayevery model, one key, one bill.

An OpenAI-compatible endpoint for the models a Space allows, called with a Space key and billed to the Space wallet.

The AI Gateway lets any OpenAI-compatible client (the OpenAI SDKs, LangChain, Cursor, your own code) use Wakato as its model provider. You call it with a Space API key, the models are the ones the Space allows, and every call is charged to the Space wallet and shows up in its usage.

OpenAI base URLhttps://api.wakato.io/functions/v1/gateway-endpoint/v1
Anthropic base URLhttps://api.wakato.io/functions/v1/gateway-endpoint
AuthAuthorization: Bearer wks_live_… or x-api-key: wks_live_…
Scopeai:run ("Space Gateway" in the key dialog)

Make a key in Space → Settings → API Keys with the Space Gateway ticked. See Keys and scopes.

Chat completions

import OpenAI from "openai";

const ai = new OpenAI({
  baseURL: "https://api.wakato.io/functions/v1/gateway-endpoint/v1",
  apiKey: process.env.WAKATO_SPACE_KEY, // wks_live_…
});

const res = await ai.chat.completions.create({
  model: "anthropic/claude-sonnet-4.6",
  messages: [{ role: "user", content: "Write 3 ad headlines for a linen apron" }],
});

console.log(res.choices[0].message.content);
import os
from openai import OpenAI

ai = OpenAI(
    base_url="https://api.wakato.io/functions/v1/gateway-endpoint/v1",
    api_key=os.environ["WAKATO_SPACE_KEY"],
)

res = ai.chat.completions.create(
    model="anthropic/claude-sonnet-4.6",
    messages=[{"role": "user", "content": "Write 3 ad headlines for a linen apron"}],
)
print(res.choices[0].message.content)
curl https://api.wakato.io/functions/v1/gateway-endpoint/v1/chat/completions \
  -H "Authorization: Bearer $WAKATO_SPACE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "anthropic/claude-sonnet-4.6",
    "messages": [{ "role": "user", "content": "Write 3 ad headlines for a linen apron" }]
  }'

temperature, max_tokens (or max_completion_tokens), tools and tool_choice are passed through. Model names are vendor/model; take them from the model list below rather than guessing.

List models

curl https://api.wakato.io/functions/v1/gateway-endpoint/v1/models \
  -H "Authorization: Bearer $WAKATO_SPACE_KEY"

The answer is an OpenAI-style list. Each entry's id is the string to send as model, plus a few extras most clients ignore: display_name, category (text, image, video, audio, embedding…), context_window, max_output_tokens, supports_tools, supports_vision. It lists only what this key may call in this Space.

Which models a Space may use

  • A Space with no model list allows every active Wakato model.
  • Once the owner or an admin adds models to the Space's list, only those are allowed. A call to another model gets 403 with a sentence saying it is not on in this Space.
  • A key can be narrowed further to selected models in its own settings. A model outside the key's list is refused with 403, naming the allowed ones.

Streaming

stream: true is accepted and answers with standard server-sent events, so streaming clients work unchanged. The gateway completes the call first and then replays it as a stream: the text arrives at the end, not token by token. Plan timeouts accordingly; a single call may take up to about two minutes.

const stream = await ai.chat.completions.create({
  model: "anthropic/claude-sonnet-4.6",
  messages: [{ role: "user", content: "Summarise this week's orders" }],
  stream: true,
});
for await (const chunk of stream) process.stdout.write(chunk.choices[0]?.delta?.content ?? "");

Other routes

All under the same base, same key and scope:

MethodPathWhat it does
POST/v1/embeddingsOpenAI-compatible embeddings
POST/v1/images/generationsImage generation
POST/v1/audio/speechText to speech; answers JSON with the audio URL
POST/v1/audio/transcriptionsSpeech to text: a multipart file, or JSON audio_url / audio
POST/v1/evaluationsJudging: typed questions about a text, answered with probabilities
POST/v1/generationsVideo, music and other media: { model, input }
GET/v1/generations/:job_idPoll a media job
POST/v1/messagesAnthropic-compatible messages (streaming supported)
POST/v1/messages/count_tokensA rough token count

Media generation is asynchronous by default: /v1/generations answers 202 with an id and a poll path. Send "wait": true only for fast models.

Clients built on the Anthropic SDK point their base URL at https://api.wakato.io/functions/v1/gateway-endpoint and use the same key.

Billing and spend limits

Every call is charged to the Space wallet, tagged with the key, so the Space's usage shows what each key cost. Calls stop when money runs out:

  • The wallet cannot cover the call: 402, code INSUFFICIENT_BALANCE.
  • A spending cap set on the Space was reached: 402, code SPACE_BUDGET_EXCEEDED.
  • When the key belongs to one of the Space's agents, that agent's own daily, weekly or monthly cap also applies: 402, code AGENT_SPEND_CAP.

A 402 always means the Space's money or limits, never a provider problem.

Errors

Errors use OpenAI's envelope (Anthropic's on /v1/messages):

{
  "error": {
    "message": "Wakato's model service is temporarily unavailable. Please try again in a few minutes.",
    "type": "api_error",
    "code": "PROVIDER_DOWN"
  }
}
StatusCodeMeaningWhat to do
400REQUEST_TOO_LONGToo long for the modelShorten the input
400PROVIDER_REJECTEDThe model could not process the requestCheck the input
401Missing, wrong, expired or revoked keyCheck the key
402INSUFFICIENT_BALANCE, SPACE_BUDGET_EXCEEDED, AGENT_SPEND_CAPMoney or a capTop up or raise the cap
403No ai:run scope, or the model is not allowedEdit the key or the Space's models
404MODEL_NOT_FOUNDUnknown modelUse an id from /v1/models
429PROVIDER_BUSYThe model is busyRetry with backoff
503PROVIDER_DOWNTemporarily unavailableRetry in a few minutes

Messages are Wakato's own sentences and safe to show to a person. Retry 429 and 503; do not retry 400, 402 or 403 without changing something.

From an app or an agent

Inside a Space App, use wakato.gateway.llm() and friends instead; see the App SDK. Agents connected over MCP reach the same models through the AI tools.

On this page