Coral Inference API
OpenAI-compatible inference for chat, interactive agents, and long-running autonomous agents. One API key, three surfaces, open models.
Coral Bricks runs open models against the OpenAI wire format. Point your
existing OpenAI SDK at the Coral gateway and you get three progressively
more powerful surfaces:
- Chat Completions — turn-based chat. Client owns the conversation.
- Responses — stateful, interactive agents. Server carries reasoning
and thread state across turns.
- Responses in background mode — autonomous agents that run for
minutes to tens of minutes, headless. Fire-and-poll, resumable
streams, no HTTP hold.
Same auth. Same model ids. Same SDK. Choose the surface that matches the
shape of your workload.
Coral Inference is currently a design-partner program. To get access,
contact us at hello@coralbricks.ai.
Building with a coding agent? This page is served as raw markdown at
https://www.coralbricks.ai/docs.md.
A machine-readable site index lives at /llms.txt, and the
complete docs in one file at /llms-full.txt.
Using OpenCode, Cursor, Cline, or Claude Code? One config stanza (or
one click) routes their agent loops through Coral — see the setup guides
for OpenCode, Cursor,
Cline, Claude Code, and
Kilo Code.
Coding agent setup guides
Point your coding agent at Coral with one config change:
- OpenCode — open-source, multi-provider terminal agent
- Cline — VS Code extension for autonomous coding
- Claude Code — Anthropic's terminal coding agent
- Kilo Code — open-source VS Code agent
Which API should I use?
| Your workload |
Use |
Why |
| Turn-based chat, single-shot generation, you already have OpenAI Chat code |
Chat Completions |
Stateless per request. Drop-in for any Chat Completions client. |
| Multi-step interactive agent, tool use, reasoning that should carry across turns, a human is waiting |
Responses |
Server-side state via previous_response_id. Reasoning preserved between turns — measurably better on reasoning models. |
| Long-running headless agent, runs in CI / cron / a cloud box / a coding agent, no human waiting on the socket |
Responses (background) |
Fire-and-poll. Resumable streams. Survives caller death, network drops, and multi-minute runs. |
All three share the same base URL (https://inference.coralbricks.ai/v1),
the same API key, and the same model ids.
Authentication
Every request needs:
Authorization: Bearer <CORAL_API_KEY>
- Mint and rotate keys at /api-keys. Keys look like
cb_… (older ak_… keys remain valid).
- Keep keys server-side. Never embed in a browser bundle or a mobile
app — anyone with the key can spend against your account.
- Newly-minted keys may take up to ~30 seconds to be honoured.
Access to the Coral Inference API is gated per-account. If you see
403 access_denied, your account hasn't been granted yet — contact us.
Models
| Model |
Description |
Status |
glm-5.2-fp4 |
Zhipu's GLM 5.2, FP4 weights |
available |
gpt-oss-120b |
OpenAI's open-weight 120B MoE |
available |
kimi-k3 |
Moonshot AI's Kimi K3 |
available |
Pass the model id verbatim as the model field on any request. The
exact set enabled for your key is also available programmatically:
curl -sS https://inference.coralbricks.ai/v1/models \
-H "Authorization: Bearer $CORAL_API_KEY"
The same model ids work across Chat Completions, Responses, and
background mode.
Pricing and cached input
Per-model rates are on the pricing page. Cached input tokens
are free — a prefix that is already resident is billed at $0, on every
model and both APIs, with no cache-management flags to set. Agent loops
that re-send a growing conversation each turn benefit most: the repeated
prefix costs nothing after the first turn.
Cached tokens are reported per response so you can verify the discount:
"usage": {
"prompt_tokens": 20767,
"prompt_tokens_details": { "cached_tokens": 20032 },
"completion_tokens": 246
}
1. Chat Completions
Turn-based chat. Stateless per request — you send the full message
history on every call, and the server returns one assistant turn. The
foundational OpenAI-compatible chat endpoint, unchanged from what your
existing SDK expects.
Use when: you already have working chat.completions code, you're
generating a single response, or you don't need the server to remember
anything about the conversation.
POST /v1/chat/completions
curl -sS -X POST https://inference.coralbricks.ai/v1/chat/completions \
-H "Authorization: Bearer $CORAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-oss-120b",
"messages": [
{"role": "system", "content": "You are a careful research assistant."},
{"role": "user", "content": "What are the key metrics to watch for a Series A SaaS company?"}
]
}'
Streaming is supported the OpenAI way — pass stream: true and consume
the SSE. Tool calling (tools / tool_choice) works the same as
upstream. Background mode is not available on this endpoint — use
/v1/responses for that.
from openai import OpenAI
client = OpenAI(base_url="https://inference.coralbricks.ai/v1", api_key="cb_...")
resp = client.chat.completions.create(
model="gpt-oss-120b",
messages=[
{"role": "system", "content": "You are a careful research assistant."},
{"role": "user", "content": "Explain KV attention in one paragraph."},
],
)
print(resp.choices[0].message.content)
2. Responses — interactive agents
Stateful. The server holds reasoning and conversation state between
turns, so subsequent calls can reference an earlier response by id
instead of resending the full history. This preserves the model's
reasoning context across turns, which measurably improves multi-step
tool-using agents.
Use when: you're building an interactive agent — multi-step tool
calling, iterative reasoning, threaded conversation — and a human (or
an upstream agent) is waiting on the reply. Timescale: seconds.
POST /v1/responses
curl -sS -X POST https://inference.coralbricks.ai/v1/responses \
-H "Authorization: Bearer $CORAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-oss-120b",
"input": "Sketch a plan to refactor the auth module."
}'
Follow-up turns pass previous_response_id to continue the thread. The
server carries state; you don't have to replay the transcript:
first = client.responses.create(
model="gpt-oss-120b",
input="Sketch a plan to refactor the auth module.",
)
# Same thread, no history replay needed.
next_turn = client.responses.create(
model="gpt-oss-120b",
input="OK, now do step 1 in detail.",
previous_response_id=first.id,
)
print(next_turn.output_text)
| Field |
Type |
Notes |
model |
string |
Required. One of the ids from GET /v1/models. |
input |
string or array |
Required. Same shape as OpenAI Responses. |
instructions |
string |
Optional system / developer instructions. |
previous_response_id |
string |
Continues an existing thread. Sticky-routed back to the same replica for locality. |
stream |
boolean |
When true, SSE stream of Responses events. |
| ...other OpenAI fields |
|
Forwarded verbatim. |
GET /v1/responses/{id}
Retrieve any prior response by id — useful for auditing, resuming a
UI after a page reload, or re-hydrating a thread from persistent
storage. Also serves stream resumption (see background mode).
curl -sS https://inference.coralbricks.ai/v1/responses/$RESPONSE_ID \
-H "Authorization: Bearer $CORAL_API_KEY"
DELETE /v1/responses/{id}
Delete a stored response.
3. Responses in background mode — autonomous agents
Same endpoint as above, plus one flag: background: true. The call
returns immediately with a response id and status: "queued". The
model then runs on Coral's cluster — not on your socket — for as long
as the work takes. You poll (or resume the stream) on your own cadence.
Use when: the caller is not a human at a chat window. Long-running
research loops, coding agents, batch pipelines, CI jobs, cron tasks,
overnight runs. Timescale: minutes to tens of minutes. Nobody is
waiting on the next token.
Why the shape matters for autonomous agents:
- No HTTP hold. The socket closes when
create returns. No proxy
timeouts, no keepalive plumbing, no reconnect logic.
- Survives caller death. If your agent process crashes or your CI
runner is preempted, the response keeps running server-side. A fresh
process retrieves by id and gets the completed result.
- Resumable streams. If you were streaming and the socket dropped,
a
GET /v1/responses/{id}?stream=true from any process picks up
where you left off.
- Location-independent. Kick off from your laptop, poll from a
Lambda, render in a Slack bot. One id, three consumers.
POST /v1/responses (with background: true)
curl -sS -X POST https://inference.coralbricks.ai/v1/responses \
-H "Authorization: Bearer $CORAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-oss-120b",
"input": "Plan a 5-step refactor for the attached repo, then execute step 1.",
"background": true
}'
{
"id": "resp_01HXY…",
"object": "response",
"status": "queued",
"model": "gpt-oss-120b"
}
GET /v1/responses/{id} (polling)
The status moves through queued → in_progress → completed | failed | cancelled. Poll on any cadence you like.
import time
queued = client.responses.create(
model="gpt-oss-120b",
input="Run the full research loop. Take your time.",
background=True,
)
while True:
current = client.responses.retrieve(queued.id)
if current.status in ("completed", "failed", "cancelled"):
break
time.sleep(5)
print(current.output_text)
POST /v1/responses/{id}/cancel
Cooperative cancel of an in-progress background response. Queued
responses flip to cancelled synchronously.
curl -sS -X POST https://inference.coralbricks.ai/v1/responses/$RESPONSE_ID/cancel \
-H "Authorization: Bearer $CORAL_API_KEY"
Stream + background
You can combine stream: true with background: true. The initial
call returns an SSE stream that you can consume; if the socket drops or
you want a second consumer, GET /v1/responses/{id}?stream=true picks
up from where the last event left off. Useful when the agent loop and
the renderer live on different machines.
Streaming
Every surface supports OpenAI-shape SSE streaming via stream: true.
Consume it exactly as you would from OpenAI's SDK. See the background
section above for stream resumption via GET.
Errors
Errors follow the OpenAI error shape:
{"error": {"message": "…", "type": "…", "code": "…"}}
| Status |
code |
Meaning |
400 |
bad_request / model_required |
Malformed body or missing required field. |
401 |
missing_api_key / invalid_api_key |
Auth header absent or rejected. Re-mint at /api-keys. |
403 |
access_denied |
Account isn't on the Coral Inference allowlist — contact us. |
404 |
model_not_accepted |
The model id isn't enabled for your account or doesn't match a known id. |
404 |
response_not_found |
Wrong response_id, or it belongs to another account. |
429 |
rate_limit_exceeded |
Per-API-key rate limit. Slow down and retry with backoff. |
502 |
upstream_error |
Upstream model server returned an error. Safe to retry. |
503 |
backend_unconfigured |
Transient. Retry. |
504 |
timeout |
Sync request waited too long. Re-issue with background: true. |
Limits
Rate, concurrency, and context-length limits are set per API key and
account. The defaults fit a single interactive agent or a single
background loop comfortably. If you're fanning out (multiple
background agents in parallel, a batch pipeline, a coding agent that
spawns sub-agents), talk to us so we can raise the cap on your key.
Support