Dracon AI API — Reference
Every endpoint, request/response shape, error code, and the recommended client retry policy. For the formal internal spec, see apis/docs/external-consumer-guide-2026-06-12.md in the public repo.
Base URL & auth
All endpoints are at https://dracon.uk. AI endpoints use the x-api-key header. Auth endpoints use a session cookie (set automatically when you sign in via the magic-link flow).
POST https://dracon.uk/api/v1/ai/chat/completions
Content-Type: application/json
x-api-key: dracon_628ca0502df74aa1862b72a74968b508
{
"lane": "writing",
"project_id": "my-app",
"messages": [{ "role": "user", "content": "Hello" }],
"max_tokens": 4096
}
Endpoints
AI completions
| Method | Path | Auth |
|---|---|---|
| POST | /api/v1/ai/chat/completions | x-api-key |
| POST | /api/v1/ai/chat/stream | x-api-key (SSE) |
| POST | /api/v1/ai/image | x-api-key |
| POST | /api/v1/ai/music | x-api-key |
| POST | /api/v1/ai/soundfx | x-api-key |
| POST | /api/v1/ai/tts | x-api-key |
BYOK (Bring Your Own Key)
| Method | Path | Purpose |
|---|---|---|
| POST | /api/v1/keys | Upload a provider key (OpenAI, Anthropic, …) |
| GET | /api/v1/keys | List stored providers |
| DELETE | /api/v1/keys/{provider} | Remove a stored key |
Auth & key management
| Method | Path | Auth | Purpose |
|---|---|---|---|
| POST | /api/v1/auth/request-magic-link | none | Send a magic link to your email |
| POST | /api/v1/auth/verify-code | none | Consume a magic-link code, get session cookies |
| GET | /api/v1/auth/session | session | Get current session info |
| GET | /api/v1/me | session or api key | Get current user profile |
| POST | /api/v1/auth/api-keys | session + Origin | Create a new API key (returns plaintext once) |
| GET | /api/v1/auth/api-keys/list | session | List your API keys (no plaintext) |
| POST | /api/v1/auth/api-keys/revoke | session + Origin | Revoke a key by id |
Request shapes
Chat completions (POST /api/v1/ai/chat/completions)
{
"lane": "writing", // required, must be in AI_ALLOWED_LANES
"project_id": "my-app", // required, ≤128 chars
"messages": [ // 1–128 messages, each ≤64 KB
{ "role": "user", "content": "Hello" }
],
"model": "gpt-4o", // optional, defaults to lane default
"max_tokens": 4096 // optional, default 4096
}
Response:
{
"content": "Hello, how can I help?",
"model_used": "gemini-2.5-flash",
"finish_reason": "stop",
"usage": { "completion_tokens": 182, "prompt_tokens": 22, "total_tokens": 204 }
}
The model field is optional. For the free lane, Dracon selects from the verified free providers in priority order: Gemini 2.5 Flash, Mistral Medium, and NVIDIA Nemotron. The wildcard OpenRouter free router and unreliable free models are not served as first-class free-lane options.
API key creation (POST /api/v1/auth/api-keys)
{
"name": "my-app", // required, alphanumeric
"scope": "ai" // optional, default "ai"
}
Response (201):
{
"key": "dracon_628ca0502df74aa1862b72a74968b508",
"key_id": "2e4b82aa-ae48-44bb-b9e2-9a30d5b81605",
"key_prefix": "dracon_6",
"name": "my-app",
"scope": "ai"
}
The plaintext key is shown once. The server stores only a hash. There is no "show me the key again" endpoint.
Error codes
Errors return JSON with error (string code) and request_id (UUID). Always log request_id when reporting issues.
| Code | HTTP | Meaning |
|---|---|---|
missing api key | 401 | No x-api-key header |
invalid api key | 401 | Key revoked or not found |
missing_authentication | 401 | No session cookie or api key |
csrf_origin | 403 | State-changing request from browser with wrong Origin |
maximum_keys | 400 | 5-key limit reached |
rate_limited | 429 | Honour retry-after header |
messages cannot be empty | 400 | messages: [] |
message content exceeds maximum length | 400 | Single message > 64 KB |
total message content exceeds 8MB limit | 400 | Sum of all messages > 8 MB |
lane is required | 400 | lane empty or missing |
project_id is required | 400 | project_id present but empty |
| deserialization error | 422 | project_id field omitted from JSON |
unknown lane | 400 | lane not in AI_ALLOWED_LANES |
upstream AI service timed out | 504 | Provider did not respond in 60s; retry with backoff |
Retry policy
No per-call charge is enforced by the Dracon API layer in the current deployment. The preview limits below are the enforceable limits.
- 401 with
expiredorinvalid api key— the key is dead. Re-prompt the user to create a new one. Do not retry. - 429 with
retry-after— honour the header. Back off. - 504 — retry once with exponential backoff (e.g. 2s, 4s, 8s). After 3 attempts, surface the error.
- 5xx (any other) — retry once. If still failing, surface.
- Network error — retry with backoff. Log the
request_idfrom any prior response for traceability.
CORS for browser clients
If you call the API from a browser served from a different domain, your origin must be in the apex CORS allowlist. The apex currently allows https://dracon.uk. To add your origin, contact the operator (admin@dracon.uk) with:
- Your origin URL (e.g.
https://my-app.example.com) - Whether you need POST/DELETE preflight to work (all AI endpoints accept POST; BYOK uses DELETE)
Same-origin browser clients (your app at https://dracon.uk/...) work out of the box — CORS only applies cross-origin.
Operational limits
- 60 requests per minute per source IP. Returns 429 with
retry-afterwhen exceeded. - 5 API keys per user. Returns 400
maximum_keyson the 6th. - Max 128 messages per chat request.
- Max 64 KB per message.
- Max 8 MB total message content per request.
- Provider timeout: 60 seconds.
Need a key? Sign up in 60 seconds.