DOCS / MANAGEMENT API / API KEYS

API Keys

This is where an application actually gets a credential it can use against /v1/chat/completions. Every endpoint here is scoped to one application ({id} in the path). For the generation/hashing mechanics themselves, see Security.

List an application's keys

http
Authorization: Bearer lattice_sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
json
type ProviderAdapter = {
  id: ProviderId;
  createChatCompletion(
    request: ChatCompletionRequest,
    ctx: ProviderRequestContext,
  ): Promise<ChatCompletionResponse>;
  streamChatCompletion(
    request: ChatCompletionRequest,
    ctx: ProviderRequestContext,
  ): AsyncGenerator<ChatCompletionChunk, void, void>;
};

type ProviderRequestContext = {
  apiKey?: string;
  providerModel: string;
  signal: AbortSignal;
};
WARNING
Only keyPrefix is ever returned — enough to recognize a key in a UI (lattice_sk_ plus 12 characters), never enough to reconstruct it. The stored hash never leaves the server; the serializer that builds this response strips it explicitly. See Security.

Create (issue) a key

http
{
  "id": "chatcmpl-...",
  "object": "chat.completion",
  "created": 1755878400,
  "model": "gpt-4o",
  "choices": [
    {
      "index": 0,
      "message": { "role": "assistant", "content": "..." },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 42,
    "completion_tokens": 118,
    "total_tokens": 160
  }
}

No request body. Response (200):

json
data: {"id":"chatcmpl-...","object":"chat.completion.chunk","created":1755878400,"model":"gpt-4o","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}

data: {"id":"chatcmpl-...","object":"chat.completion.chunk","created":1755878400,"model":"gpt-4o","choices":[{"index":0,"delta":{"content":"Sure"},"finish_reason":null}]}

data: {"id":"chatcmpl-...","object":"chat.completion.chunk","created":1755878400,"model":"gpt-4o","choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":{"prompt_tokens":42,"completion_tokens":118,"total_tokens":160}}

data: [DONE]
NOTE
key is the raw secret, returned exactly once, in this response only. It is never retrievable again — not through this API, not through the dashboard, not from the database (only its hash is stored). Capture it immediately and hand it to whoever owns the calling application; if it's lost, issue a new key and revoke the old one.

404 not_found if {id} doesn't match an existing application.

Revoke a key

http
type ChatCompletionChunk = {
  id: string;
  object: 'chat.completion.chunk';
  created: number;
  model: string;
  choices: [
    {
      index: number;
      delta: { role?: 'assistant'; content?: string };
      finish_reason: 'stop' | 'length' | 'content_filter' | null;
    },
  ];
  usage?: { prompt_tokens: number; completion_tokens: number; total_tokens: number } | null;
};

Returns the now-revoked ApiKey (with revokedAt set). 404 not_found if there's no active key with that id under that application — revoking an already-revoked or nonexistent key is not idempotent-success, it's a 404.

Revocation is immediate: the next request authenticated with that key fails with 401 invalid_api_key, since verifyApiKey only matches active (unrevoked) keys.

Rotating a key without downtime

Issue a new key

POST .../api-keys — capture the returned key.

Deploy it

Update the calling application's configuration/secret store with the new key, deploy, and confirm it's serving traffic successfully.

Revoke the old key

DELETE .../api-keys/{oldKeyId} once you've confirmed nothing is still using it.

An application can hold multiple simultaneously-active keys — nothing about creating a new one revokes the old one automatically, which is what makes this rotation safe to do without a gap.

Disabling an application vs. revoking its keys

Revoking is per-key and granular. Setting applications.disabled (via update application) is a single switch that invalidates every key that application has ever been issued, at once, without touching the api_keys rows individually — useful for an incident response ("cut this application off now") where enumerating and revoking keys one by one would be slower.

LATTICE — INTERNAL AI INFRASTRUCTURE
GITHUB © 2026