Agent mode APIs in Genie Agents
Agent mode APIs let you run Agent mode programmatically instead of through the Databricks UI. Use them to integrate Agent mode into your own applications, such as chatbots, scheduled reports, and internal tools.
The Genie Agents Agent mode APIs are in Beta.
Agent mode was formerly known as Research Agent. Genie Agents were formerly known as Genie Spaces.
How Agent mode APIs work
With the Agent mode APIs, you send a natural-language question to a Genie Agent. It creates and refines a research plan, runs SQL queries, iterates based on each result, and returns a report with citations and supporting tables. Results stream to your client as Server-Sent Events (SSE).
The APIs cover the endpoints, request and response formats, and streaming event types needed to communicate with Agent mode directly. For the concept overview and the UI experience, see Agent mode in Genie Agents.
Requirements
To use the Agent mode APIs, your workspace must meet the following requirements:
- Unity Catalog is enabled. See What is Unity Catalog?.
- Partner-powered AI features are enabled. See Partner-powered AI features.
- You have a Genie Agent with clear instructions and table metadata. Agent mode relies on this context to reason about your data. See Curate an effective Genie Agent.
To enable the APIs for your workspace, contact your Databricks account team with the workspace IDs where you want the feature. After the request is approved, a workspace admin turns on Genie Agents Agent Mode API from the Previews menu.
Get started
The following examples show how to send a prompt and read the streamed response.
Send your first prompt with curl
The following request sends a natural-language question to a Genie Agent and streams the response as an SSE:
curl -N --no-buffer \
-X POST "https://${DATABRICKS_HOST}/api/2.0/genie/agents/${AGENT_ID}/responses" \
-H "Authorization: Bearer ${DATABRICKS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"input": [
{
"type": "message",
"role": "user",
"content": [{"type": "input_text", "text": "What were our top 10 customers by revenue last quarter?"}]
}
]
}'
Events arrive as event: and data: pairs:
event: response.created
data: {"type":"response.created","sequence_number":0,"response":{"object":"response","id":"01f14fe4e34b...","model":"genie-agent","status":"in_progress","output":[],"conversation_id":"01f14fe4e338..."}}
event: response.output_item.added
data: {"type":"response.output_item.added","output_index":0,"sequence_number":1,"item":{"type":"reasoning","id":"01f14fe4f248...","status":"in_progress","content":[{"type":"reasoning_text","text":"I need to find revenue data..."}],"summary":[]}}
event: response.completed
data: {"type":"response.completed","sequence_number":42,"response":{"object":"response","id":"01f14fe4e34b...","model":"genie-agent","status":"completed","output":[...],"conversation_id":"01f14fe4e338...","created_at":1748383200}}
Read the stream with the Databricks OpenAI client (Python)
Install the client:
pip install databricks-openai
Create a response and handle each event as it arrives:
from databricks.sdk import WorkspaceClient
from databricks_openai import DatabricksOpenAI
AGENT_ID = "<your-agent-id>" # Same as your Genie Agent ID
w = WorkspaceClient()
host = f"https://{w.config.host}" if not w.config.host.startswith("http") else w.config.host
client = DatabricksOpenAI(workspace_client=w)
client.base_url = f"{host}/api/2.0/genie/agents/{AGENT_ID}"
stream = client.responses.create(
model="genie-agent",
input=[
{
"type": "message",
"role": "user",
"content": [{"type": "input_text", "text": "What were our top 10 customers by revenue last quarter?"}],
}
],
stream=True,
)
conversation_id = None
for event in stream:
if event.type == "response.created":
conversation_id = event.response.conversation_id
elif event.type == "response.output_item.done":
print(f"Output item: {event.item.type}")
elif event.type == "response.completed":
print(f"Done: {event.response.status}")
elif event.type == "response.failed":
print(f"Failed: {event.response.error}")
Send a follow-up prompt
To continue a conversation, pass the conversation_id from the first response:
stream = client.responses.create(
model="genie-agent",
input=[
{
"type": "message",
"role": "user",
"content": [{"type": "input_text", "text": "Break that down by region"}],
}
],
stream=True,
extra_body={"conversation_id": conversation_id},
)
The agent retains context from previous turns and can reference earlier queries and results.
API reference
The Agent mode APIs cover the available endpoints, the request and response formats, the SSE event lifecycle, the data models, and the error codes.
Base URL
All endpoints are relative to the following base URL:
https://<workspace-url>/api/2.0/genie/agents
The agent_id in each path is the Genie Agent ID, the same 32-character hexadecimal identifier that appears in the Genie Agent URL.
Endpoints
The APIs provide the following endpoints:
Method | Path | Description |
|---|---|---|
|
| Create a response as an SSE stream. |
|
| List all items in a conversation. |
Create a response
Creates a new Agent mode response. Returns an SSE stream that delivers output items in real time as Agent mode runs.
POST /{agent_id}/responses
Path parameters
The endpoint accepts the following path parameter:
Parameter | Type | Required | Description |
|---|---|---|---|
|
| Yes | The ID of the Genie Agent. A 32-character lowercase hexadecimal string. |
Request body
The request body accepts the following fields:
Field | Type | Required | Default | Description |
|---|---|---|---|---|
|
| Yes | None | The input items. The array must contain exactly one |
|
| No |
| The ID of an existing conversation to continue. When omitted, a new conversation is created. |
SSE event lifecycle
The stream opens with a response.created event, streams output items, then closes with a terminal event:
response.created (once, stream opened)
-> response.output_item.added (0..N, new item appears)
-> response.output_item.updated (0..N, item content changed)
-> response.output_item.done (0..N, item finalized)
-> response.completed (once, terminal success)
OR response.failed (once, terminal failure)
Every event carries a monotonically increasing sequence_number that you can use for ordering.
SSE event types
The stream emits the following event types.
response.created
Emitted once at the start. Contains a Response object with status: "in_progress" and an empty output array.
event: response.created
data: {
"type": "response.created",
"sequence_number": 0,
"response": {
"object": "response",
"id": "01f15a22a7a816299374da7bc4264025",
"model": "genie-agent",
"status": "in_progress",
"output": [],
"conversation_id": "01f15a22a79a1699ab5e7f59563c5655",
"created_at": 1748383200
}
}
response.output_item.added
Emitted when a new output item first appears. The item might still be in_progress.
event: response.output_item.added
data: {
"type": "response.output_item.added",
"output_index": 0,
"sequence_number": 1,
"item": {
"type": "reasoning",
"id": "01f14fe4f24818d79f3e5963c31ec151",
"status": "in_progress",
"content": [
{"type": "reasoning_text", "text": "I need to find the revenue data..."}
],
"summary": []
}
}
response.output_item.updated
Emitted when an existing item's content changes, such as when query results arrive for a function_call_output. Uses the same payload shape as response.output_item.added.
response.output_item.done
Emitted when an output item reaches its final state. Uses the same payload shape as response.output_item.added. If an item arrives already completed, both the added and done events are emitted in sequence.
response.completed
Terminal success event. Wraps the final Response with all output items.
event: response.completed
data: {
"type": "response.completed",
"sequence_number": 42,
"response": {
"object": "response",
"id": "01f14fe4e34b1b2293908bcece575499",
"model": "genie-agent",
"status": "completed",
"output": [ ... ],
"conversation_id": "01f14fe4e33816c6aa264b4661f998ea",
"created_at": 1748383200
}
}
response.failed
Terminal failure event. The Response has status: "failed" and an error object. A system error message item is emitted as response.output_item.added immediately before this event. For the full list of codes, see Streaming error codes.
event: response.failed
data: {
"type": "response.failed",
"sequence_number": 5,
"response": {
"object": "response",
"id": "01f14fe4e34b1b2293908bcece575499",
"model": "genie-agent",
"status": "failed",
"output": [ ... ],
"error": {
"type": "server_error",
"code": "sql_execution_error",
"message": "Table 'sales' does not exist"
},
"conversation_id": "01f14fe4e33816c6aa264b4661f998ea",
"created_at": 1748383200
}
}
Concurrency
Only one response can be generated per conversation at a time. A second request to a conversation that already has an in-progress response returns an HTTP 409:
HTTP 409
{"error": {"type": "RESOURCE_CONFLICT", "message": "A response is already being generated for conversation <id>"}}
Timeouts
The SSE stream has a server-side timeout of 90 minutes. Because Agent mode runs multi-step reasoning and SQL execution, keep your HTTP connection open for the full duration.
List conversation items
Retrieves the output items in a conversation as a flat list. Items from all turns are combined in chronological order, including user messages, reasoning, queries, results, and reports. This endpoint supports cursor-based pagination through the after and limit query parameters.
GET /{agent_id}/conversations/{conversation_id}/items
Use this endpoint to:
- Display the full conversation history in your application.
- Recover results after an SSE stream disconnects. Call this endpoint after the response completes.
- Fetch large conversations incrementally instead of loading all items at once.
Path parameters
The endpoint accepts the following path parameters:
Parameter | Type | Required | Description |
|---|---|---|---|
|
| Yes | The ID of the Genie Agent. A 32-character lowercase hexadecimal string. |
|
| Yes | The ID of the conversation. |
Query parameters
The endpoint accepts the following query parameters:
Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
|
| No | 100 | The maximum number of items to return. Range: 1 to 100. |
|
| No | None | The pagination cursor. Pass |
|
| No |
| The sort order. Use |
Example requests
Retrieve all items in a conversation:
GET /api/2.0/genie/agents/01f14fe4e338.../conversations/01f14fe4e338.../items
Limit the page size:
GET /api/2.0/genie/agents/01f14fe4e338.../conversations/01f14fe4e338.../items?limit=5
Return the newest items first:
GET /api/2.0/genie/agents/01f14fe4e338.../conversations/01f14fe4e338.../items?order=desc&limit=5
Fetch the next page:
GET /api/2.0/genie/agents/01f14fe4e338.../conversations/01f14fe4e338.../items?limit=5&after=01f14fe4f24e10beacaa1720d4b79b59_output
Response
The response has Content-Type: application/json and is a paginated list envelope with "object": "list":
{
"data": [
{
"type": "message",
"role": "user",
"content": [{ "type": "input_text", "text": "What were our top 10 customers by revenue last quarter?" }],
"id": "01f14fe4e34b1b2293908bcece575499_input",
"status": "completed"
},
{
"type": "reasoning",
"id": "01f14fe4f24818d79f3e5963c31ec151",
"status": "completed",
"content": [{ "type": "reasoning_text", "text": "I'll query the revenue table grouped by customer..." }],
"summary": []
},
{
"type": "function_call",
"id": "01f14fe4f24e10beacaa1720d4b79b59",
"call_id": "01f14fe4f24e10beacaa1720d4b79b59",
"status": "completed",
"name": "execute_sql",
"arguments": "{\"title\": \"Top 10 Customers\", \"sql\": \"SELECT customer, SUM(revenue) AS total FROM sales GROUP BY customer ORDER BY total DESC LIMIT 10\"}"
},
{
"type": "function_call_output",
"id": "01f14fe4f24e10beacaa1720d4b79b59_output",
"call_id": "01f14fe4f24e10beacaa1720d4b79b59",
"status": "completed",
"output": "Top 10 Customers\n\n| customer | total |\n| --- | --- |\n| Acme Corp | 1500000 |\n| Globex | 1200000 |"
},
{
"type": "message",
"id": "01f14fe5383f184a97ca1178af0d9356",
"role": "assistant",
"status": "completed",
"content": [
{
"type": "output_text",
"text": "Here are your top 10 customers by revenue last quarter [1](https://host/genie/rooms/01f14fe4e338.../chats/01f14fe4e338...?o=12345&gra_focus=01f14fe4f24e...)."
},
{
"type": "output_text",
"text": "| customer | total |\n| --- | --- |\n| Acme Corp | 1500000 |\n| Globex | 1200000 |",
"metadata": {
"columns": [
{ "name": "customer", "type": "STRING" },
{ "name": "total", "type": "DOUBLE" }
],
"preview_rows": [
["Acme Corp", "1500000"],
["Globex", "1200000"]
],
"total_row_count": 10,
"status": "available",
"sql": "SELECT customer, SUM(revenue) AS total FROM sales GROUP BY customer ORDER BY total DESC LIMIT 10"
}
},
{
"type": "output_text",
"text": "Acme Corp leads with $1.5M [1](https://host/genie/rooms/01f14fe4e338.../chats/01f14fe4e338...?o=12345&gra_focus=01f14fe4f24e...), followed by Globex at $1.2M [1](https://host/genie/rooms/01f14fe4e338.../chats/01f14fe4e338...?o=12345&gra_focus=01f14fe4f24e...)..."
}
]
}
],
"first_id": "01f14fe4e34b1b2293908bcece575499_input",
"last_id": "01f14fe5383f184a97ca1178af0d9356",
"has_more": false,
"status": "completed",
"object": "list"
}
The top-level status field reflects the state of the latest response in the conversation. It is "in_progress" while a response is streaming, and "completed" or "failed" after it finishes. Poll this field to detect when a response has finished.
Pagination
The response includes three pagination fields:
Field | Type | Description |
|---|---|---|
|
| The ID of the first item in the current page. Absent when |
|
| The ID of the last item in the current page. Pass it as |
|
|
|
To paginate through all items, request pages until has_more is false:
items = []
after = None
while True:
params = {"limit": 10}
if after:
params["after"] = after
page = client.get(f"/conversations/{conv_id}/items", params=params)
items.extend(page["data"])
if not page["has_more"]:
break
after = page["last_id"]
The data array contains output items in chronological order. User input messages appear as message items with an _input suffix on the ID.
Understand the response
This section explains how the output items fit together to form a complete Agent mode response.
Output item flow
A typical Agent mode response produces output items in the following order:
reasoning The agent's plan and analysis
|
function_call A SQL query the agent runs
|
function_call_output The query results, paired with the function_call above
|
... (reasoning, function_call, and function_call_output repeat for each query) ...
|
message The final report, with structured text and inline tables
The agent can run multiple queries in sequence, refining its analysis based on each result. A single response can contain many reasoning, query, and result cycles before the final report.
How function_call and function_call_output pair
Every SQL query produces a pair of output items linked by call_id:
function_callis the query the agent runs. Theargumentsfield is a JSON-encoded string that describes the tool invocation.function_call_outputis the result. After the item completes, theoutputfield contains the query title followed by a markdown table of the data.
The call_id is identical on both items. The function_call_output.id is always {call_id}_output.
Parse the report
The final output item is a message with role: "assistant". Its content array contains multiple output_text chunks of two kinds:
- Text chunks hold narrative analysis with inline citation links.
- Table chunks hold inline query results rendered as markdown tables. Each table chunk carries
metadatawith the structured query result data, so your client can render rich tables or charts programmatically.
The following table chunk includes both the rendered markdown and the structured metadata:
{
"type": "output_text",
"text": "| customer | total |\n| --- | --- |\n| Acme Corp | 1500000 |\n| Globex | 1200000 |",
"metadata": {
"columns": [
{ "name": "customer", "type": "STRING" },
{ "name": "total", "type": "DOUBLE" }
],
"preview_rows": [
["Acme Corp", "1500000"],
["Globex", "1200000"]
],
"total_row_count": 10,
"status": "available",
"sql": "SELECT customer, SUM(revenue) AS total FROM sales GROUP BY customer ORDER BY total DESC LIMIT 10"
}
}
A table chunk metadata object contains the following fields:
Field | Type | Description |
|---|---|---|
|
| The column definitions. |
|
| The truncated result rows. |
|
| The total row count, when known. |
|
| Either |
|
| The SQL query that produced the results. |
Citations
Text chunks in the report contain inline citations that link each claim to the SQL query that supports it. Each citation is a markdown link of the form [N](url), where N is a sequential footnote number and url points to the Genie Agent UI with the relevant query focused.
The citation URL has the following format:
https://<workspace-url>/genie/rooms/<space_id>/chats/<conversation_id>?o=<workspace_id>&gra_focus=<attachment_id>
The URL contains the following components:
Component | Description |
|---|---|
| The Genie Agent ID, the same value as |
| The conversation that contains the cited query. |
| The numeric workspace ID. |
| The query attachment ID, which identifies the specific SQL query result. |
To render citations, follow this guidance based on your client:
- Markdown renderers display citations as clickable footnote links automatically.
- For plain text, reduce
[N](url)to[N]or remove the citation. - For a custom UI, parse the
gra_focusquery parameter from the URL to identify the cited query, then match it against thefunction_call_outputitems in the conversation.
Citations are deduplicated. If the same query is cited multiple times, every reference uses the same index number and URL.
Data models
This section describes the objects that the APIs return.
Response
The Response object is returned in the response.created, response.completed, and response.failed SSE events.
Field | Type | Description |
|---|---|---|
|
| Always |
|
| The unique response ID. |
|
| Always |
|
| Either |
|
| The output items produced by the response. |
|
| The conversation the response belongs to. |
|
| The Unix epoch time in seconds when the response was created. |
|
| Present when |
ErrorInfo
The ErrorInfo object describes a failure:
Field | Type | Description |
|---|---|---|
|
| One of: |
|
| A human-readable description. For internal errors, this is always |
|
| An optional error code with more detail, such as |
Output items
Output items are polymorphic on the type field. The following types are available.
reasoning
The agent's internal reasoning as Agent mode runs.
Field | Type | Description |
|---|---|---|
|
|
|
|
| The unique item ID. |
|
| Either |
|
| Contains |
|
| Always |
function_call
A tool invocation, which is a SQL query execution.
Field | Type | Description |
|---|---|---|
|
|
|
|
| The unique item ID. |
|
| The correlation ID that links to the paired |
|
|
|
|
|
|
|
| A JSON string, for example |
function_call_output
The result of a tool invocation, paired with a function_call through call_id.
Field | Type | Description |
|---|---|---|
|
|
|
|
| Always |
|
| Matches the corresponding |
|
| Either |
|
| The query result. See the following lifecycle table. |
The output field evolves as the item progresses:
Status |
|
|---|---|
| The query title only. |
| The query title, a blank line, then the markdown result table. |
Structured query result data, such as columns, rows, and SQL, is available on the report's table chunks, not on the function_call_output item. See Parse the report.
message
A text message. A message appears in one of three roles:
Role | When | Description |
|---|---|---|
| Input | The user's question. Appears in |
| Report | The final structured report with text and inline table chunks. |
| Error or cancel | Emitted when a response fails or is cancelled. |
The message object contains the following fields:
Field | Type | Description |
|---|---|---|
|
|
|
|
| Either |
|
| The message content. See Parse the report for assistant messages. |
|
| The unique item ID. System messages use |
|
| Either |
When a response fails, the structured error is delivered on the Response object's error field (see ErrorInfo) and in the response.failed event, not on the system message item.
Content items
The APIs use the following content item types:
Type | Fields | Used in |
|---|---|---|
|
| User messages (input). |
|
| Assistant messages (report chunks). Text chunks contain |
|
| Reasoning items. |
ColumnInfo
The ColumnInfo object describes a column:
Field | Type | Description |
|---|---|---|
|
| The column name. |
|
| The column data type, such as |
Error handling
The APIs return two kinds of errors: HTTP errors before the stream starts, and streaming errors that end an open stream.
HTTP errors
HTTP errors are returned as standard JSON responses before the SSE stream starts:
{ "error": { "type": "ERROR_CODE", "message": "Human-readable description" } }
The following HTTP errors can occur:
HTTP status | Error code | Condition |
|---|---|---|
|
| A path parameter is missing, the input items are missing or invalid, or the last input is not a user message. |
|
| The workspace is not enrolled in the preview, or a workspace admin has not turned on the preview. |
|
| The caller lacks CAN VIEW permission on the Genie Agent. |
|
| The Genie Agent or conversation does not exist. |
|
| A response is already being generated for the conversation. |
|
| An unexpected server error occurred. |
Streaming error codes
When a failure occurs mid-stream, a system error message (role: "system", status: "failed") is emitted as response.output_item.added, followed by the response.failed event. The error object on the Response carries a type and a code.
The type field is one of the following spec types:
| Description |
|---|---|
| An internal server failure that the client did not cause. |
| A malformed or semantically invalid request, or a permissions issue the user can act on. |
| A referenced resource does not exist. |
| The model failed to process an otherwise valid request. |
| The request was rate limited. |
The code field provides more detail:
|
| Description |
|---|---|---|
|
| An unexpected server error. The message is always |
|
| A SQL query failed to execute. |
|
| An upstream dependency is temporarily unavailable. |
|
| The request or an upstream call timed out. |
|
| The model is temporarily unavailable. |
|
| The conversation history exceeded the model's context window. |
|
| A content filter blocked the response. |
|
| Too many concurrent requests, or an upstream rate limit was reached. |
|
| The workspace exceeded its usage budget for Agent mode. |
|
| The caller lacks permission to use the configured SQL warehouse. |
|
| No queryable tables are available in the Genie Agent. |
|
| The request was malformed or missing required fields. |
|
| The caller lost permission, or delegation failed during execution. |
|
| A concurrent operation conflicted with the request. |
|
| The configured SQL warehouse does not exist or was deleted. |
|
| A referenced resource was not found during execution. |
Frequently asked questions
The following questions cover common topics for the Agent mode APIs.
How long do responses take?
Response time depends on the complexity of the question. Single-query questions can complete in under a minute. Multi-query research can take several minutes. The stream has a server-side timeout of 90 minutes.
Can I poll instead of streaming?
Yes. Send the request to create a response, then use the conversation ID from the response.created event to retrieve the conversation items. The items endpoint returns the full conversation history, including in-progress responses. Poll the top-level status field on the items-list response until it is completed or failed.
How does a multi-turn conversation work?
Pass the conversation ID from a previous response in your next request. The agent has access to all prior queries and results in the conversation, and can reference them in the report.
Is the markdown output format stable?
Text content, including report chunks, reasoning text, and query result output, is returned in markdown. The exact markdown structure, such as heading levels and table formatting, is generated by the model and is not guaranteed to be stable across requests or API versions. Treat markdown output as best-effort formatted text, and use the structured fields, such as columns and preview rows, as the stable, machine-readable representation of the data.
Can I retrieve visualizations?
Yes. Retrieve visualizations with the download message attachment visualization endpoint. See GET /api/2.0/genie/spaces/{space_id}/conversations/{conversation_id}/messages/{message_id}/attachments/{attachment_id}/query-result/visualization in the REST API reference.
Do query results expire?
Yes. SQL query results follow the same expiration policy as the Statement Execution API. After results expire, the statement ID no longer returns them. The preview rows in the response metadata remain available from the conversation items endpoint.
How do I know which tables the agent can query?
The agent can only query tables that you add to the Genie Agent. It cannot access your full catalog. For the best results, add column descriptions, sample queries, and join instructions. See Curate an effective Genie Agent.