Skip to main content

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:

ChannelExample
Request field"privacy": "zdr"
Base-path prefixhttps://llm.bankr.bot/zdr/v1/chat/completions
Model suffix"model": "glm-5.2:zdr"
Account settingSettings 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 healthy
  • 503 — 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

ParameterTypeDefaultDescription
daysnumber30Number 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

FieldTypeDescription
balanceUsdnumberTotal spendable credit on the wallet, in USD.
effectiveBalanceUsdnumberAvailable balance after subtracting in-flight usage not yet deducted. Floored at 0. Use this for capacity decisions.
undeductedCostUsdnumberCost of in-flight/served requests not yet deducted from balanceUsd (the amount subtracted to derive effectiveBalanceUsd).
dailyBudgetobjectPresent 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.

FieldTypeDescription
limitUsdnumberThe configured cap, in USD per UTC day.
spentUsdnumberSpend counted against the budget so far today, including usage not yet deducted.
remainingUsdnumberlimitUsd - spentUsd, floored at 0.
exceededbooleanWhether the budget is spent. While true, requests are rejected.
resetsAtstringISO 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.