Authentication
Authentication
Every endpoint except GET /models and GET / needs a key. There are two accepted
header styles, and they are equivalent: pick whichever your client already emits.
The two styles
Authorization: Bearer sk-your-key-here
The OpenAI style. Any OpenAI SDK sends this on its own once api_key is set.
x-api-key: sk-your-key-here
The Anthropic style. Claude Code, Cursor and the Anthropic SDKs send this. api-key and
x-goog-api-key are accepted as well, for clients with their own spelling.
A key that works for a completion also works for your bill, so the wallet endpoints use
the same lookup rather than a second credential system.
Padding is tolerated
RFC 7230 allows spaces around a header value and some SDKs send them. The key is trimmed
before it is resolved, so a trailing newline pasted from a dotfile does not produce a
401.
What a bad key looks like
{
"error": {
"message": "Invalid API key (invalid_api_key)",
"type": "authentication_error",
"param": null,
"code": "invalid_api_key",
"support": "[email protected]",
"docs": "https://docs.hisoka.ai/errors/",
"request_id": "01M73N2HP4HDDZH803J1C120HT"
}
}
That is one code covering four situations: missing, malformed, revoked, and expired. All
four are fixed the same way, by issuing a new key, so the distinction is not worth a
separate code.
IP allowlists
A key may carry an allowlist. A caller outside it gets 403 ip_not_allowed, and the
allowlist is checked per request rather than only at creation, so narrowing it takes
effect immediately for keys already in use.
Limits worth knowing
- Keys are shown once. The plaintext exists at creation and never again; the server
keeps only a hash. If you lose it, revoke and create another. - A revoked key is dead immediately. There is no grace period, so rotate by creating
the replacement first. - There is an active-key ceiling per account. Revoking a key frees a slot; expired and
revoked keys do not count against you, so rotating does not lock you out.
A key in a browser bundle or a mobile binary is a key you have published. Proxy through
your own backend and keep the key server-side. Every call is billed to the key’s owner,
so a leaked key is your balance, not someone else’s problem.
Using it from an SDK
from openai import OpenAI
client = OpenAI(
api_key="sk-your-key-here",
base_url="https://hisoka.ai/api/v1",
)
import OpenAI from "openai";
const client = new OpenAI({
apiKey: "sk-your-key-here",
baseURL: "https://hisoka.ai/api/v1",
});
The SDKs append their own /v1 to the paths they call, so base_url ends at /api/v1
and the SDK builds /api/v1/chat/completions. Set it one level deeper and every request
404s. The gateway collapses a repeated version segment, but it will never strip a single
one, because that would break clients that send it exactly once.