diff --git a/docs/api-reference.md b/docs/api-reference.md
index 684941455..0fe5c5a46 100644
--- a/docs/api-reference.md
+++ b/docs/api-reference.md
@@ -145,6 +145,149 @@ GET /api/v1/websites/{domain}/urls
## Platform API
-The Platform service exposes a public API at `/api/v1/*` for programmatic access to your data. Authenticate using an `x-api-key` header with a key from Settings > API Keys.
+The Platform service exposes a public API at `/api/v1/*` for programmatic access to your data. Authenticate using an API key from **Settings > API Keys**.
-Full API documentation: `https://yourdomain.com/api/v1/openapi.json`
+### OpenAI-compatible chat completions
+
+The platform provides an interface fully compatible with the [OpenAI Chat Completions API](https://platform.openai.com/docs/api-reference/chat). Any client or SDK that supports OpenAI (Python, Node, curl, LiteLLM, etc.) can connect by pointing `base_url` to your Tale instance.
+
+#### Quick start
+
+
+
+```python Python
+from openai import OpenAI
+
+client = OpenAI(
+ base_url="https://your-tale-instance.com/api/v1",
+ api_key="tale_...", # from Settings > API Keys
+ default_headers={"X-Organization-Slug": "default"},
+)
+
+response = client.chat.completions.create(
+ model="chat-agent", # agent slug from your Agents page
+ messages=[{"role": "user", "content": "Hello!"}],
+)
+print(response.choices[0].message.content)
+```
+
+```typescript Node.js
+import OpenAI from "openai";
+
+const client = new OpenAI({
+ baseURL: "https://your-tale-instance.com/api/v1",
+ apiKey: "tale_...",
+ defaultHeaders: { "X-Organization-Slug": "default" },
+});
+
+const response = await client.chat.completions.create({
+ model: "chat-agent",
+ messages: [{ role: "user", content: "Hello!" }],
+});
+console.log(response.choices[0].message.content);
+```
+
+```bash curl
+curl https://your-tale-instance.com/api/v1/chat/completions \
+ -H "Authorization: Bearer tale_..." \
+ -H "X-Organization-Slug: default" \
+ -H "Content-Type: application/json" \
+ -d '{"model":"chat-agent","messages":[{"role":"user","content":"Hello!"}]}'
+```
+
+
+
+#### Authentication
+
+All requests require a Bearer token in the `Authorization` header:
+
+```text
+Authorization: Bearer tale_...
+```
+
+Create API keys in **Settings > API Keys** in the platform UI.
+
+#### Headers
+
+| Header | Required | Description |
+| --- | --- | --- |
+| `Authorization` | Yes | `Bearer ` |
+| `X-Organization-Slug` | No | Organization slug. Auto-resolved if user belongs to one org. |
+| `X-Thread-Id` | No | Reuse a conversation thread across requests. |
+
+#### Endpoints
+
+##### POST /api/v1/chat/completions
+
+Send a chat message and receive a response. Supports streaming and tool calling.
+
+**Request body:**
+
+| Field | Type | Description |
+| --- | --- | --- |
+| `model` | string | **Required.** Agent slug (e.g., `chat-agent`). |
+| `messages` | array | **Required.** Conversation messages with `role` and `content`. |
+| `stream` | boolean | Enable SSE streaming. Default: `false`. |
+| `temperature` | number | Sampling temperature (0–2). |
+| `max_tokens` | number | Maximum tokens to generate. |
+| `top_p` | number | Nucleus sampling parameter. |
+| `frequency_penalty` | number | Penalize repeated tokens. |
+| `presence_penalty` | number | Penalize tokens already present. |
+| `stop` | string or array | Stop sequences. |
+| `response_format` | object | Set `{"type": "json_object"}` for JSON mode. |
+| `tools` | array | Tool definitions for client-side tool calling. |
+| `tool_choice` | string or object | `"auto"`, `"required"`, `"none"`, or `{"type":"function","function":{"name":"..."}}`. |
+
+**Two modes:**
+
+- **Agent mode** (no `tools`): The agent uses its pre-configured server-side tools (RAG, web search, etc.) and auto-executes them. The response contains the final text.
+- **Client tool mode** (`tools` provided): Only the client-defined tools are available. The model returns `tool_calls` for the client to execute. Send results back with `role: "tool"` messages.
+
+**Tool calling example:**
+
+```python
+# Step 1: send tools
+response = client.chat.completions.create(
+ model="chat-agent",
+ messages=[{"role": "user", "content": "What's the weather?"}],
+ tools=[{
+ "type": "function",
+ "function": {
+ "name": "get_weather",
+ "description": "Get weather for a city",
+ "parameters": {
+ "type": "object",
+ "properties": {"city": {"type": "string"}},
+ "required": ["city"],
+ },
+ },
+ }],
+ tool_choice="required",
+)
+
+# Step 2: execute tool and send result
+tc = response.choices[0].message.tool_calls[0]
+messages = [
+ {"role": "user", "content": "What's the weather?"},
+ response.choices[0].message.model_dump(),
+ {"role": "tool", "tool_call_id": tc.id, "content": '{"temp": 20}'},
+]
+final = client.chat.completions.create(
+ model="chat-agent", messages=messages, tools=tools
+)
+print(final.choices[0].message.content)
+```
+
+##### GET /api/v1/models
+
+List available agents (models).
+
+```json
+{
+ "object": "list",
+ "data": [
+ {"id": "chat-agent", "object": "model", "owned_by": "default"},
+ {"id": "workflow-assistant", "object": "model", "owned_by": "default"}
+ ]
+}
+```
diff --git a/package.json b/package.json
index d7d8defbd..61ac5e6b0 100644
--- a/package.json
+++ b/package.json
@@ -68,7 +68,7 @@
"esbuild"
],
"patchedDependencies": {
- "convex-helpers@0.1.113": "patches/convex-helpers@0.1.113.patch"
+ "convex-helpers@0.1.114": "patches/convex-helpers@0.1.114.patch"
},
"overrides": {
"react-is": "19.2.5",
diff --git a/patches/convex-helpers@0.1.113.patch b/patches/convex-helpers@0.1.114.patch
similarity index 100%
rename from patches/convex-helpers@0.1.113.patch
rename to patches/convex-helpers@0.1.114.patch
diff --git a/services/platform/app/routes/docs.tsx b/services/platform/app/routes/docs.tsx
index b9130a172..8fbbcc043 100644
--- a/services/platform/app/routes/docs.tsx
+++ b/services/platform/app/routes/docs.tsx
@@ -64,6 +64,13 @@ function ApiDocsPage() {