Reference
Base URL: https://chat.app.urai.dev/api/agents/{agent_id}/v1
Endpoints
Section titled “Endpoints”| Method | Path | Purpose |
|---|---|---|
POST |
/responses |
Run a turn, buffered or streamed. |
GET |
/responses/{id} |
Read a stored response. |
DELETE |
/responses/{id} |
Delete the response and the turn that prompted it. |
POST |
/responses/{id}/cancel |
Stop a running turn. |
GET |
/responses/{id}/input_items |
List the thread items before that response. |
GET |
/models |
The one model this agent runs on. |
The routes with an id in the path take the end-user principal as ?user=,
because they carry no body.
Request fields
Section titled “Request fields”| Field | Type | Notes |
|---|---|---|
input |
string or array | Required. The turn, or a list of message items. |
instructions |
string | Added after the agent’s own instructions. Not stored. |
stream |
boolean | Return Server-Sent Events. |
user |
string | Your identifier for the end user. Isolates stored threads. |
previous_response_id |
string | Continue the thread that produced that response. |
vars |
object | Context for this turn. Reaches tools as meta.vars. At most 32 keys. |
metadata |
object | An alias for vars. vars wins on a shared key. |
reasoning |
object | {"effort": "..."}, where the model supports it. |
attachments |
array | File ids from POST /api/openai/v1/files. |
model |
string | Accepted and ignored. The agent’s model wins. |
store |
boolean | Accepted and ignored. Threads are always stored. |
tools |
array | Rejected with 400. Configure tools on the agent. |
tool_choice |
string or object | Rejected with 400. |
text.format.type |
string | Only text. Any other value is rejected with 400. |
Urai accepts any other OpenAI field and ignores it. A request built by a typed OpenAI SDK therefore works without a change.
Input items
Section titled “Input items”input is a string, or an array of items.
Item type |
Handling |
|---|---|
message, or absent |
Read as a turn. |
| Any other value | Skipped. Tools run on the server, and their calls are already in the thread. |
| Role | Handling |
|---|---|
user |
A turn in the conversation. The last one drives the run. |
assistant |
A turn in the conversation. |
system |
Read as an instruction for this request only. Not stored. |
developer |
The same as system. |
| Any other value | 400 with the code invalid_input. |
Content parts
Section titled “Content parts”content is a string, or an array of parts.
Part type |
Handling |
|---|---|
input_text |
Read as the message text. Several text parts are joined. |
output_text |
The same, for an assistant turn you echo back. |
input_image |
An attachment. Set image_url to a base64 data: URL, or set file_id. |
input_file |
An attachment. Set file_data with filename, or set file_id. |
| Any other value | Ignored, so a client sending a new OpenAI part still works. |
Headers
Section titled “Headers”| Header | Direction | Purpose |
|---|---|---|
Authorization: Bearer sk-urai-... |
Request | Required. An organization API key. |
x-thread-id |
Response | The stored thread for this exchange. Sent on every route. |
x-thread-id |
Request | Continues that thread. Send only the new message. |
A thread belongs to the triple of API key, user value, and agent.
The response object
Section titled “The response object”{ "id": "resp_9f2c1e40-1b7c-4c65-9a30-51a6b0f2c3d1", "object": "response", "created_at": 1710000000, "status": "completed", "error": null, "incomplete_details": null, "instructions": null, "model": "anthropic/claude-haiku-4-5", "output": [], "parallel_tool_calls": true, "previous_response_id": null, "store": true, "tool_choice": "auto", "tools": [], "truncation": "disabled", "usage": { "input_tokens": 1204, "input_tokens_details": { "cached_tokens": 900 }, "output_tokens": 86, "output_tokens_details": { "reasoning_tokens": 41 }, "total_tokens": 1290 }, "user": null, "metadata": {}, "thread_id": "0723cee0-3912-434e-8450-2c701e6f9713"}| Field | Notes |
|---|---|
id |
resp_ and the UUID of the assistant message. |
status |
in_progress, completed, failed, or cancelled. |
error |
{"code": "...", "message": "..."} when the status is failed. |
instructions |
Your instructions for this request. Never the agent’s own. |
model |
The model the turn ran on, as provider/model. |
output |
The items of the turn. See below. |
store |
Always true. |
tools |
Always empty. The agent’s tools are not published here. |
usage |
The whole turn, including every tool round. |
metadata |
The vars of the thread. |
thread_id |
A Urai addition. The stored conversation. |
tool_choice, truncation, and parallel_tool_calls are fixed. They report
how the agent runs, and a request cannot change them.
Output items
Section titled “Output items”| Type | Fields |
|---|---|
reasoning |
id (rs_), summary[] of summary_text parts. |
function_call |
id (fc_), call_id, name, arguments as a JSON string, status. |
message |
id (msg_), role, status, content[] of output_text parts. |
function_call.status is completed, incomplete when the tool returned an
error, or in_progress while it runs.
An output_text part carries annotations. A source the turn used appears as a
url_citation:
{ "type": "url_citation", "url": "https://example.com/shipping", "title": "Shipping times", "start_index": 0, "end_index": 118}The span covers the whole message. Urai records which sources a turn consulted, and not which sentence each one supports.
Object ids
Section titled “Object ids”| Prefix | Names |
|---|---|
resp_ |
A response, which is one assistant message. |
msg_ |
A message output item. |
fc_ |
A function call output item. |
rs_ |
A reasoning output item. |
previous_response_id and the {id} path segment accept the prefixed form and
the bare UUID.
Stream events
Section titled “Stream events”| Event | Meaning |
|---|---|
response.created |
The turn started. |
response.in_progress |
The same object again. |
response.output_item.added |
An item opened. |
response.output_item.done |
An item closed, restated in full. |
response.reasoning_summary_text.delta |
More reasoning text. |
response.reasoning_summary_text.done |
The whole reasoning summary. |
response.function_call_arguments.delta |
The arguments of a tool call. |
response.function_call_arguments.done |
The same arguments, complete. |
response.content_part.added |
The text part of the message opened. |
response.output_text.delta |
More answer text. |
response.output_text.done |
The whole answer. |
response.content_part.done |
The text part closed. |
response.completed |
The turn finished. Terminal. |
response.failed |
The turn failed. Terminal. |
Every event carries type and a sequence_number that starts at 0 and counts
up by one. The stream has no [DONE] frame. See
Streaming for the order.
Other objects
Section titled “Other objects”GET /models:
{ "object": "list", "data": [{ "id": "anthropic/claude-haiku-4-5", "object": "model", "created": 1710000000, "owned_by": "Support agent" }]}DELETE /responses/{id}:
{ "id": "resp_9f2c1e40-...", "object": "response", "deleted": true }GET /responses/{id}/input_items:
{ "object": "list", "data": [{ "id": "msg_1c9a...", "type": "message", "role": "user", "content": [{ "type": "input_text", "text": "Where is order 4821?" }] }], "first_id": "msg_1c9a...", "last_id": "msg_1c9a...", "has_more": false}Errors
Section titled “Errors”{ "error": { "message": "An agent brings its own tools. Configure them on the agent instead of sending them per request.", "type": "invalid_request_error", "param": "tools", "code": "tools_not_supported_for_agent" }}| Status | Code | Cause |
|---|---|---|
| 401 | missing_api_key |
No Authorization header. |
| 401 | invalid_api_key |
Urai does not recognise the key. |
| 401 | api_key_disabled |
Someone disabled the key. |
| 401 | expired_api_key |
The key is past its expiry. |
| 400 | invalid_agent_id |
The agent id in the path is not a UUID. |
| 404 | agent_not_found |
No such agent, or it belongs to another organization or another project. |
| 403 | agent_api_disabled |
The API is off for this agent. Enable it on the agent’s settings page. |
| 400 | tools_not_supported_for_agent |
The request sent tools or tool_choice. |
| 400 | unsupported_response_format |
text.format.type is not text. |
| 400 | invalid_input |
No user message, an empty final turn, or an unknown role. |
| 400 | invalid_vars |
vars or metadata is not an object, or the merge holds over 32 keys. |
| 400 | invalid_response_id |
previous_response_id or the path id is not a UUID. |
| 400 | invalid_thread_id |
x-thread-id is not a UUID. |
| 400 | model_not_configured |
The agent has no model. Set one on the agent. |
| 400 | invalid_attachment |
A remote URL, a bad data URL, invalid base64, or a file part with no payload. |
| 400 | attachment_too_large |
One attachment is over 25 MiB. |
| 400 | too_many_attachments |
More than 16 attachments in one request. |
| 404 | response_not_found |
Unknown response, or it belongs to another key, user, or agent. |
| 404 | thread_not_found |
The x-thread-id thread does not belong to this key, user, and agent. |
| 500 | (none) | Server error. Urai logs the detail and does not return it. |
| 502 | (none) | The turn could not start, or the agent’s model is not enabled. |
A turn that fails after it starts returns 200. The body carries
"status": "failed" and an error with the code agent_error.
A tool that fails at run time is not an error of the request. The agent reads
the failure and continues, and the tool’s output item closes with
"status": "incomplete".
Limits
Section titled “Limits”| Limit | Value |
|---|---|
| Request body | 64 MiB. Base64 adds about one third to the size of the bytes. |
| Attachments in one request | 16 |
| Size of one attachment | 25 MiB after decoding |
vars and metadata keys |
32 after the merge |
| Buffered request | 10 minutes. A longer turn returns "status": "failed". |
| Streamed request | No time limit. |
| Turns in flight per thread | 1 |
input_items paging |
None. The list returns every item, with has_more: false. |
usage scope |
The whole turn, including every tool round. |