Get an API key

Version 2026-08-01

API reference

One REST API, four official SDKs and no surprises. Every endpoint is idempotent where it can be, every error is machine-readable, and every response tells you exactly what it cost.

Introduction

The Lumen API is organised around three resources: runs (a model call, with optional tools and retrieval), collections (indexed documents) and keys. Requests and responses are JSON. All timestamps are RFC 3339 in UTC.

Base URL https://api.lumen.example.com/v1
Every response carries usage usage.input_tokens, usage.output_tokens and usage.cached_tokens appear on every successful call, so you can attribute cost per request without a separate billing query.

Authentication

Authenticate with a bearer token in the Authorization header. Keys are scoped to a single workspace and carry one of three roles: read, run or admin.

Request header
Authorization: Bearer lum_live_7f4c9a2e8b1d6035
Content-Type: application/json
Lumen-Version: 2026-08-01
Never ship a key to the browser Keys prefixed lum_live_ carry full workspace permissions. For client-side apps, mint a short-lived session token from your backend with POST /v1/sessions instead.

Key roles

Role Can do Cannot do
read Query collections, read runs and usage Create runs, mutate collections
run Everything read can, plus create runs and call tools Rotate keys, change billing, delete collections
admin Full workspace access including key rotation and budgets Cross-workspace access — keys never span workspaces

Quickstart

The shortest useful call: one prompt, one model, one answer. Pick your language.

curl https://api.lumen.example.com/v1/runs \
  -H "Authorization: Bearer $LUMEN_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "lumen-pro",
    "input": "Summarise our refund policy in two sentences.",
    "collections": ["handbook"],
    "max_output_tokens": 300
  }'

Create a run

A run is one turn of an agent: optional retrieval, zero or more tool calls, and a final answer. Runs are durable — fetch one again by id for 30 days.

POST /v1/runs

Body parameters

Parameter Required Description
modelstring Required One of lumen-flash, lumen-pro, lumen-max. See models.
inputstring | array Required A prompt string, or an array of message objects for multi-turn conversations.
collectionsstring[] Optional Collection ids to retrieve from before answering. Retrieval is skipped when omitted.
toolsobject[] Optional Tool definitions the model may call. Up to 128 per run.
streamboolean Optional When true, responds with text/event-stream. Defaults to false.
max_output_tokensinteger Optional Hard ceiling on generated tokens. Defaults to the model maximum.
temperaturenumber Optional Between 0 and 2. Defaults to 0.7. Use 0 for extraction.
response_formatobject Optional Pass {"type":"json_schema","schema":{…}} to force schema-valid JSON.
idempotency_keystring Optional Replays return the original run instead of billing twice. Retained 24 hours.

Unknown fields are rejected with 400 invalid_request rather than ignored — typos fail loudly.

Response

200 OK · application/json
{  "id": "run_9f2ab41c",  "object": "run",  "model": "lumen-pro",  "created_at": "2026-08-01T09:14:22Z",  "status": "completed",  "output_text": "Refunds are available for 30 days…",  "citations": [    { "source": "handbook.pdf", "page": 14, "score": 0.912 }  ],  "usage": {    "input_tokens": 1842,    "cached_tokens": 1408,    "output_tokens": 96,    "cost_eur": 0.00213  }}

Streaming

Set stream: true to receive Server-Sent Events. Tokens, tool calls and citations arrive on the same channel, each as a typed event.

Event types emitted during a streamed run.
Event Payload Meaning
run.started { id, model } The run is accepted. Emitted once.
token { text } A fragment of the answer. Concatenate in order received.
tool.call { name, arguments } The model wants a tool run. Arguments are already schema-validated.
tool.result { name, output, ms } Your handler returned. Emitted for hosted tools only.
citation { source, page, score } A source that grounded the sentence just streamed.
run.completed { usage, finish_reason } Terminal event. Always emitted, including after an error.
event: run.started
data: {"id":"run_9f2ab41c","model":"lumen-pro"}

event: token
data: {"text":"Refunds "}

event: tool.call
data: {"name":"lookup_order","arguments":{"id":"A-8812"}}

event: citation
data: {"source":"handbook.pdf","page":14}

event: run.completed
data: {"finish_reason":"stop","usage":{"output_tokens":96}}

Tool calling

Declare tools as JSON Schema. Lumen validates arguments before they reach your handler, so a malformed call never becomes a runtime exception in your code. Independent calls run in parallel automatically.

tool definition
{
  "name": "lookup_order",
  "description": "Fetch an order by its reference.",
  "parameters": {
    "type": "object",
    "properties": {
      "id": { "type": "string", "pattern": "^A-[0-9]{4}$" }
    },
    "required": ["id"],
    "additionalProperties": false
  },
  "timeout_ms": 4000,
  "retries": 2
}
Keep descriptions behavioural “Fetch an order by its reference” beats “order tool”. The description is the only thing the model reads when deciding whether to call it.

Retrieval

Query a collection directly when you want the passages without an answer — for a search UI, an evaluation harness, or your own prompt assembly.

POST /v1/collections/{collection_id}/query
GET /v1/collections/{collection_id}/documents
DELETE /v1/collections/{collection_id}/documents/{document_id}
query.sh
curl ".../v1/collections/handbook/query" \
  -H "Authorization: Bearer $LUMEN_KEY" \
  -d '{
    "query": "parental leave",
    "top_k": 5,
    "rerank": true,
    "filter": { "region": "eu", "updated_after": "2026-01-01" }
  }'

# → { "matches": [ { "text": "…", "score": 0.91, "page": 14 } ] }

Errors

Errors use standard HTTP status codes with a stable machine-readable code. Match on code, never on message — the prose changes, the code does not.

Every error the API can return.
Status Code What happened What to do
400 invalid_request A field is missing, malformed or unknown. Fix the payload. The param field names the offender.
401 invalid_api_key The key is missing, revoked or from another workspace. Check the header. Do not retry — it will not start working.
403 insufficient_scope A read key tried to create a run. Mint a key with the run role.
404 not_found No such run, collection or document. Verify the id. Runs are retained for 30 days.
409 idempotency_conflict The same key was reused with a different body. Use a fresh key, or resend the identical payload.
413 context_length_exceeded Input plus retrieved context exceeds the window. Lower top_k, or move to a longer-context model.
429 rate_limited Requests or tokens per minute exceeded. Back off using Retry-After. See limits.
429 budget_exceeded The workspace hit its monthly spend cap. Raise the cap in settings. Retrying will not help.
500 internal_error Our fault. Already paged. Retry with jittered backoff, up to three attempts.
503 upstream_unavailable Every provider for that model is degraded. Retry, or fall back to a different model family.
400 Bad Request
{
  "error": {
    "code": "invalid_request",
    "message": "temperature must be between 0 and 2",
    "param": "temperature",
    "request_id": "req_c81f0a44"
  }
}

Always log request_id. It is the fastest way for us to find your call in support.

Versioning

The API is dated, not numbered. Pin a version with the Lumen-Version header; without it you get the version your workspace was created on, frozen. Breaking changes ship under a new date and old dates stay live for 18 months.

Version Status Notes
2026-08-01 Current Parallel tool calls, cached_tokens in usage, 1M context on max.
2026-02-14 Supported Adds citations to streamed runs. Sunsets 14 August 2027.
2025-09-30 Deprecated Sunsets 30 March 2027. Migrate off completions.

Get a key and make your first call

Free tier, no card. The quickstart above works verbatim once you paste your key.