Heimdall API documentation
OpenAI-compatible LLM gateway with virtual keys, per-key budgets, multi-provider routing.
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
- 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.
- Receive your API key by email. It looks like
sk-bf-<your-api-key>. - Replace your existing OpenAI/Anthropic base URL with
https://heimdall-llm.com/v1. - 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 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 / param | Required | Notes |
|---|---|---|
Authorization: Bearer sk-bf-... | yes | Your virtual key |
model | yes | See /v1/models. Must be in your key's allowed_models list. |
messages | yes | [{role, content}, ...] |
max_tokens, temperature, top_p, stream | no | OpenAI-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
- Anthropic:
claude-opus-4-7,claude-sonnet-4-6,claude-haiku-4-5 - DeepSeek:
deepseek-v4-flash,deepseek-reasoner - OpenAI:
gpt-5.5,gpt-5.4,gpt-5.4-mini - Anthropic aliases:
ceo(best),default(balanced),cheap - DeepSeek aliases:
cheap-chat,cheap-reasoner - OpenAI aliases:
gpt-pro,gpt-fast
Error codes
| HTTP | Code | When |
|---|---|---|
| 401 | virtual_key_not_found | Key is unknown, revoked, or paused |
| 403 | MODEL_NOT_ALLOWED | Requested model not in key's allowed_models |
| 403 | ACCOUNT_SUSPENDED | Org owner is suspended |
| 429 | DAILY_LIMIT_EXCEEDED | Per-key daily budget hit |
| 429 | RATE_LIMIT_EXCEEDED | Per-IP throttle |
| 502 | UPSTREAM_ERROR | Provider down (Anthropic / OpenAI / DeepSeek) |
Heimdall management API
Account & key management. JWT auth via POST /api/v1/auth/login.
| Method & path | Auth | Purpose |
|---|---|---|
POST /api/v1/auth/signup | none | Create account. Body: {email, password, locale, tos_version_accepted} |
POST /api/v1/auth/verify-email | none | Activate via emailed token |
POST /api/v1/auth/login | none | Returns access JWT + refresh cookie |
POST /api/v1/auth/refresh | cookie | Rotates access JWT |
POST /api/v1/auth/logout | cookie | Revokes refresh family |
POST /api/v1/keys | JWT | Create virtual key (returns 202; poll /:id for secret) |
GET /api/v1/keys | JWT | List keys |
GET /api/v1/keys/{id} | JWT | Status; returns secret if cache hit (5-min reveal window) |
POST /api/v1/keys/{id}/revoke | JWT | Revoke 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]