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.
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.