API overview

API overview

Base URL: https://hisoka.ai/api/v1

Every path below is relative to it. The base URL deliberately stops at /api/v1, because
the SDKs append their own version segment.

The three wire protocols

Endpoint Protocol Clients
POST /chat/completions OpenAI chat Cline, Roo, Kilo, Continue, aider, OpenAI SDK
POST /responses OpenAI Responses Codex CLI
POST /messages Anthropic Messages Claude Code, Cursor, Zed
POST /messages/count_tokens Anthropic Claude Code, before every turn

Each one is a first-class path with its own renderer, not a translation layer bolted onto
one canonical format. That is why an SDK sees the envelope it expects, including the error
shape: /messages returns an Anthropic {"type": "error"} body while the OpenAI paths
return {"error": {...}}.

The response envelope

A chat completion is an ordinary OpenAI response plus one extra block:

{
  "id": "chatcmpl-01M73N2HP4HDDZH803J1C120HT",
  "object": "chat.completion",
  "created": 1794345354,
  "model": "glm-5.3-flash",
  "choices": [
    {
      "index": 0,
      "message": { "role": "assistant", "content": "2, 3, 5." },
      "finish_reason": "stop"
    }
  ],
  "usage": { "prompt_tokens": 18, "completion_tokens": 8, "total_tokens": 26 },
  "hisoka": {
    "model": "glm-5.3-flash",
    "usd_charged": 0.000014,
    "usd_micro_charged": 14,
    "balance": "4.819986",
    "max_tokens": null,
    "cap_raised_from": null,
    "client": "curl"
  }
}

The hisoka block is our addition. Treat it as optional: a client that ignores unknown
fields loses nothing, and a proxy that strips it still leaves a valid OpenAI response.

Field Meaning
usd_micro_charged The integer micro-USD the wallet moved. Use this to reconcile.
max_tokens The cap actually applied, which may differ from what you sent.
cap_raised_from Set when a reasoning model needed a higher floor than you asked for.
balance Balance after the call, as the gateway formats it.
client Detected client family, for support.

Request ids

Every response carries X-Request-Id. Every failure repeats it inside the body as
request_id, and adds x-should-retry. Quote the id in any report: it pairs a caller’s
screenshot with the exact server-side attempt.

curl -i https://hisoka.ai/api/v1/models | grep -i x-request-id

Errors

Every failure, on every path, uses the same nested envelope:

{
  "error": {
    "message": "No such model: the requested model (model_not_found)",
    "type": "not_found_error",
    "param": null,
    "code": "model_not_found",
    "support": "[email protected]",
    "docs": "https://docs.hisoka.ai/errors/",
    "request_id": "01M73N2HP4HDDZH803J1C120HT"
  }
}

Branch on code, never on the message. The message is written for a human reading a
screenshot and may be reworded; the code is stable. The full list, with which codes are
worth retrying, is on the Errors page.

A provider name never appears in an error

The upstream pool is operator information. If you see an internal slug in a response,
that is a bug worth reporting, not configuration you need to handle.

Rate limits

Per-key limits are enforced per route and answered with 429 gateway_rate_limited plus
Retry-After. A 429 pool_exhausted is different: it means every account behind that
model is throttled upstream, and the right response is to wait, not to switch models.

See Rate limits for the numbers.

Specification

This reference is generated from an OpenAPI 3.1 document:

curl https://docs.hisoka.ai/assets/hisoka.openapi.json -o hisoka.openapi.json

Point any OpenAPI tool at it: Postman, an SDK generator, or a client that validates
requests before sending them.