> ## Documentation Index
> Fetch the complete documentation index at: https://continuum-three-olive.vercel.app/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Inference API

> Call hosted models with OpenAI-compatible or Anthropic-compatible HTTP requests.

The Inference API runs model requests against your Continuum hosted inference allowance. Use it from your backend or an API-compatible coding tool.

## Endpoints and base URLs

| Method | URL                                            | Purpose                             |
| ------ | ---------------------------------------------- | ----------------------------------- |
| `GET`  | `https://continuumcode.ai/v1/models`           | Discover model IDs and capabilities |
| `POST` | `https://continuumcode.ai/v1/chat/completions` | OpenAI Chat Completions format      |
| `POST` | `https://continuumcode.ai/v1/messages`         | Anthropic Messages format           |
| `POST` | `https://continuumcode.ai/v1/responses`        | OpenAI Responses format             |

For OpenAI clients, set the base URL to `https://continuumcode.ai/v1`. For Anthropic clients that append `/v1/messages`, set it to `https://continuumcode.ai`, without `/v1`. These are compatibility endpoints; provider-specific features are not automatically supported.

## Authentication

Create an inference key in **Settings → Account → Inference API**. Keys start with `cont_sk_` and require the `inference:chat` scope. The value is shown once. Keep it in a server environment variable such as `CONTINUUM_API_KEY`; never put it in browser code or a public repository.

Send either `Authorization: Bearer YOUR_KEY` or `x-api-key: YOUR_KEY`. The latter supports Anthropic clients. Provider-issued keys, Computer API partner keys, and client tokens cannot authenticate these routes.

The app's managed `continuum-inference-key` credential uses this same inference surface. Its storage name is not a token or an HTTP header. Create a separate named key for your integration so you can revoke it independently.

## Models and effort

Fetch the catalog with your key before selecting a model:

```bash theme={"dark"}
curl --fail-with-body https://continuumcode.ai/v1/models \
  -H "Authorization: Bearer $CONTINUUM_API_KEY"
```

Read `data[].id` and `data[].capabilities`. Example model IDs in the hosted catalog include `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.6-luna`, `claude-fable-5-1`, `claude-sonnet-5`, and `grok-4.6`. Availability changes with your entitlement and configured capacity. Use exact returned IDs, without a `continuum/` prefix. Organization policy and spend controls still apply when you send a request.

For Chat Completions, set `reasoning_effort` to a value from that model's `capabilities.effort_variants`. The vocabulary is `minimal`, `low`, `medium`, `high`, `xhigh`, `max`, and `ultra`; each model supports only a subset. An empty array means omit effort. Unsupported values are clamped to the model's highest advertised effort, or omitted if it has none. Prefer an advertised value to avoid unexpected reasoning cost.

The Responses format uses `reasoning: { "effort": "high" }`. The current Anthropic bridge does not forward `thinking`, `output_config`, or `reasoning_effort`; use the OpenAI-compatible route when you need explicit effort control. Do not infer image support from a model name; inspect `capabilities.input_modalities`. The Messages bridge handles text and tool blocks, and does not translate image input.

## Request examples

Set `CONTINUUM_API_KEY` in your server environment. The examples use `gpt-5.6-sol` or `claude-sonnet-5`; substitute a model returned by your catalog. Set `stream` explicitly: Chat Completions currently defaults to streaming, while Messages defaults to a single JSON response.

### curl: OpenAI format

```bash theme={"dark"}
curl --fail-with-body https://continuumcode.ai/v1/chat/completions \
  -H "Authorization: Bearer $CONTINUUM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.6-sol",
    "messages": [{"role": "user", "content": "Write a short release note."}],
    "max_tokens": 1024,
    "stream": false
  }'
```

The response text is in `choices[0].message.content`.

### curl: Anthropic format

```bash theme={"dark"}
curl --fail-with-body https://continuumcode.ai/v1/messages \
  -H "x-api-key: $CONTINUUM_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-5",
    "max_tokens": 1024,
    "system": "Keep answers short.",
    "messages": [{"role": "user", "content": "Write a short release note."}],
    "stream": false
  }'
```

The response contains a `content` array of blocks, including text or tool use.

### Node.js

Save as `inference.mjs` and run with Node.js 20 or later. This uses built-in `fetch` and needs no package installation.

```javascript theme={"dark"}
const key = process.env.CONTINUUM_API_KEY;
if (!key) throw new Error("Set CONTINUUM_API_KEY");

const response = await fetch("https://continuumcode.ai/v1/chat/completions", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${key}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: "gpt-5.6-sol",
    messages: [{ role: "user", content: "Write a short release note." }],
    max_tokens: 1024,
    stream: false,
  }),
  signal: AbortSignal.timeout(120_000),
});
if (!response.ok) {
  throw new Error(`HTTP ${response.status}: ${await response.text()}`);
}
const result = await response.json();
console.log(result.choices[0].message.content);
```

### Python

Save as `inference.py` and run with Python 3. This uses the standard library and the Anthropic format.

```python theme={"dark"}
import json
import os
import urllib.error
import urllib.request

request = urllib.request.Request(
    "https://continuumcode.ai/v1/messages",
    method="POST",
    headers={
        "x-api-key": os.environ["CONTINUUM_API_KEY"],
        "anthropic-version": "2023-06-01",
        "Content-Type": "application/json",
    },
    data=json.dumps({
        "model": "claude-sonnet-5",
        "max_tokens": 1024,
        "messages": [{"role": "user", "content": "Write a short release note."}],
        "stream": False,
    }).encode("utf-8"),
)
try:
    with urllib.request.urlopen(request, timeout=120) as response:
        result = json.load(response)
except urllib.error.HTTPError as error:
    raise SystemExit(f"HTTP {error.code}: {error.read().decode('utf-8')}")

for block in result["content"]:
    if block["type"] == "text":
        print(block["text"])
```

## Streaming

Set `"stream": true` and use an SSE reader. With curl, add `--no-buffer` so output arrives as the server sends it.

| Format           | Stream                                                                                                                                          |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| Chat Completions | `data:` chunks with `choices[].delta`, followed by `data: [DONE]`                                                                               |
| Messages         | Named events including `message_start`, `content_block_start`, `content_block_delta`, `content_block_stop`, `message_delta`, and `message_stop` |

Treat network chunks as bytes, not complete events: buffer until the SSE event separator. Handle error events and a disconnected stream even after HTTP `200`. Do not treat partial output as a completed response or automatically replay a turn after executing tools.

## Tool calls

The model requests a tool; your application validates and executes it. The Inference API does not run your tool code.

For Chat Completions, send `tools` with function definitions and, optionally, `tool_choice` and `parallel_tool_calls`:

```json theme={"dark"}
{
  "tools": [{
    "type": "function",
    "function": {
      "name": "get_order",
      "description": "Read an order by ID",
      "parameters": {
        "type": "object",
        "properties": {"order_id": {"type": "string"}},
        "required": ["order_id"]
      }
    }
  }],
  "tool_choice": "auto"
}
```

Append the returned assistant message, including its `tool_calls`, to the next request. Return each result as a message with `role: "tool"`, the matching `tool_call_id`, and string `content`. In a stream, assemble argument deltas before parsing JSON.

For Messages, definitions use `name`, `description`, and `input_schema`. The assistant returns `tool_use` blocks; send the results in the following user message as `tool_result` blocks with the matching `tool_use_id`. The bridge supports this round trip. It does not provide Anthropic server-managed tools. Tool availability and forced tool selection also depend on the selected model.

## Errors and rate limits

Chat Completions gateway errors use `{"error":"code","detail":"optional explanation"}`. Messages errors use `{"type":"error","error":{"type":"authentication_error","message":"invalid_token"}}`, with a type appropriate to the status. Do not assume every error has the OpenAI SDK's nested error shape.

| HTTP  | Meaning                                                               | Action                                                                  |
| ----- | --------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| `400` | Invalid body, tool schema, or unapproved model                        | Fix the request; refresh the catalog for model errors                   |
| `401` | `invalid_token`                                                       | Check the key; replace expired or revoked keys                          |
| `402` | `subscription_required`                                               | Check your hosted inference entitlement                                 |
| `403` | `insufficient_scope`, `hosted_not_included`, or `model_not_permitted` | Check key scope, plan, and organization policy                          |
| `413` | Request body too large                                                | Reduce the body; the current limit is 10 MiB                            |
| `429` | `rate_limited`, upstream capacity limit, or exhausted spend budget    | Back off for rate limits; check funding or allocation for budget errors |
| `424` | Upstream dependency rejected the request                              | Read the detail; avoid an unbounded retry loop                          |
| `503` | Model or gateway capacity unavailable                                 | Retry with a bound or select another available model                    |

The current gateway limiter is shared per member across hosted completion routes: a burst capacity of 240 requests, refilling at 4 requests per second. This is a request limit, not a token allowance or a throughput guarantee. Upstream and spend limits can be lower. Honor `Retry-After` when present. The local `rate_limited` response does not currently include it; use bounded exponential backoff when it is absent. Budget errors such as `weekly_budget_exhausted` or `corporate_budget_exhausted` need an allowance reset, funding, or an allocation change rather than rapid retries.

## Pricing and plans

API usage draws from the same hosted inference allowance as the app. Standard monthly plans are:

| Plan    | Monthly price, USD | Included weekly budget, USD |
| ------- | ------------------ | --------------------------- |
| Plus    | \$25               | \$25                        |
| Max 100 | \$100              | \$100                       |
| Max 200 | \$200              | \$200                       |
| Ultra   | \$500              | \$1,000                     |

Eligible organization access can also include hosted inference. The account's active entitlement and organization controls determine access. Free hosted chat in the app does not by itself grant API key issuance.

Usage is metered by model and tokens. Paid usage beyond the included weekly budget draws from prepaid balance at pass-through model cost, subject to organization caps. These are spend budgets, not fixed token counts. Check Settings for your current allowance and billing terms; see [Hosted inference and billing](/docs/features/hosted-inference) for resets and overage.

Optional per-client attribution with `X-Continuum-Client` is upcoming with the [Computer API](/docs/apis/computer). It will retain the existing inference key and endpoints. Do not rely on that header for isolation or billing attribution until enabled for your partner.
