Heimdall / docs

Heimdall API documentation

OpenAI-compatible LLM gateway with virtual keys, per-key budgets, multi-provider routing.

📌 About code samples below: All sk-bf-<your-api-key> strings are placeholder examples, not real credentials. Your actual key is delivered to you by email after account provisioning. Read the user guide to learn how to obtain and store keys safely.

Quickstart — 60 seconds

  1. Buy a plan on the pricing page. Our team responds within 24h to set you up — manual onboarding is intentional during MVP, automated billing comes in Phase 2.
  2. Receive your API key by email. It looks like sk-bf-<your-api-key>.
  3. Replace your existing OpenAI/Anthropic base URL with https://heimdall-llm.com/v1.
  4. Make a request — see examples below.

Authentication

Heimdall uses Bearer token auth. Pass your virtual key in the Authorization header:

Authorization: Bearer sk-bf-<your-api-key>

Same format works for both LLM endpoints (/v1/*) and Heimdall management API (/api/v1/*). For management API, the token is a short-lived access JWT obtained via POST /api/v1/auth/login.

First API call

curl Python Node.js Go
curl https://heimdall-llm.com/v1/chat/completions \
  -H "Authorization: Bearer sk-bf-..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-haiku-4-5",
    "messages": [{"role": "user", "content": "Hello!"}]
  }'

LLM endpoints (OpenAI-compatible)

POST /v1/chat/completions

Standard OpenAI chat-completions schema. Streaming via "stream": true.

Header / paramRequiredNotes
Authorization: Bearer sk-bf-...yesYour virtual key
modelyesSee /v1/models. Must be in your key's allowed_models list.
messagesyes[{role, content}, ...]
max_tokens, temperature, top_p, streamnoOpenAI-standard params

GET /v1/models

Lists all models known to Heimdall, with pricing. Requires authentication. The actual subset your key can use depends on the allowed_models list configured for that key.

curl https://heimdall-llm.com/v1/models \
  -H "Authorization: Bearer sk-bf-<your-api-key>"

Currently available providers & aliases

Error codes

HTTPCodeWhen
401virtual_key_not_foundKey is unknown, revoked, or paused
403MODEL_NOT_ALLOWEDRequested model not in key's allowed_models
403ACCOUNT_SUSPENDEDOrg owner is suspended
429DAILY_LIMIT_EXCEEDEDPer-key daily budget hit
429RATE_LIMIT_EXCEEDEDPer-IP throttle
502UPSTREAM_ERRORProvider down (Anthropic / OpenAI / DeepSeek)

Heimdall management API

Account & key management. JWT auth via POST /api/v1/auth/login.

Method & pathAuthPurpose
POST /api/v1/auth/signupnoneCreate account. Body: {email, password, locale, tos_version_accepted}
POST /api/v1/auth/verify-emailnoneActivate via emailed token
POST /api/v1/auth/loginnoneReturns access JWT + refresh cookie
POST /api/v1/auth/refreshcookieRotates access JWT
POST /api/v1/auth/logoutcookieRevokes refresh family
POST /api/v1/keysJWTCreate virtual key (returns 202; poll /:id for secret)
GET /api/v1/keysJWTList keys
GET /api/v1/keys/{id}JWTStatus; returns secret if cache hit (5-min reveal window)
POST /api/v1/keys/{id}/revokeJWTRevoke key (propagates to all providers within ~1 second)

Usage

GET /api/v1/usage/summary?period=today|7d|30d|90d
Authorization: Bearer <access_token>

Returns aggregate by model with transparent split:

{
  "totals": {"requests": 95, "input_tokens": 28700, "output_tokens": 12500,
             "cost_provider_usd_cents": 186, "cost_billed_usd_cents": 262},
  "by_model": [
    {"model": "claude-sonnet-4-6", "requests": 20,
     "cost_provider_usd_cents": 144, "cost_billed_usd_cents": 201,
     "heimdall_fee_usd_cents": 57}
  ],
  "last_synced_at": "2026-05-12T22:15:21Z"
}

Privacy / DSR (GDPR Art. 15 + 152-ФЗ ст. 14)

POST /api/v1/settings/dsr/export    # request data export
GET  /api/v1/settings/dsr/requests  # list past requests

Limit: 1 request per 30 days per user. Target response time: 5 business days (30-day hard SLA per GDPR Art. 12(3)).


Questions? [email protected] · DSR: [email protected]