/v1/responses path is still accepted as an alias for clients pinned to it.
When to use this vs. the Chat Completions proxy
If you want IronClaw’s capabilities behind an OpenAI-shaped wire contract, this is the endpoint.
Authentication
Every protected route requires a bearer token in theAuthorization header:
- Instance token (single-user)
- Per-user tokens (multi-user)
The bearer token provisioned during onboarding authenticates both the web interface and this API. It is written to Supply your own instead by setting
webui-token in your IronClaw home:IRONCLAW_REBORN_WEBUI_TOKEN before starting serve.401. Chat send endpoints (including this one) are rate-limited to 30 requests per 60 seconds per user.
Quickstart
The simplest request, with no session state and no tools:base_url at https://your-host/api/v1 (or /v1 for the alias).
Request fields
These fields are rejected with
400 so callers know they were ignored rather than silently dropped:
tool_choice(no per-request tool surface to enforce against)temperature(configure via settings)max_output_tokens(not yet wired)- Any
modelother than"default"
Session continuity
Each response embeds its thread UUID in theid. Pass the previous id back as previous_response_id to continue the same conversation:
404).
Each POST mints a fresh response_uuid, so two turns on the same thread produce different ids.
Retrieving a past response
usage field on a retrieved response is zero.
Streaming
Set"stream": true to receive Server-Sent Events:
event: field matches the JSON type:
A keepalive frame fires every 15 seconds to prevent intermediate proxies from closing idle connections.
The non-streaming path has a 120-second turn timeout. Long-running tool work (sandbox jobs, multi-step agentic flows) should use
stream: true so the connection stays responsive.
External tools
You can register your own function tools per request. The agent treats them as first-class actions alongside built-in tools and pauses execution when it wants to call one. Your client executes the call and feeds the result back on the next request. This is a function-calling round-trip, not a prompt-level convention. The wire shape matches the OpenAI Responses API spec.Define tools
400 on violation):
- Only
type: "function"is accepted.web_search,file_search,code_interpreter, etc. are rejected. IronClaw routes those through its own registry, not caller-provided definitions. - Names:
^[A-Za-z0-9_-]{1,64}$, unique within the request. - Names must not shadow a registered IronClaw action (built-in tool, extension tool, or an agent capability like
mission_*,skill_*,memory_*). Shadowing is rejected to prevent confused-deputy behavior. - The entire
tools[]payload caps at 16 KiB of canonical JSON.
The round trip
When the model calls one of your tools, the response completes with afunction_call output item and the thread sits in Waiting:
message item so you see both pieces in order.
Execute the call locally, then POST a follow-up with a function_call_output item. Include previous_response_id so the resume targets the same thread:
message output item.
Pass the same tools[] on the resume request. The catalog is per-thread; passing the definitions keeps the tool available for any follow-up calls the model makes.
Resume validation
The resume request must satisfy the bridge:- A
function_call_outputitem without a live external-tool gate on this thread returns400. - A
function_call_outputitem whosecall_iddoes not match the pending gate returns400. - A
function_call_outputitem with an emptycall_idor missingoutputreturns400. - If the thread is paused on an unrelated gate (OAuth, approval, pairing), resolve that first.
message item. Both will be visible to the agent:
Multi-call batching
The engine pauses on the first external tool call in an assistant turn. If the model wants to invoketool_a and tool_b together, only tool_a surfaces on the first response. After you resume, tool_b is emitted on the next turn. This is a known limitation; OpenAI-style “post all results together” is a follow-up.
Streaming flow
Withstream: true, the external-tool flow looks like:
response.created- Optional
response.output_text.deltaevents for any leading prose. response.output_item.addedwith thefunction_callitem.response.output_item.donewith the same item.response.completed.
response.completed. Send the resume as a fresh POST with previous_response_id.
Structured context (x_context)
For integrations that need to pass structured state alongside the user message (notification approval, webhook payload, environment hints), use x_context:
<user-context> block ahead of the user message. Total serialized size caps at 10 KB. Pass a flat {key: {object}} structure; deeper nesting is serialized as raw JSON.
x_context is an IronClaw extension and is not part of the OpenAI Responses API spec.
Per-request instructions
Useinstructions to inject a one-turn system/developer message:
instructions apply only to the current turn and are not carried by previous_response_id. IronClaw currently prepends the <instructions> block into the user message and persists it as part of the conversation, so it is visible on later turns when history is replayed. Until the handler stores instructions out-of-band, treat them as sticky for the thread and re-send (or override) them explicitly on each turn that needs different behaviour.
The agent’s persistent identity files (AGENTS.md, SOUL.md, USER.md, IDENTITY.md) come from workspace memory and are not affected by this field.
Errors
Errors from the Responses handler use the OpenAI envelope:
A turn that completes but fails mid-flight (the model errored, a required tool raised) returns
200 with "status": "failed" and a populated error field. Inspect status before reading output.
Two cases do not use the JSON envelope and need separate handling:
401Unauthorized comes from the gateway auth middleware before the request reaches the handler, and the body is a plain-text string (Invalid or missing auth token). Same for403(Forbiddenfor OIDC domain violations) and the503(Database unavailable) emitted by the middleware when the token store is down.GET /api/v1/responses/{id}returns404(still JSON-enveloped) when the response id is unknown or the thread does not belong to the authenticated user.POSTwith a foreignprevious_response_iddoes not return404; the handler only decodes the UUID and dispatches into the agent, where the cross-user resume surfaces as a turn-level failure rather than an HTTP error. Treat cross-user resume as undefined and avoid relying on the response shape.
SDK usage
The OpenAI SDKs are the easiest way to use this endpoint. Point them at IronClaw and they “just work”:Limits and quirks
- Rate limit: 30 requests per 60 seconds per user (shared with
/api/chat/send). - Body size: 14 MiB request limit at the gateway.
- Turn timeout (non-streaming): 120 seconds. Use
stream: truefor long-running work. - Tool batching: one external-tool call per round trip. The engine resumes the next call on the next turn.
- Approvals and auth gates: not surfaced over the Responses API. Resolve them via the web UI before retrying.
tool_choice,temperature,max_output_tokens: not yet supported. Requests carrying these fields are rejected so callers see they were not honoured.model: must be"default". Provider and model selection is server-side via settings.- Token usage on retrieval:
GET /api/v1/responses/{id}returns reconstructed output items butusageis zero because per-message token counts are not persisted.
Related
- Inference Providers — configure the model that backs
"default". - Configuration — configuration file layout, profiles, and environment overrides.
- Sandboxed Tools — how IronClaw’s built-in tools execute when the agent calls them.
- MCP — connect Model Context Protocol servers to extend the agent’s tool surface server-side instead of supplying caller tools per-request.