API
API reference
The cloud gateway and conifer serve answer the same wire. Everything below holds for both unless marked.
| Host | Base URL | Auth |
|---|---|---|
| Cloud | https://api.conifer.build | Authorization: Bearer $CONIFER_API_KEY |
conifer serve | http://127.0.0.1:8080 | none on loopback; any non-empty key satisfies clients that require one |
Bearer is the only accepted auth form. x-api-key headers get a 401.
curl https://api.conifer.build/v1/chat/completions \
-H "Authorization: Bearer $CONIFER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "conifer-swift",
"max_tokens": 1024,
"messages": [{"role": "user", "content": "three names for a build cache"}]
}'Routes
| Route | Wire | Notes |
|---|---|---|
POST /v1/chat/completions | OpenAI chat | Every model, including Conifer's own. |
POST /v1/messages | Anthropic Messages | Anthropic model ids only. Prompt caching and live streaming ride this route. |
POST /v1/messages/count_tokens | Anthropic | Token counting. Local door only today. |
POST /v1/responses | OpenAI Responses | Stateless tool loop. What Codex speaks. |
GET /v1/models | OpenAI | The catalog your key can call, with prices. |
GET /v1/balance | Conifer | Your balance, integers. Cloud only. |
GET /health | Conifer | Liveness and served planes. Local door only. |
Parameters
| Field | Behavior |
|---|---|
model | An exact id from GET /v1/models. Unknown ids are refused by name, never served as something else. |
max_tokens | Optional on the chat wire (the server applies 4096). Required on /v1/messages. Conifer models enforce a per-model minimum; a too-small cap is a 400, not a truncated answer. |
stream | Accepted everywhere; see streaming below. |
tools | Passed through. Check the model's caps field on the catalog first. |
Streaming
stream: true always returns well-formed SSE. On /v1/messages, tokens arrive live. On the chat and Responses wires, most models currently deliver the completion as one burst at the end. Do not build a UI on incremental token timing there. On streams, the cost arrives as a terminal conifer_receipt event instead of a header.
Time bounds
A buffered call gets about 280 seconds. A stream is bounded by idle time (120 seconds between frames), not total time. For very long outputs, stream or split the request.
Receipt headers
Every cloud response carries its accounting:
| Header | Meaning |
|---|---|
x-conifer-requested-model | What you asked for. |
x-conifer-effective-model | The exact model that served the admitted request. |
x-conifer-receipt-reason | Opaque execution detail from the deciding native hop. |
x-conifer-cost-nanousd | The settled cost of this request, in nanodollars (1e-9 USD). |
One request header goes the other way: x-conifer-max-cost-nanousd sets a hard cost ceiling. A request whose worst case exceeds it is refused with a 402 before anything runs.
Prompt caching
Send cache_control breakpoints on /v1/messages; they pass through to the model unchanged. The response reports cache_read_input_tokens and cache_creation_input_tokens, billed at the cache rates on the catalog. The chat wire cannot carry cache directives. Nothing is ever cached on your behalf.
Errors
| Status | Meaning |
|---|---|
| 400 | The request itself. The body names the problem: a prompt over the model's context window, a cap under the model's floor, a non-Anthropic id on /v1/messages (wire_upstream_mismatch). |
| 401 | Auth. Bearer missing, malformed, expired, or revoked. |
| 402 | insufficient_allowance: billing isn’t set up or the balance can’t cover the worst case. Billing & caching covers it. |
| 404 | model_not_found. The id isn't in your catalog; on a pinned local door, anything but the served model. |
| 501 | Local thin builds only: an engine-only route on a machine with no engine. |