Skip to main content
POST
This is the non-streaming turn, for server-to-server integrations and jobs that cannot read an event stream. It returns once the answer is complete. To show the answer as it is written, use Stream a message instead; both run the same turn. The response is the whole turn: the updated conversation, your question, and the answer, each as its own object. An answer with abstained: true means the assistant declined because your knowledge did not support an answer. That is a successful 201, not an error. See How answers work. A conversation answers one question at a time. While a question is in progress, another one returns 409. A question left unanswered for more than 15 minutes, because the server handling it stopped, no longer blocks the conversation: the next question takes over and the lost answer is marked interrupted. Only the conversation’s owner can ask questions in it, and an archived conversation refuses new questions with 409. This request also resolves the conversation’s assistant. If that assistant can no longer answer (it is disabled or archived, or has no knowledge attached), this request returns 400 validation_error. Retrying safely. Send an idempotency_key with each question. If you retry with the same key after the first attempt finished, you get the turn it produced, with 201, and the model is not asked again. If the first attempt is still being answered, the retry returns 409. A turn that failed, here or on the streaming endpoint, or was interrupted on the streaming endpoint, is kept, so a retry with its key returns it as it ended, with 201 and the answer’s status: send a new key to ask again. When your organisation has used its monthly answer allowance, the question is refused with 429 and the code quota_exceeded before it is stored or any model is called. Do not retry it on a timer; see Errors. If generation fails, you get a 502 or 503 error, and the attempt is kept, as the streaming endpoint keeps it: your question and an answer with status: "failed" are added to the conversation, and the conversation is free for the next question. A retry with the same idempotency_key returns that failed turn with 201 rather than asking again; send a new key, or none, to ask again.
Changed on 1 November 2026. Until then a failed attempt on this endpoint kept nothing, and a retry with the same idempotency_key asked the model again. The error status you receive is unchanged. If your integration retries a failed question with the same key, give the retry a new key.
string
required
The conversation ID.
string
required
The question. 1 to 16,000 characters after trimming. Newlines and tabs are allowed; other control characters and invisible formatting characters are rejected. Windows line endings are normalized to \n.
string
Your own key for this question, unique within the conversation. Up to 128 characters from A-Z, a-z, 0-9, _, ., : and -.
object
Your own labels for the question, as string keys and string values. At most 20 entries; keys up to 64 characters matching ^[a-z][a-z0-9_.-]*$; values up to 512 characters on a single line. Returned verbatim, so never put secrets here.
The request body can be at most 256 KiB.

Response

Returns 201 Created.
object
required
The conversation after this turn. It has the same fields as Get a conversation. If the conversation was untitled, it is now named after the first line of your question.
object
required
Your question, as stored. It has the same fields as answer, with role user, status complete, empty citations, and model and finish_reason set to null.
object
required
The assistant’s answer.
Last modified on November 7, 2026