API Reference
The LLM Gateway provides two API formats: OpenAI-compatible and Anthropic-compatible.
Base URL
https://llm.bankr.bot
Authentication
All requests require a Bankr API key (bk_...) in the X-API-Key header or Authorization: Bearer token:
X-API-Key: bk_YOUR_API_KEY
or
Authorization: Bearer bk_YOUR_API_KEY
Generate API keys at bankr.bot/api-keys.
OpenAI-Compatible API
List Models
GET /v1/models
List available models.
Response
{
"object": "list",
"data": [
{ "id": "claude-opus-4.8", "object": "model", "owned_by": "anthropic" },
{ "id": "claude-opus-4.7", "object": "model", "owned_by": "anthropic" },
{ "id": "claude-opus-4.6", "object": "model", "owned_by": "anthropic" },
{ "id": "claude-sonnet-4.6", "object": "model", "owned_by": "anthropic" },
{ "id": "claude-haiku-4.5", "object": "model", "owned_by": "anthropic" },
{ "id": "gemini-3.1-pro", "object": "model", "owned_by": "google" },
{ "id": "gemini-3-flash", "object": "model", "owned_by": "google" },
{ "id": "gemma-4-31b-it", "object": "model", "owned_by": "google" },
{ "id": "gpt-5.4", "object": "model", "owned_by": "openai" },
{ "id": "gpt-5.2", "object": "model", "owned_by": "openai" },
{ "id": "gpt-5.2-codex", "object": "model", "owned_by": "openai" },
{ "id": "grok-4.20", "object": "model", "owned_by": "x-ai" },
{ "id": "glm-5.1", "object": "model", "owned_by": "z-ai" },
{ "id": "deepseek-v3.2", "object": "model", "owned_by": "deepseek" },
{ "id": "minimax-m2.7", "object": "model", "owned_by": "minimax" },
{ "id": "kimi-k2.6", "object": "model", "owned_by": "moonshotai" },
{ "id": "kimi-k2.5", "object": "model", "owned_by": "moonshotai" },
{ "id": "qwen3.5-plus", "object": "model", "owned_by": "qwen" }
]
}
The list above is abbreviated — call /v1/models or bankr llm models for the full live catalog. See Supported Models for the complete list.
A model that can serve private (TEE) inference carries "private": true; once its enclave is attested it also reports "confidential": true and "attested": "gateway". A model that generates images reports "output_modalities": ["image"] and its image rate under pricing.image_output.
Chat Completions
POST /v1/chat/completions
Create a chat completion using OpenAI format.
Request
curl -X POST https://llm.bankr.bot/v1/chat/completions \
-H "Content-Type: application/json" \
-H "X-API-Key: bk_YOUR_API_KEY" \
-d '{
"model": "claude-opus-4.8",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Hello!"}
],
"temperature": 0.7,
"max_tokens": 1024
}'
Response
{
"id": "chatcmpl-abc123",
"object": "chat.completion",
"created": 1706123456,
"model": "claude-opus-4.8",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Hello! How can I help you today?"
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 20,
"completion_tokens": 10,
"total_tokens": 30
}
}
Image Generation
POST /v1/images/generations
Generate images using OpenAI's native Images API format (today: gpt-image-2). Streaming is not supported and n is capped at 4.
Request
curl -X POST https://llm.bankr.bot/v1/images/generations \
-H "Content-Type: application/json" \
-H "X-API-Key: bk_YOUR_API_KEY" \
-d '{
"model": "gpt-image-2",
"prompt": "a friendly pixel-art robot mascot holding a coin",
"size": "1024x1024",
"n": 1
}'
Response
Images are returned as base64 in b64_json; usage reports the tokens billed.
{
"created": 1783526478,
"data": [{ "b64_json": "iVBORw0KGgoAAAANSU..." }],
"usage": {
"input_tokens": 19,
"output_tokens": 1756,
"output_tokens_details": { "image_tokens": 1756, "text_tokens": 0 },
"total_tokens": 1775
}
}
See the Image Generation guide for SDK examples, parameters, and pricing.
Anthropic-Compatible API
Messages
POST /v1/messages
Create a message using Anthropic format. Ideal for Claude Code and Anthropic SDK users.
Request
curl -X POST https://llm.bankr.bot/v1/messages \
-H "Content-Type: application/json" \
-H "X-API-Key: bk_YOUR_API_KEY" \
-d '{
"model": "claude-opus-4.8",
"max_tokens": 1024,
"messages": [
{"role": "user", "content": "Hello!"}
]
}'
Response
{
"id": "msg_abc123",
"type": "message",
"role": "assistant",
"content": [
{
"type": "text",
"text": "Hello! How can I help you today?"
}
],
"model": "claude-opus-4.8",
"stop_reason": "end_turn",
"usage": {
"input_tokens": 10,
"output_tokens": 12
}
}
Ignored Request Fields
When a request is served through OpenRouter's native /messages, the OpenRouter routing controls — provider, models, fallbacks, route, transforms, plugins — are removed rather than forwarded. The gateway picks the upstream provider itself, and usage is metered and priced against the model you named, so a routing override in the body can't move the request to a model you aren't being billed for.
Don't send them at all, though: that route is the only one that strips them, and a provider that receives an unknown top-level field may reject the whole request.
Privacy Tiers
Every request is served at one of three nested tiers — standard (default), zdr, private — and each fails closed rather than downgrading. Ask for one in whichever way your client supports:
| Channel | Example |
|---|---|
| Request field | "privacy": "zdr" |
| Base-path prefix | https://llm.bankr.bot/zdr/v1/chat/completions |
| Model suffix | "model": "glm-5.2:zdr" |
| Account setting | Settings tab in the LLM Gateway terminal |
The account setting and a per-request ask combine strongest-wins — a request can tighten beyond the account setting, never below it. A tier endpoint is authoritative instead: sending a request that names a different tier to /zdr or /private returns 400 privacy_conflict. "zdr": true and "private": true remain supported as legacy spellings.
See Privacy Tiers for the full reference.
curl -X POST https://llm.bankr.bot/v1/chat/completions \
-H "Content-Type: application/json" \
-H "X-API-Key: bk_YOUR_API_KEY" \
-d '{
"model": "glm-5.2",
"privacy": "zdr",
"messages": [{"role": "user", "content": "Hello!"}]
}'
A request that asks for zdr on a model no provider can serve with zero retention returns 422 zdr_unavailable.
Private (Confidential) Inference
Available on both /v1/chat/completions (OpenAI format) and /v1/messages (Anthropic format).
Send "privacy": "private" — or append :private to a private-capable model ID, or send "private": true in the request body — to route into a hardware-secured enclave. The gateway verifies the enclave's attestation and fail-closes (422 confidential_unavailable if the model has no TEE slot, 503 attestation_unverified if attestation can't be verified). Verified responses carry X-Confidential-Verified, X-Confidential-Signer, and X-Confidential-Tcb headers.
curl -X POST https://llm.bankr.bot/v1/chat/completions \
-H "Content-Type: application/json" \
-H "X-API-Key: bk_YOUR_API_KEY" \
-d '{
"model": "glm-5.2:private",
"messages": [{"role": "user", "content": "Hello!"}]
}'
Attestation Report
GET /v1/attestation/report
Returns the provider's raw attestation report (Intel TDX quote + ed25519 signing key) so a client can independently verify the enclave. See Private Inference for the full flow.
Health Check
GET /health
Check gateway and provider health. No authentication required.
Response
{
"status": "ok",
"providers": {
"vertexGemini": true,
"vertexClaude": true,
"openrouter": true
}
}
Status codes:
200— At least one provider healthy503— All providers unavailable
Error Responses
401 Unauthorized
{
"error": {
"message": "Unauthorized",
"type": "auth_error"
}
}
429 Rate Limited
{
"error": {
"message": "Too many requests, please try again later.",
"type": "rate_limit_error"
}
}
503 Model Temporarily Unavailable
Returned when no provider slot is currently serving the requested model — an operational state, not a bad request. Retry, or fall back to another model.
{
"error": {
"message": "Model temporarily unavailable",
"type": "api_error",
"code": "provider_unavailable"
}
}
500 Server Error
{
"error": {
"message": "Internal server error",
"type": "api_error",
"code": "internal_error"
}
}
On /v1/messages, errors use the Anthropic envelope instead — {"type": "error", "error": {"type", "message"}} — with the same status codes.
Usage
Get Usage Summary
GET /v1/usage?days=30
Returns aggregated token usage and cost breakdown for the authenticated API key. Requires authentication.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
days | number | 30 | Number of days to aggregate (1–90) |
Response
{
"object": "usage_summary",
"days": 30,
"startDate": "2026-01-28T00:00:00.000Z",
"endDate": "2026-02-27T00:00:00.000Z",
"totals": {
"totalRequests": 1981,
"totalInputTokens": 489789,
"totalOutputTokens": 631794,
"totalCacheReadInputTokens": 53460194,
"totalCacheWriteInputTokens": 12555591,
"totalTokens": 67137368,
"totalCost": 248.38,
"totalCacheCost": 208.01
},
"byModel": [
{
"model": "claude-opus-4.8",
"provider": "vertex-claude",
"requests": 1574,
"inputTokens": 6250,
"outputTokens": 500097,
"cacheReadInputTokens": 27309491,
"cacheWriteInputTokens": 7474005,
"totalTokens": 35289843,
"totalCost": 218.7,
"cacheCost": 181.1
}
]
}
Credits
Get Credit Balance
GET /v1/credits
Returns the current LLM credit balance for the API key's wallet. Requires authentication.
Use this to check available capacity before relying on the gateway — effectiveBalanceUsd is the truest "available balance" because it nets out in-flight usage that hasn't been deducted yet. Balances read directly from the database (not a cached value) for accuracy.
Request
curl https://llm.bankr.bot/v1/credits \
-H "X-API-Key: bk_YOUR_API_KEY"
Response
{
"object": "credit_balance",
"balanceUsd": 12.34,
"effectiveBalanceUsd": 11.2,
"undeductedCostUsd": 1.14,
"dailyBudget": {
"limitUsd": 25,
"spentUsd": 4.2,
"remainingUsd": 20.8,
"exceeded": false,
"resetsAt": "2026-08-08T00:00:00.000Z"
}
}
Fields
| Field | Type | Description |
|---|---|---|
balanceUsd | number | Total spendable credit on the wallet, in USD. |
effectiveBalanceUsd | number | Available balance after subtracting in-flight usage not yet deducted. Floored at 0. Use this for capacity decisions. |
undeductedCostUsd | number | Cost of in-flight/served requests not yet deducted from balanceUsd (the amount subtracted to derive effectiveBalanceUsd). |
dailyBudget | object | Present only when a daily spend budget is set on the wallet. Omitted entirely when spend is uncapped. |
Requests are rejected with 402 Payment Required once the effective balance is exhausted. There are no per-key spending caps — the balance shown is the full credit available to the key.
Daily spend budget
A wallet can carry an optional cap on how much it spends per day. It bounds burn rate; the credit balance still bounds total spend. Set it in the Settings tab at bankr.bot/llm — a key cannot change its own wallet's budget, so a leaked key can't raise the cap it is bound by.
The budget spans all metered LLM spend on the wallet, not just gateway traffic: requests from every API key it owns, plus Max Mode and app-invoked Bankr agent runs. Both are enforced — gateway requests are refused, and an agent run ends early once the day's spend reaches the cap.
| Field | Type | Description |
|---|---|---|
limitUsd | number | The configured cap, in USD per UTC day. |
spentUsd | number | Spend counted against the budget so far today, including usage not yet deducted. |
remainingUsd | number | limitUsd - spentUsd, floored at 0. |
exceeded | boolean | Whether the budget is spent. While true, requests are rejected. |
resetsAt | string | ISO 8601 timestamp of the next reset — always the next 00:00 UTC. |
Once the budget is reached, requests are rejected with 402 Payment Required and an error type of daily_budget_exceeded — distinct from the insufficient_credits returned when the balance itself runs out. Only requests that spend are blocked. Every read-only (GET) endpoint — /v1/credits, /v1/usage, /v1/models among them — keeps working while you're over budget, so you can still read remainingUsd and resetsAt to find out when you'll be unblocked, and check what spent the budget:
{
"error": {
"message": "Daily LLM Gateway spend budget reached. It resets at 00:00 UTC, or you can raise it at bankr.bot/llm.",
"type": "daily_budget_exceeded"
}
}
Budget changes reach the gateway within 60 seconds (it caches authentication state), and enforcement is evaluated against that cached view, so spend may overshoot the cap slightly under a sustained burst. Each gateway instance caches independently, so with several serving traffic the overshoot scales with instance count. Treat it as a guardrail, not an accounting boundary — your credit balance remains the hard limit on total spend.
Streaming
Both endpoints support streaming responses:
curl -X POST https://llm.bankr.bot/v1/chat/completions \
-H "Content-Type: application/json" \
-H "X-API-Key: bk_YOUR_API_KEY" \
-d '{
"model": "claude-opus-4.8",
"messages": [{"role": "user", "content": "Hello!"}],
"stream": true
}'
Streaming uses Server-Sent Events (SSE) format.