OpenAI-compatible API
OdinClaw implements the OpenAI REST API format. Change your base_url and API key — nothing else. This page documents the supported endpoints, supported request fields on /chat/completions, and honest limitations.
Base URL and authentication
https://api.claw.odin-labs.ai/v1Authorization: Bearer YOUR_API_KEYcurl https://api.claw.odin-labs.ai/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ODINCLAW_API_KEY" \
-d '{
"model": "deepseek-v3",
"messages": [{"role": "user", "content": "Hello"}]
}'import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["ODINCLAW_API_KEY"],
base_url="https://api.claw.odin-labs.ai/v1",
)
response = client.chat.completions.create(
model="deepseek-v3",
messages=[{"role": "user", "content": "Hello"}],
)
print(response.choices[0].message.content)import OpenAI from 'openai';
const client = new OpenAI({
apiKey: process.env.ODINCLAW_API_KEY,
baseURL: 'https://api.claw.odin-labs.ai/v1',
});
const response = await client.chat.completions.create({
model: 'deepseek-v3',
messages: [{ role: 'user', content: 'Hello' }],
});
console.log(response.choices[0].message.content);Supported endpoints
| Method | Endpoint | Status |
|---|---|---|
| POST | /v1/chat/completions | Supported |
| GET | /v1/models | Supported |
| POST | /v1/embeddings | Supported |
| POST | /v1/completions | Partial |
| POST | /v1/images/generations | Not supported |
| POST | /v1/audio/transcriptions | Not supported |
| POST | /v1/audio/speech | Not supported |
| POST | /v1/fine_tuning/jobs | Not supported |
/chat/completions — supported fields
All fields in the OpenAI chat completions request body. OdinClaw passes supported fields through to the underlying model provider; unsupported fields are silently dropped (never error on unknown fields).
| Field | Status |
|---|---|
model | Yes |
messages | Yes |
temperature | Yes |
max_tokens | Yes |
stream | Yes |
top_p | Yes |
stop | Yes |
n | Yes |
tools | Yes |
tool_choice | Yes |
response_format | Yes |
seed | No |
logprobs | No |
top_logprobs | No |
user | No |
presence_penalty | No |
frequency_penalty | No |
Streaming
Set stream: true (or stream=True in Python) to receive server-sent events (SSE). The chunk format is identical to OpenAI's streaming response — each chunk contains choices[].delta.content and is terminated by [DONE].
stream = client.chat.completions.create(
model="deepseek-v3",
messages=[{"role": "user", "content": "Write a haiku about the EU."}],
stream=True,
)
for chunk in stream:
delta = chunk.choices[0].delta.content
if delta:
print(delta, end="", flush=True)Tool use / function calling
Tool-use follows the OpenAI tool-calling schema. Pass tools as an array of function definitions. Supported on DeepSeek V3, Gemini 2.5 Flash, and Claude models. Not yet available on all models — check the model page for per-model capability flags.
tools = [
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "Get the weather for a city",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "City name"},
},
"required": ["city"],
},
},
}
]
response = client.chat.completions.create(
model="deepseek-v3",
messages=[{"role": "user", "content": "What's the weather in Berlin?"}],
tools=tools,
tool_choice="auto",
)
tool_call = response.choices[0].message.tool_calls[0]
print(tool_call.function.name) # get_current_weather
print(tool_call.function.arguments) # {"city": "Berlin"}What is NOT supported
Honest limitations. We prefer to document gaps over hiding them.
Known issues
Tool-use streaming varies by model
Tool-call events in streaming mode follow the OpenAI chunk format, but the granularity of argument streaming differs across providers. DeepSeek V3 and Claude stream tool-arguments token-by-token; Gemini Flash may emit the full argument JSON in a single chunk. Parse with index-based chunk accumulation, not line-based.
"model" field in response may differ from request
The response.model field reflects the provider's internal model identifier, which may not exactly match the OdinClaw model ID you sent. Do not use response.model for billing attribution — use the OdinClaw request ID from the x-request-id response header.
Rate limits are per-tier, not per-model
OdinClaw rate limits are applied at the gateway tier level, not per-model. If you're on the free tier and hit the limit, switching model IDs in the same request will not help — the request will still be rate-limited.
context_length_exceeded error shape
OdinClaw returns a 400 with error.code "context_length_exceeded" and error.type "invalid_request_error" when your prompt exceeds the model's context window. The exact message is provider-forwarded and may not be identical to OpenAI's wording — do not pattern-match on the exact message string.
Available models
Use GET /v1/models to fetch the current list programmatically. The full model registry with per-model pricing, context window, and capability flags is at /models.
deepseek-v3gemini-2.5-flashclaude-3-5-haikullama-3.3-70bFull list at /models. Model IDs and availability change — use GET /v1/models for the live list.
Ready to start?
Free tier — 100K tokens per month, no credit card, hard spend cap at €0. Get your API key in under 60 seconds.