Using the API
Compatible endpoints
Point OpenAI and Anthropic clients at Snaga — chat completions and responses run your agents; the Messages API reaches the model catalogue.
Plenty of software already speaks the OpenAI or Anthropic API. Rather than
asking you to rewrite it, Snaga answers those shapes at
https://api.snaga.ai/v1/…, with your Snaga API key. The difference that
matters is what sits behind each route:
| Route | Behind it |
|---|---|
POST /v1/chat/completions | one of your agents, as a run |
POST /v1/responses, GET /v1/responses/{responseId} | one of your agents, as a run |
GET /v1/models | your agents, listed as models |
POST /v1/embeddings | the platform's embedding model |
POST /v1/messages, POST /v1/messages/count_tokens | the platform's model catalogue, not an agent |
These routes run in the key's own company. Naming another company with
X-Active-Tenant is refused with 400 — create a key in that company instead.
OpenAI-compatible
Chat completions → an agent run
The model field names the agent: its id, or agent/<agent_id>. The request
becomes a run of that agent. A system message you send is treated as your
instruction for this call and delivered with your last message; the agent's
own system prompt stays.
curl https://api.snaga.ai/v1/chat/completions \
-H "Authorization: Bearer $SNAGA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "agent/<agent_id>",
"messages": [{"role": "user", "content": "What changed in the pipeline this week?"}]
}'
The answer is a chat.completion with exactly one choice, whose
finish_reason is stop or error, and a usage block. With
"stream": true it arrives as text/event-stream chunks ending in
data: [DONE]. Also accepted: temperature, max_tokens, tools and
tool_choice.
The same call from the OpenAI Python SDK:
from openai import OpenAI
client = OpenAI(base_url="https://api.snaga.ai/v1", api_key="<your Snaga API key>")
reply = client.chat.completions.create(
model="agent/<agent_id>",
messages=[{"role": "user", "content": "What changed in the pipeline this week?"}],
)
print(reply.choices[0].message.content)
Models
GET /v1/models lists your company's agents in the OpenAI model-list shape,
with the agent's name in display_name — inactive agents included. Teams
appear in the same list with ids of the form team/<team_id>. Use an agent's
id as model.
Responses
POST /v1/responses takes model (an agent id) and input. Chain a
conversation with previous_response_id: that response and everything before
it become this call's history; an id that is not a response in your company is
404. instructions apply to this call only. GET /v1/responses/{responseId}
reads one back — the id is the run id, and a run still in progress has empty
text.
Embeddings
POST /v1/embeddings always uses the platform-configured model, whatever
model you send; the answer's model names it. Each input is embedded on its
own and reports input_tokens and truncated — long texts are cut, never
refused. A 501 means embeddings are switched off on this deployment; do not
retry it.
Errors
These routes answer errors in the OpenAI envelope, {"error": {"message", "type", "code"}}, because that is what OpenAI SDKs decode.
Anthropic-compatible
POST /v1/messages accepts the Anthropic Messages API for Anthropic clients
pointed at this base URL. It is not an agent run: the request goes to the
platform's model proxy, so your plan's model access and its daily, hourly and
per-minute limits apply. The key needs both runs:create and agents:read
and a developer role or higher.
The key may be sent as x-api-key (read when there is no Authorization
header) or as a Bearer token.
curl https://api.snaga.ai/v1/messages \
-H "x-api-key: $SNAGA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "<provider>/<model>",
"max_tokens": 512,
"messages": [{"role": "user", "content": "Hello"}]
}'
model, max_tokens and messages are required. A claude-* id is served by
the model the platform has configured for this route; any other id is looked
up in the model catalogue as <provider>/<model>.
What is read: system, tools with tool_choice, temperature, top_p,
stop_sequences, stream and metadata. In messages, text, image,
tool_use and tool_result blocks are read; a document block is replaced by
a placeholder and thinking blocks are dropped. Other fields are accepted and
ignored.
With "stream": true the answer is the Anthropic event stream:
message_start, content_block_start / content_block_delta /
content_block_stop, message_delta, message_stop, with ping frames
while a reasoning model thinks. A streamed and a non-streamed request get the
same time budget.
POST /v1/messages/count_tokens returns input_tokens as an estimate —
about four characters per token — without calling any model or spending
anything.
Errors mostly use the Anthropic envelope (invalid_request_error,
permission_error, billing_error, rate_limit_error, api_error). A
missing scope or role, an oversized body and the per-key rate limit answer in
the platform's problem document instead; see
Requests and errors.
Related
- Agents — what answers behind
/v1/chat/completions. - Usage and limits — the limits
/v1/messagesdraws on. - API reference — the full request and response shapes.