Skip to main content

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.

tip

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
StatusDescription
waitingAgent is queued and waiting to begin processing
runningAgent is actively processing
awaiting_toolAgent is waiting for an asynchronous tool call to resolve
finishedAgent completed successfully; artifacts are available
stoppedAgent was stopped by the user
failedAgent 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:

ParameterTypeDefaultDescription
limitnumber20Number of agents to return (max 100)
cursorstringPagination cursor from previous response
statusstringFilter by status
workflowIdstringFilter 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:

FieldTypeRequiredDescription
prompt.textstringConditionalText instruction. Required for simple agents and prompt-driven workflow agents. Must be omitted when a workflow declares file-input slots (use workflowInputs instead).
prompt.imagesArray<{ media_type: string, data: string }>NoInline 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.
workflowIdstringNoWorkflow ID to run (see Files & Workflows). Omit to launch a simple agent.
fileIdsstring[]NoFiles and folders the agent can read (see Files & Workflows to find IDs). Simple agents only; not allowed alongside workflowId.
workflowInputsRecord<string, string | string[] | null>ConditionalNamed 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.
capabilitiesobjectNoOptional capabilities (extra tools) to enable. Simple agents only; not allowed alongside workflowId. See Capabilities.
projectIdstringNoProject 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 400 when you try to set that slot by name.
  • Omitting a slot key is invalid; include every requested slot and use explicit null for 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.

CapabilityTypeTool unlockedDescription
codeSearchboolean | { jurisdiction?: string }find_relevant_codesSearch building, fire, electrical, plumbing, and other regulatory codes and standards (e.g. IBC, NFPA, NEC). Refers to regulations — not source code.
webSearchbooleanweb_searchSearch 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:

ParameterTypeDefaultDescription
includestringComma-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.

TypeAlwaysWith stepsDescription
userUser prompt text
assistantAgent response text
errorError encountered during processing
thinkingModel reasoning. redacted: true when the provider withheld the content.
toolTool invocation. subAgentId is set for dispatch_page_agents calls.
compactionContext-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:

ParameterTypeDescription
idstringAgent ID
artifactIdstringArtifact 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:

FieldTypeRequiredDescription
prompt.textstringYesFollow-up instruction
prompt.imagesArray<{ media_type: string, data: string }>NoInline 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 statusCodeDescription
400bad_requestMalformed body, missing required fields
401unauthorizedMissing or invalid API key
403forbiddenValid key but not the agent's owner
404not_foundAgent or artifact not found
409invalid_stateOperation not allowed in the agent's current status
429rate_limitedToo many requests; retry after Retry-After header
500internal_server_errorUnexpected 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"])