Docs

API Reference

Call the AI Gateway with the same format as OpenAI — endpoints, parameters, errors and headers on one page

Your first request in 3 steps

If your app already calls OpenAI, two lines is the whole migration.

  1. 1

    Create an API key

    In the dashboard go to API Keys and create a key. Keys start with sk- and are shown once, at creation.

  2. 2

    Point the base URL at Wisporta

    Keep your existing client. Set the base URL to https://api.wisporta.com/v1 and use your Wisporta key.

  3. 3

    Pick a model

    Name it as provider/model, for example openai/gpt-5.5, or use a short alias such as claude-sonnet.

first request
curl https://api.wisporta.com/v1/chat/completions \
  -H "Authorization: Bearer sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-5.5",
    "messages": [
      { "role": "user", "content": "Hello!" }
    ]
  }'

See what you can call

GET /v1/models is public — no API key needed. It returns every model open for use along with its price per 1M tokens in pts.

list models
curl https://api.wisporta.com/v1/models

# → { "object": "list", "data": [ { "id": "openai/gpt-5.5", … } ] }
The response is cacheable for 300 seconds and carries an ETag — send it back as If-None-Match and a match returns 304 Not Modified. Add an Authorization header and the response becomes private, no-store.

Two ways to name a model

Full idopenai/gpt-5.5

provider/model — states exactly which provider you want. Use this in production.

Aliasclaude-sonnetanthropic/claude-sonnet-5

The short form without a slash. Convenient while experimenting, but what it points at can change as the catalogue moves.

A misspelled name returns 400 model_not_found with the closest matches in a suggestions field.

Providers currently enabled

This list is pulled live from /v1/models every hour.

Anthropic4 models
anthropic/claude-fable-5anthropic/claude-opus-4-8
DeepSeek2 models
deepseek/deepseek-v4-prodeepseek/deepseek-v4-flash
Google4 models
google/gemini-3.1-progoogle/gemini-3.5-flash
OpenAI5 models
openai/gpt-5.5openai/gpt-5.4
See every model and its price on the pricing page

Request body for /v1/chat/completions

The same shape as OpenAI Chat Completions, plus one Wisporta parameter: strategy.

ParameterTypeDefaultMeaning
modelrequiredstringFull model id or alias
messagesrequiredarrayThe conversation. Each entry has a role and content — at least one is required.
streambooleanfalsetrue streams tokens back over SSE. Omitting it means false.
strategy"cost" | "latency" | "fallback""cost"How to pick a target when a model has fallbacks — cost is cheapest, latency is fastest, fallback walks the list in order.
max_tokensnumberCaps how many tokens the model may produce
temperaturenumber (0–2)Creativity from 0 to 2. Some models reject this parameter; the gateway strips it for them, so you do not have to special-case it.

Only system, user, assistant are accepted as a role — the tool role is not supported yet.

Receive tokens as they are produced

Set "stream": true and you get text/event-stream in the chat.completion.chunk format OpenAI uses, closing with data: [DONE].

streaming
curl https://api.wisporta.com/v1/chat/completions \
  -H "Authorization: Bearer sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "anthropic/claude-sonnet-5",
    "messages": [{ "role": "user", "content": "Tell me a joke" }],
    "stream": true
  }'

data: {"id":"chatcmpl-…","object":"chat.completion.chunk","choices":[{"delta":{"role":"assistant","content":""},"finish_reason":null}]}
data: {"id":"chatcmpl-…","object":"chat.completion.chunk","choices":[{"delta":{"content":"Why"},"finish_reason":null}]}
data: {"id":"chatcmpl-…","object":"chat.completion.chunk","choices":[{"delta":{},"finish_reason":"stop"}]}
data: [DONE]
If something fails after the stream has started, the gateway emits a frame carrying error.type = stream_error and then closes with [DONE]. The HTTP status stays 200, because headers went out before the failure — inspect the frames, not just the status.

Headers worth reading

Your point balance and the state of the model ride along on every response, so there is no second endpoint to poll.

HeaderMeaning
X-Credit-BalancePoints the organization held when the request started
X-Credit-Expires-AtWhen those points expire (ISO 8601)
X-Credit-Days-LeftDays left before the points expire
X-Model-Deprecatedtrue when the model you called is being retired — still callable, but plan the move
X-Model-Replaced-ByThe model to move to
WarningA human-readable 299 notice for your logs

Error handling

The gateway returns two error envelopes. A client that parses only one of them breaks on the other.

flat

error is a plain string. Used for auth, points and malformed requests.

nested

error is an object. Used for model problems and upstream provider failures.

error envelopes
// flat — auth, points, malformed request
{
  "error": "insufficient_credit",
  "message": "Insufficient points. Please add points to continue.",
  "balance": 0,
  "currency": "THB"
}

// nested — model and upstream provider problems
{
  "error": {
    "type": "invalid_request_error",
    "code": "model_not_found",
    "message": "…",
    "param": "model",
    "suggestions": ["openai/gpt-5.5"]
  }
}
Inside the nested object, code is a string such as model_not_found — never the numeric HTTP status.
codeHTTPEnvelopeMeaning
invalid_request400flatBody is not JSON, or failed validation — see the details field
model_not_found400nestedNo such model — check the suggestions field
unauthorized401flatAPI key is wrong, revoked, or missing
insufficient_credit402flatNot enough points left
credit_expired402flatPoints have expired — add more to continue
account_disabled403flatThe user account is suspended
organization_disabled403flatThe organization is suspended
too_many_requests429flatThis organization already has 10 requests in flight — let one finish and retry
internal_error500flatSomething broke on our side. Retry.
upstream_error502nestedThe upstream provider returned an error
model_unavailable503nestedThe model is switched off for now — the response names a fallback when one exists
service_unavailable503flatNo provider is available for this model

Works with the OpenAI SDKs as-is

No new library, no hand-rolled HTTP client. Set base_url and api_key.

python
from openai import OpenAI

client = OpenAI(
    base_url="https://api.wisporta.com/v1",
    api_key="YOUR_WISPORTA_KEY",
)

response = client.chat.completions.create(
    model="openai/gpt-5.5",
    messages=[{"role": "user", "content": "Hello!"}],
)
print(response.choices[0].message.content)
node
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.wisporta.com/v1",
  apiKey: process.env.WISPORTA_API_KEY,
});

const response = await client.chat.completions.create({
  model: "openai/gpt-5.5",
  messages: [{ role: "user", content: "Hello!" }],
});
console.log(response.choices[0].message.content);

Limits to know about

Concurrent requests

One organization may have 10 requests in flight at once. The next one gets 429 too_many_requests immediately.

Points and expiry

Points are deducted after a request succeeds, and they expire 30 days after your most recent top-up — the Web App guide covers the rules.

This is not a rate limit. A steady stream of a few requests at a time never hits it, however long it runs. There is currently no per-key limit on requests per interval.
Read nextRun your organization, keys and points from the dashboardWeb App Guide

Ready to get started?

Sign up free today — no credit card needed. Top up credit when you go live.

An e-Tax Invoice & e-Receipt is issued on every credit top-up