POST /api/v1/conversation-instances/{instance_slug}/conversations/{conversation_id}/turns
Credential: an organization API key, or a scoped key with conversations:use.
How it works
- You post
message. The platform resolves the instance’s latest published version, checks guardrails, stores the user message, and runs model rounds. - Each round may call platform tools, which run on the server and loop back to the model.
- The segment ends with a
turn_endframe. Itsstop_reasonsays whether the turn ended (for exampleend_turn), handed client tool calls to you (tool_use), or paused for a confirmation (pending_confirmation). A failure ends the segment with anerrorframe instead. - After a handoff you post
tool_results. After a confirmation pause you postconfirmations. Each resume is a new request that runs the next segment of the same turn.
Request
Send exactly one ofmessage, tool_results, or confirmations.
Sending the retired
depth field returns 400 invalid_request with “depth is no longer supported; every assistant turn uses gpt-6-sol.” Unknown fields other than depth are ignored.
The stream
A200 response has these headers: Content-Type: text/event-stream, Cache-Control: no-cache, Connection: keep-alive, X-Accel-Buffering: no. Each frame is:
type, equal to the event name.
Frames
Every stream ends with exactly one
turn_end or one error frame. Nothing follows it.
Example frames:
Usage
turn_end.usage has input_tokens, output_tokens, total_tokens, cached_input_tokens, cache_creation_input_tokens, and cache_read_input_tokens. It is cumulative across the segments of the turn, so the turn_end of the final segment reports the whole turn. cached_input_tokens is the part of input_tokens the provider served from its cache. Configured assistants run on an OpenAI model, so the two cache_* fields, which only Anthropic models fill, are 0.
Turn states
This is the one state model for a turn. Other pages link here.
After an
error frame, post the next message. If a pause is still open, that request returns 409 pending_turn, described below.
A new message while a turn is paused returns 409 pending_turn. Its details say which resume is owed:
pause_kind: "confirm" means show the approval prompts again for the listed ids and post confirmations. pause_kind: "handoff" means post tool_results for the listed ids. A resume of the wrong kind, or a resume when nothing is paused, returns 409 turn_state_conflict.
Stop reasons
When the model uses every one of
limits.max_tool_rounds, it gets one more round with no tools to write its answer.
Which config a turn runs
A newmessage runs the latest published version of the instance; the instance must have one (409 instance_not_published). A resume (tool_results or confirmations) runs the version the turn started on, even if a newer version was published during the pause. Every stored message carries the config_version_hash it ran under.
Errors before and after the first frame
The response status is decided when the first frame is written.- Before the first frame, a failure is a normal HTTP error with the JSON envelope
{code, message, details?}. Nothing was streamed. - After the first frame, the status is already
200. A failure arrives as a terminalerrorframe withcode,message, and, forprovider_error,reason. Assistant text already streamed in that segment may be incomplete.
conversation frame before it calls the model, so a model provider failure arrives as an error frame, not as an HTTP status. Its code is provider_error with a reason from a closed list (rate_limited, context_overflow, model_unavailable, invalid_request, provider_auth, provider_fault), or provider_unavailable when the provider circuit is open after repeated failures. A model call that fails with a transient error (a provider rate limit or 5xx, or a network failure) is attempted up to three times in total, waiting at most 5 seconds between attempts, as long as the provider has streamed nothing for that call. Once the provider has streamed output for that call, the failure is final.
Disconnects and timeouts
- The turn keeps running when your client disconnects. It completes and is stored; fetch the conversation to see the result.
- One segment may run for up to 10 minutes on the server. Set your client read timeout above that.
- Turns are exempt from the 30-second request timeout most routes have.
- One segment runs per conversation at a time. A hold left by a segment that died without releasing it (a crash or deploy) can be taken over after 10 minutes.
- Turn requests have their own rate limit bucket per org, separate from the default bucket other routes use. Its limit is 300 requests per minute, or the deployment’s default limit when that is higher. A
429 rate_limitedcarriesRetry-After. - If a previous turn was interrupted between a tool call and its result, the platform answers the orphaned calls with errors before the next message turn runs.
Errors
A code raised after the first frame, such as
attachment_changed, invalid_conversation_history, or internal_error, arrives in an error frame on the 200 stream instead of as this status. The full error envelope is described on Errors.
Client tools and confirmations
Resume a handoff or a confirmation pause.
Take a turn (API reference)
The generated endpoint contract.