| --- |
| summary: "Expose an OpenResponses-compatible /v1/responses HTTP endpoint from the Gateway" |
| read_when: |
| - Integrating clients that speak the OpenResponses API |
| - You want item-based inputs, client tool calls, or SSE events |
| title: "OpenResponses API" |
| --- |
| |
| # OpenResponses API (HTTP) |
|
|
| OpenClaw’s Gateway can serve an OpenResponses-compatible `POST /v1/responses` endpoint. |
|
|
| This endpoint is **disabled by default**. Enable it in config first. |
|
|
| - `POST /v1/responses` |
| - Same port as the Gateway (WS + HTTP multiplex): `http://<gateway-host>:<port>/v1/responses` |
|
|
| Under the hood, requests are executed as a normal Gateway agent run (same codepath as |
| `openclaw agent`), so routing/permissions/config match your Gateway. |
|
|
| ## Authentication, security, and routing |
|
|
| Operational behavior matches [OpenAI Chat Completions](/gateway/openai-http-api): |
|
|
| - use `Authorization: Bearer <token>` with the normal Gateway auth config |
| - treat the endpoint as full operator access for the gateway instance |
| - select agents with `model: "openclaw:<agentId>"`, `model: "agent:<agentId>"`, or `x-openclaw-agent-id` |
| - use `x-openclaw-session-key` for explicit session routing |
|
|
| Enable or disable this endpoint with `gateway.http.endpoints.responses.enabled`. |
|
|
| ## Session behavior |
|
|
| By default the endpoint is **stateless per request** (a new session key is generated each call). |
|
|
| If the request includes an OpenResponses `user` string, the Gateway derives a stable session key |
| from it, so repeated calls can share an agent session. |
|
|
| ## Request shape (supported) |
|
|
| The request follows the OpenResponses API with item-based input. Current support: |
|
|
| - `input`: string or array of item objects. |
| - `instructions`: merged into the system prompt. |
| - `tools`: client tool definitions (function tools). |
| - `tool_choice`: filter or require client tools. |
| - `stream`: enables SSE streaming. |
| - `max_output_tokens`: best-effort output limit (provider dependent). |
| - `user`: stable session routing. |
|
|
| Accepted but **currently ignored**: |
|
|
| - `max_tool_calls` |
| - `reasoning` |
| - `metadata` |
| - `store` |
| - `previous_response_id` |
| - `truncation` |
|
|
| ## Items (input) |
|
|
| ### `message` |
|
|
| Roles: `system`, `developer`, `user`, `assistant`. |
|
|
| - `system` and `developer` are appended to the system prompt. |
| - The most recent `user` or `function_call_output` item becomes the “current message.” |
| - Earlier user/assistant messages are included as history for context. |
|
|
| ### `function_call_output` (turn-based tools) |
|
|
| Send tool results back to the model: |
|
|
| ```json |
| { |
| "type": "function_call_output", |
| "call_id": "call_123", |
| "output": "{\"temperature\": \"72F\"}" |
| } |
| ``` |
|
|
| ### `reasoning` and `item_reference` |
| |
| Accepted for schema compatibility but ignored when building the prompt. |
| |
| ## Tools (client-side function tools) |
| |
| Provide tools with `tools: [{ type: "function", function: { name, description?, parameters? } }]`. |
| |
| If the agent decides to call a tool, the response returns a `function_call` output item. |
| You then send a follow-up request with `function_call_output` to continue the turn. |
|
|
| ## Images (`input_image`) |
| |
| Supports base64 or URL sources: |
| |
| ```json |
| { |
| "type": "input_image", |
| "source": { "type": "url", "url": "https://example.com/image.png" } |
| } |
| ``` |
| |
| Allowed MIME types (current): `image/jpeg`, `image/png`, `image/gif`, `image/webp`, `image/heic`, `image/heif`. |
| Max size (current): 10MB. |
| |
| ## Files (`input_file`) |
| |
| Supports base64 or URL sources: |
| |
| ```json |
| { |
| "type": "input_file", |
| "source": { |
| "type": "base64", |
| "media_type": "text/plain", |
| "data": "SGVsbG8gV29ybGQh", |
| "filename": "hello.txt" |
| } |
| } |
| ``` |
| |
| Allowed MIME types (current): `text/plain`, `text/markdown`, `text/html`, `text/csv`, |
| `application/json`, `application/pdf`. |
|
|
| Max size (current): 5MB. |
|
|
| Current behavior: |
|
|
| - File content is decoded and added to the **system prompt**, not the user message, |
| so it stays ephemeral (not persisted in session history). |
| - PDFs are parsed for text. If little text is found, the first pages are rasterized |
| into images and passed to the model. |
|
|
| PDF parsing uses the Node-friendly `pdfjs-dist` legacy build (no worker). The modern |
| PDF.js build expects browser workers/DOM globals, so it is not used in the Gateway. |
|
|
| URL fetch defaults: |
|
|
| - `files.allowUrl`: `true` |
| - `images.allowUrl`: `true` |
| - `maxUrlParts`: `8` (total URL-based `input_file` + `input_image` parts per request) |
| - Requests are guarded (DNS resolution, private IP blocking, redirect caps, timeouts). |
| - Optional hostname allowlists are supported per input type (`files.urlAllowlist`, `images.urlAllowlist`). |
| - Exact host: `"cdn.example.com"` |
| - Wildcard subdomains: `"*.assets.example.com"` (does not match apex) |
|
|
| ## File + image limits (config) |
|
|
| Defaults can be tuned under `gateway.http.endpoints.responses`: |
|
|
| ```json5 |
| { |
| gateway: { |
| http: { |
| endpoints: { |
| responses: { |
| enabled: true, |
| maxBodyBytes: 20000000, |
| maxUrlParts: 8, |
| files: { |
| allowUrl: true, |
| urlAllowlist: ["cdn.example.com", "*.assets.example.com"], |
| allowedMimes: [ |
| "text/plain", |
| "text/markdown", |
| "text/html", |
| "text/csv", |
| "application/json", |
| "application/pdf", |
| ], |
| maxBytes: 5242880, |
| maxChars: 200000, |
| maxRedirects: 3, |
| timeoutMs: 10000, |
| pdf: { |
| maxPages: 4, |
| maxPixels: 4000000, |
| minTextChars: 200, |
| }, |
| }, |
| images: { |
| allowUrl: true, |
| urlAllowlist: ["images.example.com"], |
| allowedMimes: [ |
| "image/jpeg", |
| "image/png", |
| "image/gif", |
| "image/webp", |
| "image/heic", |
| "image/heif", |
| ], |
| maxBytes: 10485760, |
| maxRedirects: 3, |
| timeoutMs: 10000, |
| }, |
| }, |
| }, |
| }, |
| }, |
| } |
| ``` |
|
|
| Defaults when omitted: |
|
|
| - `maxBodyBytes`: 20MB |
| - `maxUrlParts`: 8 |
| - `files.maxBytes`: 5MB |
| - `files.maxChars`: 200k |
| - `files.maxRedirects`: 3 |
| - `files.timeoutMs`: 10s |
| - `files.pdf.maxPages`: 4 |
| - `files.pdf.maxPixels`: 4,000,000 |
| - `files.pdf.minTextChars`: 200 |
| - `images.maxBytes`: 10MB |
| - `images.maxRedirects`: 3 |
| - `images.timeoutMs`: 10s |
| - HEIC/HEIF `input_image` sources are accepted and normalized to JPEG before provider delivery. |
|
|
| Security note: |
|
|
| - URL allowlists are enforced before fetch and on redirect hops. |
| - Allowlisting a hostname does not bypass private/internal IP blocking. |
| - For internet-exposed gateways, apply network egress controls in addition to app-level guards. |
| See [Security](/gateway/security). |
|
|
| ## Streaming (SSE) |
|
|
| Set `stream: true` to receive Server-Sent Events (SSE): |
|
|
| - `Content-Type: text/event-stream` |
| - Each event line is `event: <type>` and `data: <json>` |
| - Stream ends with `data: [DONE]` |
|
|
| Event types currently emitted: |
|
|
| - `response.created` |
| - `response.in_progress` |
| - `response.output_item.added` |
| - `response.content_part.added` |
| - `response.output_text.delta` |
| - `response.output_text.done` |
| - `response.content_part.done` |
| - `response.output_item.done` |
| - `response.completed` |
| - `response.failed` (on error) |
|
|
| ## Usage |
|
|
| `usage` is populated when the underlying provider reports token counts. |
|
|
| ## Errors |
|
|
| Errors use a JSON object like: |
|
|
| ```json |
| { "error": { "message": "...", "type": "invalid_request_error" } } |
| ``` |
|
|
| Common cases: |
|
|
| - `401` missing/invalid auth |
| - `400` invalid request body |
| - `405` wrong method |
|
|
| ## Examples |
|
|
| Non-streaming: |
|
|
| ```bash |
| curl -sS http://127.0.0.1:18789/v1/responses \ |
| -H 'Authorization: Bearer YOUR_TOKEN' \ |
| -H 'Content-Type: application/json' \ |
| -H 'x-openclaw-agent-id: main' \ |
| -d '{ |
| "model": "openclaw", |
| "input": "hi" |
| }' |
| ``` |
|
|
| Streaming: |
|
|
| ```bash |
| curl -N http://127.0.0.1:18789/v1/responses \ |
| -H 'Authorization: Bearer YOUR_TOKEN' \ |
| -H 'Content-Type: application/json' \ |
| -H 'x-openclaw-agent-id: main' \ |
| -d '{ |
| "model": "openclaw", |
| "stream": true, |
| "input": "hi" |
| }' |
| ``` |
|
|