Agent API
The Agent API lets you programmatically launch, monitor, and manage background AI agents that work on your documents. Agents run asynchronously, optionally using a workflow, and produce structured artifacts (markdown documents or tables) as output.
The API operates on background agents only — interactive chat sessions are not included in list or detail responses.
New here? Start with the Quickstart — an interactive notebook you can run in one click.
Authentication
All requests require a Nomic Platform API key with the developer:agent scope.
Pass it as a Bearer token:
curl -H "Authorization: Bearer npk_YOUR_API_KEY" \
https://<your-domain>.nomic.ai/api/v0/agents
Create API keys from the Developer Console in your Platform instance settings.
Agent lifecycle
┌─────────┐
│ waiting │
└────┬────┘
▼
┌─────── running ───────┐
│ │ │
│ ▼ │
│ awaiting_tool │
│ │ │
▼ ▼ ▼
finished stopped failed
└──────────┬───────────┘
│ follow-up
▼
running
| Status | Description |
|---|---|
waiting | Agent is queued and waiting to begin processing |
running | Agent is actively processing |
awaiting_tool | Agent is waiting for an asynchronous tool call to resolve |
finished | Agent completed successfully; artifacts are available |
stopped | Agent was stopped by the user |
failed | Agent encountered an error |
Any agent in a terminal state (finished, stopped, or failed) can be
resumed with a follow-up, which transitions it back to
running.
Endpoints
List agents
GET /api/v0/agents
Scope: developer:agent · Rate limit: Standard (300 req / min)
Returns a paginated list of background agents for the authenticated user.
Query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | number | 20 | Number of agents to return (max 100) |
cursor | string | — | Pagination cursor from previous response |
status | string | — | Filter by status |
workflowId | string | — | Filter by workflow ID. Pass null to exclude agents launched from a workflow. |
Response:
{
"data": [
{
"id": "019abc12-...",
"status": "finished",
"workflowId": "019def34-...",
"projectId": null,
"artifacts": [
{
"id": "019ccc00-...",
"name": "Results",
"type": "MARKDOWN_DOCUMENT",
"createdAt": "2026-04-09T10:35:00.000Z"
}
],
"createdAt": "2026-04-09T10:30:00.000Z",
"updatedAt": "2026-04-09T10:45:00.000Z"
}
],
"nextCursor": null
}
Launch agent
POST /api/v0/agents
Scope: developer:agent · Rate limit: Heavy (30 req / min)
Start a new background agent. The agent runs asynchronously and can be monitored via Get agent.
A simple agent runs from prompt.text, with optional prompt.images
for visual context and optional fileIds scoping the files the agent can read:
curl -X POST https://<your-domain>.nomic.ai/api/v0/agents \
-H "Authorization: Bearer npk_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": {
"text": "Summarize the attached drawings and flag anything unusual."
},
"fileIds": ["019aaa00-...", "019aaa01-..."]
}'
Pass workflowId to instead launch a workflow agent — a run of a pre-built
workflow. Workflows come in two flavors: ones whose work is driven by a text
prompt (same prompt.text shape as a simple agent), and ones that take files
through named input slots. For the latter, pass workflowInputs in place of
prompt. The workflow's own attached files, tags, and reference artifacts are
included automatically; you do not need to pass them.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
prompt.text | string | Conditional | Text instruction. Required for simple agents and prompt-driven workflow agents. Must be omitted when a workflow declares file-input slots (use workflowInputs instead). |
prompt.images | Array<{ media_type: string, data: string }> | No | Inline images for simple agents and prompt-driven workflow agents. Up to 4 images. Each data value is raw base64 image bytes, not a data URL. |
workflowId | string | No | Workflow ID to run (see Files & Workflows). Omit to launch a simple agent. |
fileIds | string[] | No | Files and folders the agent can read (see Files & Workflows to find IDs). Simple agents only; not allowed alongside workflowId. |
workflowInputs | Record<string, string | string[] | null> | Conditional | Named file inputs keyed by slot name. For multiple=false, pass a single file UUID string. For multiple=true, pass an array of file UUID strings. Pass explicit null to leave an optional slot unset. Requires workflowId. |
capabilities | object | No | Optional capabilities (extra tools) to enable. Simple agents only; not allowed alongside workflowId. See Capabilities. |
projectId | string | No | Project to scope the agent to. |
A body that provides neither prompt.text nor workflowId is rejected
with 400. The server also rejects combinations that mix simple-agent
fields with workflow fields — see the field table above.
Supported image media types are image/jpeg, image/png, image/webp, and
image/gif. Each image can be up to 20 MB after base64 decoding. Image prompts
are part of prompt, so they cannot be used with workflows that declare
file-input slots and therefore require workflowInputs instead of prompt.
Example — simple agent with an image prompt:
curl -X POST https://<your-domain>.nomic.ai/api/v0/agents \
-H "Authorization: Bearer npk_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": {
"text": "Review this site photo and list visible safety issues.",
"images": [
{
"media_type": "image/jpeg",
"data": "<base64-encoded-image-bytes>"
}
]
}
}'
Example — workflow agent, file-input slots:
curl -X POST https://<your-domain>.nomic.ai/api/v0/agents \
-H "Authorization: Bearer npk_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"workflowId": "019def34-...",
"workflowInputs": {
"Drawing Set": ["019aaa00-...", "019aaa01-..."],
"Standards": "019aaa02-...",
"Reference": null
}
}'
Notes:
- Slot names must be unique in the workflow. If a workflow defines duplicate names, launch returns
400when you try to set that slot by name. - Omitting a slot key is invalid; include every requested slot and use explicit
nullfor optional slots you want to leave unset.
Example — workflow agent, prompt-driven:
curl -X POST https://<your-domain>.nomic.ai/api/v0/agents \
-H "Authorization: Bearer npk_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"workflowId": "019abc12-...",
"prompt": {
"text": "Analyze the compliance status of our current project"
}
}'
Capabilities
Capabilities are optional tools you can switch on for an agent beyond its base abilities. They mirror the capability toggles in the product UI.
| Capability | Type | Tool unlocked | Description |
|---|---|---|---|
codeSearch | boolean | { jurisdiction?: string } | find_relevant_codes | Search building, fire, electrical, plumbing, and other regulatory codes and standards (e.g. IBC, NFPA, NEC). Refers to regulations — not source code. |
webSearch | boolean | web_search | Search the public web for current information. |
Pass capabilities when launching a simple agent. Set a capability to
true to enable it; for codeSearch you may instead pass an object with a
default jurisdiction to bias regulatory search (which also enables it):
curl -X POST https://<your-domain>.nomic.ai/api/v0/agents \
-H "Authorization: Bearer npk_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": {
"text": "Check whether this stair detail meets egress requirements."
},
"fileIds": ["019aaa00-..."],
"capabilities": {
"codeSearch": { "jurisdiction": "California" },
"webSearch": true
}
}'
Workflow agents inherit their capabilities from the workflow — the same
way they inherit mode, model, and attached files. capabilities is therefore
rejected with 400 when combined with workflowId.
Capabilities are subject to availability for your organization. Requesting a
capability you are not entitled to is rejected with 400.
Response (201 Created):
{
"data": {
"id": "019abc12-...",
"status": "waiting",
"workflowId": "019def34-...",
"projectId": null,
"parentSessionId": null,
"activeFileIds": ["019aaa00-...", "019aaa01-...", "019aaa02-..."],
"artifacts": [],
"createdAt": "2026-04-09T10:30:00.000Z",
"updatedAt": "2026-04-09T10:30:00.000Z"
}
}
For simple agents the response workflowId is null, and
activeFileIds reflects the files passed in fileIds (plus any added
during the run).
Get agent
GET /api/v0/agents/{id}
Scope: developer:agent · Rate limit: Standard (300 req / min)
Retrieve details of a specific agent. When the agent is finished, the response
includes artifacts.
Response:
{
"data": {
"id": "019abc12-...",
"status": "finished",
"workflowId": "019def34-...",
"projectId": null,
"parentSessionId": null,
"activeFileIds": ["019aaa00-..."],
"artifacts": [
{
"id": "019ccc00-...",
"name": "Review Results",
"type": "MARKDOWN_DOCUMENT",
"createdAt": "2026-04-09T10:35:00.000Z"
},
{
"id": "019ccc01-...",
"name": "Issues",
"type": "TABLE",
"createdAt": "2026-04-09T10:36:00.000Z"
}
],
"createdAt": "2026-04-09T10:30:00.000Z",
"updatedAt": "2026-04-09T10:45:00.000Z"
}
}
parentSessionId is null for top-level agents. For sub-agents (e.g.
spawned by dispatch_page_agents), it contains the parent agent's ID.
Get agent conversation
GET /api/v0/agents/{id}/conversation
Scope: developer:agent · Rate limit: Standard (300 req / min)
Retrieve the conversation history for an agent, linearized to the current active branch. If the conversation has been edited (branched), only the newest-leaf chain is returned — historical branches are not exposed.
Both top-level agents and sub-agents (spawned by dispatch_page_agents)
are fetchable. Sub-agent sessions inherit their parent's ownership, so
the same API key works.
Query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
include | string | — | Comma-separated list of optional detail. Currently supports steps (thinking, tool, compaction). |
Message types:
By default, only user, assistant, and error messages are returned.
When include=steps is passed, the response additionally includes
thinking, tool, and compaction events.
| Type | Always | With steps | Description |
|---|---|---|---|
user | ✓ | ✓ | User prompt text |
assistant | ✓ | ✓ | Agent response text |
error | ✓ | ✓ | Error encountered during processing |
thinking | ✓ | Model reasoning. redacted: true when the provider withheld the content. | |
tool | ✓ | Tool invocation. subAgentId is set for dispatch_page_agents calls. | |
compaction | ✓ | Context-window compaction event |
Hidden or unavailable internal tool events are omitted. The think tool is
surfaced as a thinking message, and compact as a compaction message,
matching the UI representation.
Response (default):
{
"data": {
"id": "019abc12-...",
"messages": [
{
"id": "019eee00-...",
"createdAt": "2026-04-09T10:30:00.000Z",
"type": "user",
"text": "Review this submittal for compliance"
},
{
"id": "019eee01-...",
"createdAt": "2026-04-09T10:30:15.000Z",
"type": "assistant",
"text": "I'll review the HVAC submittal against the project specifications..."
}
]
}
}
Response (?include=steps):
{
"data": {
"id": "019abc12-...",
"messages": [
{
"id": "019eee00-...",
"createdAt": "2026-04-09T10:30:00.000Z",
"type": "user",
"text": "Review this submittal for compliance"
},
{
"id": "019eee02-...",
"createdAt": "2026-04-09T10:30:01.000Z",
"type": "thinking",
"redacted": false,
"text": "I need to check the HVAC specs against code requirements..."
},
{
"id": "019eee03-...",
"createdAt": "2026-04-09T10:30:02.000Z",
"type": "tool",
"toolName": "find_relevant_pages",
"status": "completed"
},
{
"id": "019eee04-...",
"createdAt": "2026-04-09T10:30:10.000Z",
"type": "tool",
"toolName": "dispatch_page_agents",
"status": "completed",
"subAgentId": "019fff00-..."
},
{
"id": "019eee01-...",
"createdAt": "2026-04-09T10:30:15.000Z",
"type": "assistant",
"text": "I'll review the HVAC submittal against the project specifications..."
}
]
}
}
Recursing into sub-agents: When a tool message has subAgentId,
you can fetch that sub-agent's conversation with
GET /api/v0/agents/{subAgentId}/conversation.
Get artifact content
GET /api/v0/agents/{id}/artifacts/{artifactId}
Scope: developer:agent · Rate limit: Standard (300 req / min)
Retrieve the content of a specific artifact produced by an agent. Returns the
latest version. The content shape depends on the artifact type.
Path parameters:
| Parameter | Type | Description |
|---|---|---|
id | string | Agent ID |
artifactId | string | Artifact ID (from the agent's artifacts array) |
Response — MARKDOWN_DOCUMENT:
{
"data": {
"id": "019ccc00-...",
"name": "Review Results",
"type": "MARKDOWN_DOCUMENT",
"version": 3,
"content": "# Submittal Review\n\n## Summary\n\nThe HVAC submittal...",
"createdAt": "2026-04-09T10:35:00.000Z"
}
}
Response — TABLE:
For TABLE artifacts, content is a fully resolved object containing the
table schema and all row elements:
{
"data": {
"id": "019ccc01-...",
"name": "Findings",
"type": "TABLE",
"version": 2,
"content": {
"schema": {
"type": "object",
"properties": { "issue": { "type": "string" } }
},
"elements": [
{
"key": "row-1",
"value": { "issue": "Missing fire rating on wall assembly" }
}
]
},
"createdAt": "2026-04-09T10:36:00.000Z"
}
}
TABLE_SCHEMA and TABLE_ELEMENT artifacts return their parsed JSON content
directly.
Add follow-up
POST /api/v0/agents/{id}/followup
Scope: developer:agent · Rate limit: Heavy (30 req / min)
Send a follow-up message to an agent in a terminal state (finished,
stopped, or failed). The agent resumes processing with the new
instruction.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
prompt.text | string | Yes | Follow-up instruction |
prompt.images | Array<{ media_type: string, data: string }> | No | Inline images for the follow-up prompt, using the same shape and limits as launch |
Example:
curl -X POST https://<your-domain>.nomic.ai/api/v0/agents/019abc12-.../followup \
-H "Authorization: Bearer npk_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": {
"text": "Also check against ADA accessibility requirements"
}
}'
Response (202 Accepted):
Returns the full agent detail. The new turn is kicked off asynchronously —
the pipeline's transition to running races this response, so the
returned status reflects the current DB state and may still be the
prior terminal state for a brief window. Poll Get agent to
observe the next active-to-terminal transition.
Stop agent
POST /api/v0/agents/{id}/stop
Scope: developer:agent · Rate limit: Standard (300 req / min)
Request cancellation of an agent. A stopped agent can be resumed with a follow-up.
Idempotent — stopping an already-terminal (finished, stopped, or
failed) agent returns the agent in its current state without error.
Response (200 OK):
Returns the agent summary. For a waiting agent the transition to
stopped is immediate. For a running agent the transition is
asynchronous (the pipeline writes the final status on cleanup), so the
returned status may still be running — poll Get agent
to observe the final status.
Delete agent
DELETE /api/v0/agents/{id}
Scope: developer:agent · Rate limit: Standard (300 req / min)
Permanently delete an agent session and its messages and attachments. If the agent is currently running, an abort is broadcast first and the server waits briefly for the pipeline to release its internal lock before tearing down the row.
Artifacts produced by the agent are not deleted — their
creatingSessionId is set to null and they remain retrievable via their
own endpoints.
Response: 204 No Content on success, with an empty body.
Error responses
Errors use a standard envelope:
{
"error": "Human-readable description of the problem",
"code": "machine_readable_code"
}
| HTTP status | Code | Description |
|---|---|---|
| 400 | bad_request | Malformed body, missing required fields |
| 401 | unauthorized | Missing or invalid API key |
| 403 | forbidden | Valid key but not the agent's owner |
| 404 | not_found | Agent or artifact not found |
| 409 | invalid_state | Operation not allowed in the agent's current status |
| 429 | rate_limited | Too many requests; retry after Retry-After header |
| 500 | internal_server_error | Unexpected server error |
Full example
Upload a file, launch an agent against a workflow, poll until completion, and
retrieve results. Before running this you need a WORKFLOW_ID — obtain one from
List workflows or from the workflow's page in the
Platform UI. The example assumes the workflow has a single file-input slot named
"Documents"; for a workflow without slots, replace the workflowInputs field
with {"prompt": {"text": "..."}}.
import time
import requests
BASE_URL = "https://<your-domain>.nomic.ai/api/v0"
HEADERS = {"Authorization": "Bearer npk_YOUR_API_KEY"}
WORKFLOW_ID = "019def34-..." # ID of the workflow to run
# 1. Upload a file
with open("specs.pdf", "rb") as f:
upload = requests.post(
f"{BASE_URL}/files/upload",
headers=HEADERS,
files={"file": ("specs.pdf", f, "application/pdf")},
)
file_id = upload.json()["id"]
# 2. Launch an agent against the workflow
agent = requests.post(
f"{BASE_URL}/agents",
headers=HEADERS,
json={
"workflowId": WORKFLOW_ID,
"workflowInputs": {"Documents": [file_id]},
},
).json()["data"]
# 3. Poll until the agent reaches a terminal state
while agent["status"] not in ("finished", "failed", "stopped"):
time.sleep(5)
agent = requests.get(
f"{BASE_URL}/agents/{agent['id']}", headers=HEADERS
).json()["data"]
print(f"Status: {agent['status']}")
# 4. Retrieve artifact content
if agent["status"] == "finished" and agent.get("artifacts"):
for ref in agent["artifacts"]:
artifact = requests.get(
f"{BASE_URL}/agents/{agent['id']}/artifacts/{ref['id']}",
headers=HEADERS,
).json()["data"]
print(f"\n--- {artifact['name']} ({artifact['type']}) ---")
print(artifact["content"])