Skip to main content
Browse the documentation

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:

RouteBehind it
POST /v1/chat/completionsone of your agents, as a run
POST /v1/responses, GET /v1/responses/{responseId}one of your agents, as a run
GET /v1/modelsyour agents, listed as models
POST /v1/embeddingsthe platform's embedding model
POST /v1/messages, POST /v1/messages/count_tokensthe 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.