Agents
List, create, update and run the workspace's agents; follow their runs, steps and approvals.
List Agents#
/v1/agentsagents_listThe workspace's Agents, oldest first. Archived Agents are left out unless you ask for them with status=archived.
Each item is a summary (id, name, status, active_version_id, timestamps). Fetch GET /v1/agents/{id} for the plan, wake-ups and schedule.
status is one of draft (never turned on), active (listening for its wake-ups), paused, archived.
GET /v1/agents?status=active&limit=10Query parameters
statusstringoptionalOnly Agents in this state.
"draft""active""paused""archived"limitintegeroptionalHow many items to return, 1–100. Default 25.
Default25min 1max 100cursorstringoptionalThe
next_cursorfrom the previous page. Omit for the first page.
Can fail with 400 · 401 · 404 · 429 · 500 — the shape is in Errors & limits.
curl "https://app.attria.io/api/v1/agents?status=active&limit=10" \
-H "Authorization: Bearer $ATTRIA_API_KEY"const res = await fetch("https://app.attria.io/api/v1/agents?status=active&limit=10", {
headers: {
Authorization: `Bearer ${process.env.ATTRIA_API_KEY}`,
},
});
const data = await res.json();import os, requests
res = requests.get(
"https://app.attria.io/api/v1/agents?status=active&limit=10",
headers={
"Authorization": f"Bearer {os.environ['ATTRIA_API_KEY']}",
},
timeout=30,
)
data = res.json()Create an Agent from a description#
/v1/agentsagents_createDescribe an Agent in plain language and Attria's Agent Builder drafts its operating plan — the same builder as Agent Studio, with the same checks. The new Agent is a draft: turn it on with POST /v1/agents/{id}/activate.
The answer is an agent_build:
status: "built"— the plan was drafted;agentis the full Agent andmessageis the builder's summary.status: "needs_input"— the builder needs an answer first.questionslists them (each with suggestedoptions). The draft Agent already exists: answer withPATCH /v1/agents/{id}and amessage. Sendauto: trueto forbid questions.
Uses credits (a model call). Takes 10–90 seconds. Send an Idempotency-Key header: a retry with the same key returns the first result instead of building a second Agent.
{
"name": "Lead follow-up",
"message": "When a new Lead object is created, email them a friendly intro within 5 minutes and notify me.",
"auto": true
}Slow: can take several minutes; keep the connection open (the server allows up to 800 s).
auto: true lets Attria decide instead of answering with status: "needs_input" (questions or an outline to confirm).
Send an Idempotency-Key header: a retry with the same key replays the first result instead of doing the work twice.
Headers
Idempotency-KeystringoptionalAny unique string (a UUID) per logical write. Retrying with the same key replays the original result.
Bodyapplication/json
namestringoptionalA name for the Agent. The builder may refine it.
max length 120messagestringrequiredWhat the Agent should do, or what to change — plain language, as you would type it in Agent Studio.
max length 20000autobooleanoptionaltrue: the builder must draft the plan now and may not ask questions.false(default): it may answerneeds_inputwith questions.Defaultfalse
Can fail with 400 · 401 · 402 · 404 · 409 · 429 · 500 — the shape is in Errors & limits.
curl -X POST "https://app.attria.io/api/v1/agents" \
-H "Authorization: Bearer $ATTRIA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"name": "Lead follow-up",
"message": "When a new Lead object is created, email them a friendly intro within 5 minutes and notify me.",
"auto": true
}'const res = await fetch("https://app.attria.io/api/v1/agents", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ATTRIA_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
name: "Lead follow-up",
message: "When a new Lead object is created, email them a friendly intro within 5 minutes and notify me.",
auto: true,
}),
});
const data = await res.json();import os, uuid, requests
res = requests.post(
"https://app.attria.io/api/v1/agents",
headers={
"Authorization": f"Bearer {os.environ['ATTRIA_API_KEY']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={
"name": "Lead follow-up",
"message": "When a new Lead object is created, email them a friendly intro within 5 minutes and notify me.",
"auto": True,
},
timeout=900, # a turn that waits can take minutes
)
data = res.json()Get an Agent#
/v1/agents/{id}agents_getOne Agent in full:
profile— purpose, instructions, autonomy (automatic,ask_first, …), model and tool grants.plan.nodes/plan.edges— the operating plan as drawn in Agent Studio (kindisagent,trigger,email,ai_decide,branch, …).wakeups— every way it can be woken (chat,schedule,webhook,object_created,object_updated,integration_trigger,app_call), each with its livedeploymentwhen the Agent is active.schedule— the scheduled wake-ups and theirnext_run_at(UTC).validation—ready: truewhen Activate would succeed; otherwiseissuessays what to fix.pending_approvals— how many actions are waiting for a person (seeGET /v1/approvals).
Secrets never appear: integration credentials are stored encrypted and config values under secret-looking keys are masked.
Path parameters
idstringrequired
Can fail with 400 · 401 · 404 · 429 · 500 — the shape is in Errors & limits.
curl "https://app.attria.io/api/v1/agents/5b7e2c8e-1f0a-4c3d-9e8b-7a6f5d4c3b2a" \
-H "Authorization: Bearer $ATTRIA_API_KEY"const res = await fetch("https://app.attria.io/api/v1/agents/5b7e2c8e-1f0a-4c3d-9e8b-7a6f5d4c3b2a", {
headers: {
Authorization: `Bearer ${process.env.ATTRIA_API_KEY}`,
},
});
const data = await res.json();import os, requests
res = requests.get(
"https://app.attria.io/api/v1/agents/5b7e2c8e-1f0a-4c3d-9e8b-7a6f5d4c3b2a",
headers={
"Authorization": f"Bearer {os.environ['ATTRIA_API_KEY']}",
},
timeout=30,
)
data = res.json()Change an Agent#
/v1/agents/{id}agents_updateRename an Agent, or ask the Agent Builder to change its plan in plain language — one Agent Studio turn. The builder sees the current plan and this Agent's builder history, so a message can simply answer the questions from a needs_input result.
namealone renames it (no credits).messageruns a builder turn and answers with anagent_build(builtorneeds_input), like create.
Changes edit the draft. An active Agent keeps running its activated version until you activate again.
{ "message": "Also send me an SMS when the lead's budget is over $10k.", "auto": true }Slow: can take several minutes; keep the connection open (the server allows up to 800 s).
auto: true lets Attria decide instead of answering with status: "needs_input" (questions or an outline to confirm).
Send an Idempotency-Key header: a retry with the same key replays the first result instead of doing the work twice.
Path parameters
idstringrequired
Headers
Idempotency-KeystringoptionalAny unique string (a UUID) per logical write. Retrying with the same key replays the original result.
Bodyapplication/json
namestringoptionalA new name.
max length 120messagestringoptionalWhat the Agent should do, or what to change — plain language, as you would type it in Agent Studio.
max length 20000autobooleanoptionaltrue: the builder must draft the plan now and may not ask questions.false(default): it may answerneeds_inputwith questions.Defaultfalse
Can fail with 400 · 401 · 402 · 404 · 409 · 429 · 500 — the shape is in Errors & limits.
curl -X PATCH "https://app.attria.io/api/v1/agents/5b7e2c8e-1f0a-4c3d-9e8b-7a6f5d4c3b2a" \
-H "Authorization: Bearer $ATTRIA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"message": "Also send me an SMS when the lead'\''s budget is over $10k.",
"auto": true
}'const res = await fetch("https://app.attria.io/api/v1/agents/5b7e2c8e-1f0a-4c3d-9e8b-7a6f5d4c3b2a", {
method: "PATCH",
headers: {
Authorization: `Bearer ${process.env.ATTRIA_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
message: "Also send me an SMS when the lead's budget is over $10k.",
auto: true,
}),
});
const data = await res.json();import os, uuid, requests
res = requests.patch(
"https://app.attria.io/api/v1/agents/5b7e2c8e-1f0a-4c3d-9e8b-7a6f5d4c3b2a",
headers={
"Authorization": f"Bearer {os.environ['ATTRIA_API_KEY']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={
"message": "Also send me an SMS when the lead's budget is over $10k.",
"auto": True,
},
timeout=900, # a turn that waits can take minutes
)
data = res.json()Turn an Agent on#
/v1/agents/{id}/activateagents_activateCompiles the draft plan, provisions every wake-up (schedules, webhooks, connected-app triggers) and publishes one immutable version. From then on the Agent wakes by itself.
Answers { status: "active", version, version_id, deployments }. A webhook deployment carries its endpoint: POST JSON there to wake the Agent. Keep that URL private — anyone holding it can wake this Agent.
If the plan is not ready the answer is 422 with error.details.issues — the same list GET /v1/agents/{id} shows under validation. Activating an active Agent publishes a new version from the current draft.
Slow: can take several minutes; keep the connection open (the server allows up to 800 s).
Send an Idempotency-Key header: a retry with the same key replays the first result instead of doing the work twice.
Path parameters
idstringrequired
Headers
Idempotency-KeystringoptionalAny unique string (a UUID) per logical write. Retrying with the same key replays the original result.
Can fail with 400 · 401 · 402 · 404 · 409 · 429 · 500 — the shape is in Errors & limits.
curl -X POST "https://app.attria.io/api/v1/agents/5b7e2c8e-1f0a-4c3d-9e8b-7a6f5d4c3b2a/activate" \
-H "Authorization: Bearer $ATTRIA_API_KEY" \
-H "Idempotency-Key: $(uuidgen)"const res = await fetch("https://app.attria.io/api/v1/agents/5b7e2c8e-1f0a-4c3d-9e8b-7a6f5d4c3b2a/activate", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ATTRIA_API_KEY}`,
"Idempotency-Key": crypto.randomUUID(),
},
});
const data = await res.json();import os, uuid, requests
res = requests.post(
"https://app.attria.io/api/v1/agents/5b7e2c8e-1f0a-4c3d-9e8b-7a6f5d4c3b2a/activate",
headers={
"Authorization": f"Bearer {os.environ['ATTRIA_API_KEY']}",
"Idempotency-Key": str(uuid.uuid4()),
},
timeout=900, # a turn that waits can take minutes
)
data = res.json()Pause an Agent#
/v1/agents/{id}/pauseagents_pauseStops every wake-up (schedules, webhooks, connected-app triggers are torn down) and sets the Agent to paused. Runs already in flight finish. Turn it back on with POST /v1/agents/{id}/activate. Pausing a paused Agent is harmless.
Send an Idempotency-Key header: a retry with the same key replays the first result instead of doing the work twice.
Path parameters
idstringrequired
Headers
Idempotency-KeystringoptionalAny unique string (a UUID) per logical write. Retrying with the same key replays the original result.
Can fail with 400 · 401 · 402 · 404 · 409 · 429 · 500 — the shape is in Errors & limits.
curl -X POST "https://app.attria.io/api/v1/agents/5b7e2c8e-1f0a-4c3d-9e8b-7a6f5d4c3b2a/pause" \
-H "Authorization: Bearer $ATTRIA_API_KEY" \
-H "Idempotency-Key: $(uuidgen)"const res = await fetch("https://app.attria.io/api/v1/agents/5b7e2c8e-1f0a-4c3d-9e8b-7a6f5d4c3b2a/pause", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ATTRIA_API_KEY}`,
"Idempotency-Key": crypto.randomUUID(),
},
});
const data = await res.json();import os, uuid, requests
res = requests.post(
"https://app.attria.io/api/v1/agents/5b7e2c8e-1f0a-4c3d-9e8b-7a6f5d4c3b2a/pause",
headers={
"Authorization": f"Bearer {os.environ['ATTRIA_API_KEY']}",
"Idempotency-Key": str(uuid.uuid4()),
},
timeout=30,
)
data = res.json()List an Agent's runs#
/v1/agents/{id}/runsagents_runs_listThe Agent's runs, newest first — every execution of its plan, whether woken by a person talking to it, a schedule, a webhook, an object change or a connected app.
status is running, waiting (paused for time, an event or an approval — see waiting_for), completed, failed or cancelled. Filter with status, or with thread_id to find the run of one conversation. Fetch GET /v1/runs/{id} for its steps.
GET /v1/agents/7c1e…/runs?status=waitingPath parameters
idstringrequired
Query parameters
statusstringoptionalOnly runs in this state.
"running""waiting""completed""failed""cancelled"thread_idstringoptionalOnly runs started by this conversation.
limitintegeroptionalHow many items to return, 1–100. Default 25.
Default25min 1max 100cursorstringoptionalThe
next_cursorfrom the previous page. Omit for the first page.
Can fail with 400 · 401 · 404 · 429 · 500 — the shape is in Errors & limits.
curl "https://app.attria.io/api/v1/agents/5b7e2c8e-1f0a-4c3d-9e8b-7a6f5d4c3b2a/runs" \
-H "Authorization: Bearer $ATTRIA_API_KEY"const res = await fetch("https://app.attria.io/api/v1/agents/5b7e2c8e-1f0a-4c3d-9e8b-7a6f5d4c3b2a/runs", {
headers: {
Authorization: `Bearer ${process.env.ATTRIA_API_KEY}`,
},
});
const data = await res.json();import os, requests
res = requests.get(
"https://app.attria.io/api/v1/agents/5b7e2c8e-1f0a-4c3d-9e8b-7a6f5d4c3b2a/runs",
headers={
"Authorization": f"Bearer {os.environ['ATTRIA_API_KEY']}",
},
timeout=30,
)
data = res.json()Talk to an Agent (run it)#
/v1/agents/{id}/runsagents_runs_createSend an Agent a message — or a JSON payload as an event — exactly as someone typing to it in Attria. The Agent decides whether to answer from what it knows or to run its plan (emails, research, object writes, …). A run may pause for an approval; see GET /v1/approvals.
The answer is an agent_invocation: answer (what the Agent said), status (completed, waiting, failed, cancelled), run_id when it ran, the steps it took, and thread_id. Pass thread_id back to continue the same conversation.
Idempotency. Send an Idempotency-Key: a retry with the same key and body is answered from the first run and never runs the Agent — its emails, webhooks, credits — twice.
Long runs.
stream: true— server-sent events:started({ thread_id }) at once, then oneresult(the invocation) orerror.background: true— answers202at once withstatus: "running",thread_idand theidempotency_keyin use (minted if you sent none). To get the result, repeat the same request with the same key:202while it runs, then the finished invocation. The run also appears inGET /v1/agents/{id}/runs?thread_id=….
Uses credits. Works on draft Agents too (a draft answers but only acts through its chat wake-up).
{ "message": "Summarise yesterday's new leads and email me the top 3.", "background": true }Slow: can take several minutes. Agents should send background: true and poll GET /v1/turns/{id} (tool studio_turn_get).
stream: true answers with Server-Sent Events; the last event is result (the same body a waiting call returns) or error.
background: true answers 202 Accepted at once with an id; poll GET /v1/turns/{id} (tool studio_turn_get) every 5–10 s until it finishes.
Send an Idempotency-Key header: a retry with the same key replays the first result instead of doing the work twice.
Path parameters
idstringrequired
Headers
Idempotency-KeystringoptionalAny unique string (a UUID) per logical write. Retrying with the same key replays the original result.
Bodyapplication/json
messagestringoptionalWhat to say to the Agent.
max length 20000payloadobjectoptionalA JSON event for the Agent to act on, instead of or beside a message.
thread_idstring · uuidoptionalContinue this conversation (from an earlier invocation).
streambooleanoptionalAnswer as server-sent events.
backgroundbooleanoptionalAnswer 202 at once; poll by repeating the request with the same Idempotency-Key.
Can fail with 400 · 401 · 402 · 404 · 409 · 429 · 500 — the shape is in Errors & limits.
curl -X POST "https://app.attria.io/api/v1/agents/5b7e2c8e-1f0a-4c3d-9e8b-7a6f5d4c3b2a/runs" \
-H "Authorization: Bearer $ATTRIA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"message": "Summarise yesterday'\''s new leads and email me the top 3.",
"background": true
}'const res = await fetch("https://app.attria.io/api/v1/agents/5b7e2c8e-1f0a-4c3d-9e8b-7a6f5d4c3b2a/runs", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ATTRIA_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
message: "Summarise yesterday's new leads and email me the top 3.",
background: true,
}),
});
const data = await res.json();import os, uuid, requests
res = requests.post(
"https://app.attria.io/api/v1/agents/5b7e2c8e-1f0a-4c3d-9e8b-7a6f5d4c3b2a/runs",
headers={
"Authorization": f"Bearer {os.environ['ATTRIA_API_KEY']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={
"message": "Summarise yesterday's new leads and email me the top 3.",
"background": True,
},
timeout=900, # a turn that waits can take minutes
)
data = res.json()Get a run with its steps#
/v1/runs/{id}runs_getOne Agent run in full: its status, the event that woke it, every step it took in order (each with the plan node's kind, its input, result and error), any sub-tasks it delegated (tasks, with the tools they called), its approvals, what it cost (cost_usd) and — for a conversation — the Agent's answer.
Poll this while status is running or waiting.
Path parameters
idstringrequired
Can fail with 400 · 401 · 404 · 429 · 500 — the shape is in Errors & limits.
curl "https://app.attria.io/api/v1/runs/5b7e2c8e-1f0a-4c3d-9e8b-7a6f5d4c3b2a" \
-H "Authorization: Bearer $ATTRIA_API_KEY"const res = await fetch("https://app.attria.io/api/v1/runs/5b7e2c8e-1f0a-4c3d-9e8b-7a6f5d4c3b2a", {
headers: {
Authorization: `Bearer ${process.env.ATTRIA_API_KEY}`,
},
});
const data = await res.json();import os, requests
res = requests.get(
"https://app.attria.io/api/v1/runs/5b7e2c8e-1f0a-4c3d-9e8b-7a6f5d4c3b2a",
headers={
"Authorization": f"Bearer {os.environ['ATTRIA_API_KEY']}",
},
timeout=30,
)
data = res.json()List approvals#
/v1/approvalsapprovals_listActions Agents want to take that need a person's yes — sending an email, spending money, changing or deleting records, depending on each Agent's autonomy. Pending ones first-come-first-listed.
Each shows summary (a sentence), the exact input that will run, its risk (write, send, spend, destructive) and can_always_allow. Decide with POST /v1/approvals/{id}.
GET /v1/approvals?status=pending&agent_id=7c1e…Query parameters
statusstringoptionalWhich decisions to list. Default
pending."pending""approved""rejected""all"Default"pending"agent_idstringoptionalOnly this Agent's approvals.
limitintegeroptionalHow many items to return, 1–100. Default 25.
Default25min 1max 100cursorstringoptionalThe
next_cursorfrom the previous page. Omit for the first page.
Can fail with 400 · 401 · 404 · 429 · 500 — the shape is in Errors & limits.
curl "https://app.attria.io/api/v1/approvals" \
-H "Authorization: Bearer $ATTRIA_API_KEY"const res = await fetch("https://app.attria.io/api/v1/approvals", {
headers: {
Authorization: `Bearer ${process.env.ATTRIA_API_KEY}`,
},
});
const data = await res.json();import os, requests
res = requests.get(
"https://app.attria.io/api/v1/approvals",
headers={
"Authorization": f"Bearer {os.environ['ATTRIA_API_KEY']}",
},
timeout=30,
)
data = res.json()Approve or reject an Agent action#
/v1/approvals/{id}approvals_decideDecide one pending approval, as the key's owner.
approve— the call runs now exactly as shown in the approval'sinput, and a run waiting on it resumes. The answer carries the resumed run'soutcome.reject— the call never runs. A run waiting on it is cancelled; a call filed from inside a task is closed and the task has already moved on.
always: true (with approve) also lets this Agent take this kind of action without asking again. Only allowed where can_always_allow is true.
A decided approval answers 409.
{ "decision": "approve" }Slow: can take several minutes; keep the connection open (the server allows up to 800 s).
Send an Idempotency-Key header: a retry with the same key replays the first result instead of doing the work twice.
Path parameters
idstringrequired
Headers
Idempotency-KeystringoptionalAny unique string (a UUID) per logical write. Retrying with the same key replays the original result.
Bodyapplication/json
decisionstringrequiredapproveruns the action;rejectrefuses it."approve""reject"alwaysbooleanoptionalWith
approve: remember this action for this Agent.Defaultfalse
Can fail with 400 · 401 · 402 · 404 · 409 · 429 · 500 — the shape is in Errors & limits.
curl -X POST "https://app.attria.io/api/v1/approvals/5b7e2c8e-1f0a-4c3d-9e8b-7a6f5d4c3b2a" \
-H "Authorization: Bearer $ATTRIA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"decision": "approve"
}'const res = await fetch("https://app.attria.io/api/v1/approvals/5b7e2c8e-1f0a-4c3d-9e8b-7a6f5d4c3b2a", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ATTRIA_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
decision: "approve",
}),
});
const data = await res.json();import os, uuid, requests
res = requests.post(
"https://app.attria.io/api/v1/approvals/5b7e2c8e-1f0a-4c3d-9e8b-7a6f5d4c3b2a",
headers={
"Authorization": f"Bearer {os.environ['ATTRIA_API_KEY']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={
"decision": "approve",
},
timeout=900, # a turn that waits can take minutes
)
data = res.json()