Skip to content

Overview

Every agent you build in Urai has its own OpenAI-compatible Responses endpoint. You point an OpenAI SDK at that agent, send an input, and get the finished answer back. The agent brings its own model, its own instructions, its own tools, and its own knowledge collections.

This is the same agent that answers in the chat widget and in the Urai interface. A request through this API runs the same pipeline, so the agent behaves the same way at each door.

You want Use
One agent, configured in the browser, called from your code This API
A model of your choice, with tools and collections named per request Chat Completions API
An agent in your product interface The widget

The API is off for every agent until you turn it on. Open the agent in Urai and enable the Responses API on its settings page. The field is responses_api_enabled on the agent object.

Read the security note before you enable an agent that was written for the widget.

https://chat.app.urai.dev/api/agents/{agent_id}/v1

agent_id is the UUID of the agent. You find it in the address bar when you open the agent in Urai, and in the id field of GET /api/projects/{project_id}/assistants.

Every path on this page is relative to that base URL.

Send an organization API key as a bearer token. The API takes the same sk-urai-... keys as the Chat Completions API. There is no separate token for an agent.

Authorization: Bearer sk-urai-...

To create a key, open API Keys in the Urai sidebar. Only organization owners and admins see this page. Urai shows the value one time.

Keep the key on your server. Do not put a key in browser code.

An enabled agent answers any valid key in its organization. A key that is scoped to a project reaches only the agents in that project.

This is why the API is off by default. An agent that you wrote for the widget has instructions and tools that you chose for that audience. Enable the API after you check that the agent is safe for anyone who holds an organization key.

Three errors cover the checks:

Status Code Cause
400 invalid_agent_id The path segment is not a UUID.
404 agent_not_found No such agent, or the agent belongs to another organization or another project.
403 agent_api_disabled The agent exists and is yours, but the API is off for it.

An agent in another organization returns 404 and not 403, so a caller cannot learn that the id names a real agent.

Terminal window
curl https://chat.app.urai.dev/api/agents/$AGENT_ID/v1/responses \
-H "Authorization: Bearer $URAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "agent",
"input": "Where is order 4821?"
}'

The same request with the OpenAI Node SDK:

import OpenAI from "openai";
const client = new OpenAI({
baseURL: `https://chat.app.urai.dev/api/agents/${agentId}/v1`,
apiKey: "sk-urai-...",
});
const response = await client.responses.create({
model: "agent",
input: "Where is order 4821?",
});
console.log(response.output_text);

And with the OpenAI Python SDK:

from openai import OpenAI
client = OpenAI(
base_url=f"https://chat.app.urai.dev/api/agents/{agent_id}/v1",
api_key="sk-urai-...",
)
response = client.responses.create(
model="agent",
input="Where is order 4821?",
)
print(response.output_text)

model is not read. The SDKs make the field mandatory, so send any string.

{
"id": "resp_9f2c1e40-1b7c-4c65-9a30-51a6b0f2c3d1",
"object": "response",
"created_at": 1710000000,
"status": "completed",
"error": null,
"model": "anthropic/claude-haiku-4-5",
"output": [
{
"type": "function_call",
"id": "fc_5b3e...",
"call_id": "call_1",
"name": "orders_lookup",
"arguments": "{\"order\":\"4821\"}",
"status": "completed"
},
{
"type": "message",
"id": "msg_9f2c1e40-1b7c-4c65-9a30-51a6b0f2c3d1",
"role": "assistant",
"status": "completed",
"content": [
{ "type": "output_text", "text": "Order 4821 shipped on Tuesday.", "annotations": [] }
]
}
],
"usage": {
"input_tokens": 1204,
"input_tokens_details": { "cached_tokens": 900 },
"output_tokens": 86,
"output_tokens_details": { "reasoning_tokens": 41 },
"total_tokens": 1290
},
"metadata": {},
"thread_id": "0723cee0-3912-434e-8450-2c701e6f9713"
}

The output array holds the work of the whole turn, in the order it happened: the reasoning summary, then one function_call item for each tool the agent ran, then the message. usage covers every round of that turn.

thread_id is a Urai addition. It names the stored conversation. See Conversations.

model reports the model the turn ran on, in the form provider/model. The agent owns that choice.

A request waits up to 10 minutes for the turn to finish. An agent that runs many tool rounds can take a while. To watch the work as it happens, stream it.

The agent already holds the model, the system instructions, the tools, the skills, and the knowledge collections. You do not send them.

Fields that name those things fall into two groups.

Accepted and ignored. model, store, and any other OpenAI field that Urai does not read. Their absence changes nothing you can observe, so a request built by a typed SDK works without a change.

Rejected with 400. tools, tool_choice, and text.format with a value other than text. Urai does not drop these quietly. A dropped function tool looks like a model that never calls tools, which is hard to diagnose from the outside.

To change what the agent can do, change the agent.

Field Purpose
input The turn. A string, or a list of message items.
instructions Extra instructions for this request. Urai appends them after the agent’s own.
stream Return Server-Sent Events.
user Your identifier for the end user. It isolates stored conversations.
previous_response_id Continue the conversation that produced that response.
vars Context for this request. Your UraiJS tools read it.
metadata An alias for vars, for SDKs with no way to send an unknown field.
reasoning.effort The reasoning effort, where the model supports it.
attachments File ids to attach to the turn.

Conversations covers input, previous_response_id, user, vars, and attachments in full.

Terminal window
curl https://chat.app.urai.dev/api/agents/$AGENT_ID/v1/models \
-H "Authorization: Bearer $URAI_API_KEY"
{
"object": "list",
"data": [
{
"id": "anthropic/claude-haiku-4-5",
"object": "model",
"created": 1710000000,
"owned_by": "Support agent"
}
]
}

The list holds one entry, because the agent runs on one model. owned_by is the name of the agent.

Errors use the OpenAI envelope and the matching HTTP status.

{
"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"
}
}

A turn that fails after it starts does not return an HTTP error. The response comes back with "status": "failed" and an error object, because the turn ran and cost you tokens.

The Reference page lists every code.

  • Conversations. Continue a thread, keep end users apart, pass context, and attach files.
  • Streaming. Every event, in the order Urai sends it.
  • Reference. Every endpoint, field, object, and error code.