AGNTDocs

Tasks, autonomy and approvals

Run durable tasks that wait on people and resume on their own, decide per action type what needs a person's approval, and review, approve, edit and undo staged actions.

A task is a durable unit of work an assistant owns until it is finished, such as "Renew the Brightline Freight service contract". A task survives restarts, waits days for a reply, and resumes on its own. Every action it takes in the outside world passes through the user's autonomy settings, which decide whether the action runs immediately, after a review window, or only after a person approves it.

How it works

ConceptDescription
TaskThe durable record: title, owner, assistant, status, plan and activity timeline.
RunOne execution of the task by Prime. A task has many runs over its life.
ActivityOne entry on the task's timeline: a message in or out, a status change, an approval.
AlarmA scheduled wake. Every waiting task holds one, so no task is stranded.
ApprovalA batch of staged actions waiting for a person. The API calls it a cart.
Autonomy settingsPer user, one approval mode for each action type. They decide which actions need approval.
  create ──> pending ──process──> executing ──┬──> completed
                                              │
                    ┌─────────────────────────┤ needs a person or a time
                    v                         │
   awaiting_user_input / awaiting_non_user_response / alarm_set / scheduled
                    │                         ^
                    └── reply arrives, ───────┘
                        alarm fires, or
                        user sends /process

Reads, research and drafting happen inside a run. Side effects (a message to someone other than the user, a calendar change, a shared file, a phone call) are staged in a cart and released according to the user's autonomy settings.

Task statuses

StatusDescription
pendingCreated or woken, waiting for a run to start.
executingA run is in progress.
awaiting_user_inputNeeds the user. Reply with POST /tasks/:taskId/process.
awaiting_non_user_responseWaiting on someone else, such as an email reply. waitingOnContacts names them.
alarm_setWakes itself at alarm.wakeAt.
subtasks_runningWaiting on its own subtasks.
scheduledStarts at scheduledFor.
on_holdStopped by the user (POST /tasks/:taskId/stop) or held by the assistant. POST /tasks/:taskId/process resumes it.
pausedHeld by the system.
message_received, conversationA conversational thread at rest. A new message reopens it.
deferred_access, failed_accessHeld, or stopped, for missing calendar or account access.
credits_blockedOut of credits. Resumes when credits are restored.
completedFinished by the assistant.
done_user_markedMarked done by the user.
handled_by_otherAnother assistant took the thread. handledBy says which.
error, abandoned, archivedFailed, given up, or archived.

Every task has these guarantees:

  • No silent waits. A task cannot enter awaiting_user_input, awaiting_non_user_response or subtasks_running without an active alarm. If nobody replies, the alarm wakes the task to follow up or report back.
  • Replies route home. A reply from a person the task is waiting on, on the channel the assistant used to reach them, is attached to that task and wakes it. The next run sees the full history.
  • The owner decides when it is done. Only the owner can stop a task or mark it done. Marking a task done discards any cart it has pending.

A task resumes when any of these happens:

  1. A person it is waiting on replies.
  2. Its alarm fires.
  3. The user sends it a message with POST /tasks/:taskId/process.
  4. A staged cart is approved, cancelled or executed. The next run is told the outcome.

Create and run a task

All task calls act as a user. Pass X-User-Email with an account API key, or use a delegated SDK client. See Authentication.

Creating a task does not start it. Create the task, then call process.

curl https://api.agnt.ai/tasks \
  -X POST \
  -H "Authorization: Bearer $AGNT_API_KEY" \
  -H "X-User-Email: [email protected]" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Renew the Brightline Freight service contract",
    "description": "Harborview'\''s MSA with Brightline Freight ends 2027-01-01. Get their 2027 terms.",
    "assistant": "6702b4c1d2e3f4a5b6c7d8e9",
    "modelTier": "medium"
  }'
{
  "ok": true,
  "task": {
    "id": "6702c3a9b8c7d6e5f4a3b2c1",
    "type": "task",
    "title": "Renew the Brightline Freight service contract",
    "description": "Harborview's MSA with Brightline Freight ends 2027-01-01. Get their 2027 terms.",
    "status": "pending",
    "owner": "[email protected]",
    "modelTier": "medium",
    "createdBy": "user",
    "pendingCart": null,
    "alarm": null,
    "createdAt": "2026-11-02T16:24:11.000Z",
    "updatedAt": "2026-11-02T16:24:11.000Z"
  }
}
NameTypeRequiredDescription
titlestringYesShort name for the task.
assistantstringYesId of an assistant the user has. Another assistant returns 403.
descriptionstringNoWhat the user wants done, in their words.
statusstringNopending (default) waits for process. scheduled starts on its own at scheduledFor.
scheduledForstringNoISO 8601 time, with status: "scheduled".
modelTierstringNolow, medium, high or ultra. Fixed after the first run. See Model tiers.
skillsstring[]NoSkill names the task should use.
followersstring[]NoEmail addresses of people following the task.

Start the task. The same call sends the user's reply to a task in awaiting_user_input.

curl https://api.agnt.ai/tasks/6702c3a9b8c7d6e5f4a3b2c1/process \
  -X POST \
  -H "Authorization: Bearer $AGNT_API_KEY" \
  -H "X-User-Email: [email protected]" \
  -H "Content-Type: application/json" \
  -d '{ "message": "Dana Okafor at [email protected] handles renewals. The current MSA is attached.", "files": [{ "fileId": "6702c804b5c6d7e8f9a0b1c2" }] }'
{
  "ok": true,
  "process": {
    "success": true,
    "taskId": "6702c3a9b8c7d6e5f4a3b2c1",
    "executionId": "6702c3e4a5b6c7d8e9f0a1b2"
  }
}
NameTypeRequiredDescription
messagestringNoA message from the user, saved to the task before the run.
filesobject[]NoAttachments already in the user's drive, as { "fileId" }. Files the user cannot read are dropped.

The same flow with the TypeScript SDK:

import { AgntClient } from '@agnt-sdk/client';

const client = await AgntClient.create();
const jane = client.as('[email protected]');

const task = await jane.tasks.create({
  title: 'Renew the Brightline Freight service contract',
  assistant: '6702b4c1d2e3f4a5b6c7d8e9',
});
await jane.tasks.process(task.id, {
  message: 'Dana Okafor at [email protected] handles renewals.',
});

Follow a task

Read the task for its current state, and its activities for the timeline.

curl https://api.agnt.ai/tasks/6702c3a9b8c7d6e5f4a3b2c1 \
  -H "Authorization: Bearer $AGNT_API_KEY" \
  -H "X-User-Email: [email protected]"

curl "https://api.agnt.ai/tasks/6702c3a9b8c7d6e5f4a3b2c1/activities?limit=50" \
  -H "Authorization: Bearer $AGNT_API_KEY" \
  -H "X-User-Email: [email protected]"

Activities are newest first, in { "ok": true, "activities": [], "hasMore": true, "cursor": "<cursor>" }. Page older entries with before=<cursor>, passing the cursor back unchanged. Each activity has a type and a createdAt, and a message activity has a message with role, content and platform.

FieldDescription
statusWhere the task is in its lifecycle.
summaryWhat the assistant has done, once there is something to report.
planThe assistant's checklist, each item pending, done, skipped or blocked.
waitingOnContactsThe people the task is waiting to hear from.
alarmwakeAt, headline (the line to show the user) and status.
pendingCartA summary of what is staged for approval, or null.
effectiveApprovalMode, approvalLocksThe autonomy mode that applies right now, and any admin locks. Returned by GET /tasks/:taskId.

The API reference lists every field.

Stop, finish and reopen a task

# Stop the current run. The task goes to on_hold.
curl -X POST https://api.agnt.ai/tasks/6702c3a9b8c7d6e5f4a3b2c1/stop \
  -H "Authorization: Bearer $AGNT_API_KEY" \
  -H "X-User-Email: [email protected]"

# Mark done. Status becomes done_user_marked and any pending cart is discarded.
curl -X POST https://api.agnt.ai/tasks/6702c3a9b8c7d6e5f4a3b2c1/mark-done \
  -H "Authorization: Bearer $AGNT_API_KEY" \
  -H "X-User-Email: [email protected]"

# Reopen a done task. The assistant wakes and asks how to proceed.
curl -X POST https://api.agnt.ai/tasks/6702c3a9b8c7d6e5f4a3b2c1/mark-not-done \
  -H "Authorization: Bearer $AGNT_API_KEY" \
  -H "X-User-Email: [email protected]"

# Leave feedback: "like", "dislike", or null to clear. The value is accepted but not yet stored.
curl -X POST https://api.agnt.ai/tasks/6702c3a9b8c7d6e5f4a3b2c1/feedback \
  -H "Authorization: Bearer $AGNT_API_KEY" \
  -H "X-User-Email: [email protected]" \
  -H "Content-Type: application/json" \
  -d '{ "status": "like" }'
await jane.tasks.stop(task.id);
await jane.tasks.feedback(task.id, 'like');

Schedule a task

Create a task with "status": "scheduled" and a future scheduledFor. It starts on its own at that time.

curl https://api.agnt.ai/tasks \
  -X POST \
  -H "Authorization: Bearer $AGNT_API_KEY" \
  -H "X-User-Email: [email protected]" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Collect three vendor quotes for the lobby HVAC repair",
    "assistant": "6702b4c1d2e3f4a5b6c7d8e9",
    "status": "scheduled",
    "scheduledFor": "2026-11-09T16:00:00.000Z"
  }'

Follow-ups inside a task need no scheduling from your app. The assistant sets the task's alarm when it needs to check back, and alarm.headline is the line to show the user.

Workflows

Recurring and event-driven work is a workflow: a skill with kind: "workflow" and one or more triggers. Each firing creates a task.

Trigger onFires
cronOn a fixed schedule. schedule.frequency is minutely, hourly, daily, weekly or monthly.
webhookOn a calendar or email event, such as event.scheduled, event.cancelled or email.received, immediately or after delayOffset.
timestampRelative to a time on the matched event, such as 30 minutes before startTime.
conditionWhen a polled condition becomes true.
inactivityWhen an expected event did not happen within a window.
systemWhen another workflow's task completes or fails.
compoundWhen several sub-triggers combine with and or or.
manualWhen the user runs it.

Create a Monday-morning portfolio briefing for Jane:

curl https://api.agnt.ai/skills \
  -X POST \
  -H "Authorization: Bearer $AGNT_API_KEY" \
  -H "X-User-Email: [email protected]" \
  -H "Content-Type: application/json" \
  -d '{
    "kind": "workflow",
    "name": "weekly-portfolio-briefing",
    "title": "Weekly portfolio briefing",
    "description": "A Monday-morning summary of leases, maintenance and vendor contracts across the portfolio",
    "instructions": "Summarize leases expiring in the next 60 days, open maintenance tickets, and vendor contracts up for renewal.",
    "triggers": [{
      "on": "cron",
      "schedule": { "frequency": "weekly", "days": ["MO"], "hour": 8, "minute": 0 },
      "timezone": "America/Los_Angeles"
    }],
    "maxRuns": 52
  }'
NameTypeRequiredDescription
kindstringYesworkflow.
namestringYesUnique slug.
titlestringYesDisplay name.
descriptionstringYesWhat the workflow does.
instructionsstringNoWhat each run does.
triggersobject[]YesWhen the workflow fires.
scheduleTypestringNonow, recurring or trigger-based. Inferred from triggers when omitted.
maxRuns, recurrenceEndsAtinteger, stringNoStop after this many runs, or at this time.
maxConcurrent, cooldownMsintegerNoLimit overlapping runs and how often the workflow can fire.
overflowBehaviorstringNoqueue, drop or replace, when a firing arrives at the concurrency limit.

With X-User-Email, the workflow belongs to that user. With an account key and no X-User-Email, the workflow is available app-wide. Manage skills of every kind with the CLI.

Autonomy

Each user has a supervision matrix (supervisionMatrix): one cell per action type, each holding a mode.

ModeBehavior
autoExecutes immediately.
time-boxedWaits timeBoxedWindowMin minutes so the user can review, edit or cancel. When the window ends the cart executes, or is cancelled if timeBoxedExpiry is cancel. While it waits, the cart's status is time_boxed.
manualWaits until a person approves or cancels.

A cell can also set undoDelaySec: how many seconds an action that cannot be reversed (a sent message, a call) waits after it is released, before it goes out. Undo during that hold cancels it. Unset, the hold is 30 seconds. 0 sends at once.

Action typeCoversNew-user default
email_as_userEmail sent as the user, from their mailboxmanual
email_as_assistantEmail from the assistant's own addressauto
messagingSMS, iMessage, WhatsApp and chat messagesauto
voice_call_as_assistantCalls where the assistant speaks as itselfauto
voice_call_as_userCalls where the assistant speaks for the usermanual
calendarCreating, changing and cancelling eventsauto
driveCreating, writing and sharing files in a connected driveauto
filesFiles in the assistant's own storageauto
contactsChanges to the user's contactsauto
third_party_skillsActions through connected apps and MCP serversauto
websitePublishing a sitemanual

Reads are never gated. The defaults favor getting work done: only actions taken as the user, and publishing a site, wait for approval. For enterprise use, set email_as_assistant, messaging, voice_call_as_assistant, calendar, drive and third_party_skills to manual or time-boxed, and lock them at the organization so users cannot loosen them.

Read and change a user's settings

curl https://api.agnt.ai/users/6702b1e8f9a0b1c2d3e4f5a6/preferences/supervision/matrix \
  -H "Authorization: Bearer $AGNT_API_KEY"
{
  "ok": true,
  "supervisionMatrix": {
    "matrix": {
      "email_as_user": { "mode": "manual" },
      "email_as_assistant": { "mode": "auto" },
      "messaging": { "mode": "auto" }
    },
    "matrixUpdatedAt": "2026-11-02T16:10:03.000Z",
    "parentLockedCells": ["email_as_user"],
    "orgLockedCells": ["email_as_user"],
    "teamLockedCells": [],
    "lockedValues": { "email_as_user": { "mode": "manual" } }
  }
}

PATCH merges per cell:

curl https://api.agnt.ai/users/6702b1e8f9a0b1c2d3e4f5a6/preferences/supervision/matrix \
  -X PATCH \
  -H "Authorization: Bearer $AGNT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "matrix": {
        "email_as_assistant": { "mode": "manual" },
        "messaging": { "mode": "time-boxed", "timeBoxedWindowMin": 5 }
      } }'
NameTypeRequiredDescription
matrix.<actionType>.modestringNoauto, time-boxed, manual, or null to inherit.
matrix.<actionType>.timeBoxedWindowMinnumberNoWindow length in minutes, for time-boxed.
matrix.<actionType>.timeBoxedExpirystringNoexecute or cancel, when the window ends.
matrix.<actionType>.undoDelaySecnumberNoHold before an irreversible action goes out.

A PATCH that would loosen a cell locked by a team or the account returns 403. PUT /users/:userId/preferences/supervision/matrix/reset clears every one of the user's own cells and removes every recipient exception. Each action type then follows the team or organization value if there is one, else the platform default: manual for email_as_user, voice_call_as_user, third_party_skills and website, and auto for the rest.

Recipient exceptions

An exception changes the mode for specific people or apps. Require approval for anything Ava sends to Brightline Freight:

curl https://api.agnt.ai/users/6702b1e8f9a0b1c2d3e4f5a6/preferences/supervision/exceptions \
  -X POST \
  -H "Authorization: Bearer $AGNT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "label": "Brightline Freight",
    "match": { "kind": "domain", "value": "brightlinefreight.com" },
    "mode": "manual",
    "appliesTo": ["email_as_assistant", "email_as_user", "messaging"]
  }'
{
  "ok": true,
  "recipientException": {
    "id": "6702cc48f9a0b1c2d3e4f5a6",
    "label": "Brightline Freight",
    "match": { "kind": "domain", "value": "brightlinefreight.com" },
    "mode": "manual",
    "timeBoxedWindowMin": null,
    "timeBoxedExpiry": null,
    "undoDelaySec": null,
    "appliesTo": ["email_as_assistant", "email_as_user", "messaging"],
    "createdAt": "2026-11-02T16:12:40.000Z"
  }
}
NameTypeRequiredDescription
match.kindstringYesemail, domain, contactId, company, tag, priority ("1" to "3"), internal ("true" or "false") or connection (a connected app, by skill name).
match.valuestringYesThe value to match.
modestringYesauto, time-boxed, manual, or denied to block the action.
appliesTostring[]NoAction types it covers. Empty, or ["All"], covers every action type with a recipient.
labelstringNoUp to 60 characters.
timeBoxedWindowMinintegerNo1 to 60.
undoDelaySecintegerNo0 to 300.

A loosening exception applies only when every recipient of the action is covered by one. Each user can have up to 100 exceptions. Remove one with DELETE /users/:userId/preferences/supervision/exceptions/:exceptionId.

Per-task override

A person can set the mode for a single task, for every kind of action on it:

curl https://api.agnt.ai/tasks/6702c3a9b8c7d6e5f4a3b2c1 \
  -X PUT \
  -H "Authorization: Bearer $AGNT_API_KEY" \
  -H "X-User-Email: [email protected]" \
  -H "Content-Type: application/json" \
  -d '{ "approvalOverride": { "mode": "manual" } }'

Set approvalOverride to null to inherit again. The assistant can tighten a task's mode on its own, never loosen it. An admin lock outranks the override.

Organization and team policy

Admins set autonomy cells for an organization or team and can lock them. A locked cell is pinned to the admin's value: the user's own setting, exceptions and task overrides cannot change it. An unlocked admin value is only a default, which the user's own cell replaces.

curl https://api.agnt.ai/organizations/6702a9c3e1b4f5d6a7b8c901/settings/resource-permissions \
  -X PATCH \
  -H "Authorization: Bearer $AGNT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "matrix": {
        "email_as_user": { "mode": "manual" },
        "email_as_assistant": { "mode": "manual" },
        "locked": ["email_as_user", "email_as_assistant"]
      } }'

For a team, send { "approvalSettings": { "matrix": { } } } with the same cells to PATCH /teams/:teamId/settings/resource-permissions. Team admins can set and lock only cells the organization has not locked. Where several locks apply, the most conservative wins. Users, organizations and teams covers the rest of organization and team policy.

The mode for an action is decided in this order:

  1. A denied exception blocks the action.
  2. An admin lock decides.
  3. The task's approvalOverride.
  4. The most conservative matching exception.
  5. The user's own cell.
  6. The platform default.

The task reports the result in effectiveApprovalMode and any admin locks in approvalLocks.

Approvals

When an action needs review, the task stages it in a cart and waits. A cart's id is the id of the task that staged it. The approval endpoints live under /portal on api.agnt.ai and take the same API key and X-User-Email as every other call.

Cart statusDescription
openThe run is still staging actions. Nothing is submitted for review.
submittedStaging finished and the approval mode is being resolved. Moves on within moments.
pending_approvalWaiting for a person (manual).
time_boxedExecutes at timeBoxedExpiresAt unless edited or cancelled.
approvedA person approved it, or its window ended. Execution is about to start.
executingThe stored actions are being sent.
executedEvery action ran.
cancelledCancelled with POST /portal/carts/:cartId/cancel, or its window ended with timeBoxedExpiry: "cancel". Nothing was sent.
rejectedDeclined from an approval link, such as the Reject link in an approval email. Nothing was sent.
failedExecution failed. The task's activities show which actions, if any, went out.

Every approval has these guarantees:

  • Exactly what was shown. Every cart response carries a contentHash of its staged content. Approve must echo it. If the content changed since it was shown, approve returns 409 cart_content_changed and nothing is sent.
  • No model in between. Approval executes the stored actions. No model call runs between approval and execution, so nothing is rewritten after review.
  • A person approves. Approve, edit, cancel and undo accept a person's own session or an API key acting as that person. Certificate JWTs, the SDK's credential, get 403, so the SDK has no approval methods.
  • Edits ship verbatim. Editing a staged email's subject or body changes the content hash, and the edited text is what goes out.

Review and approve

List the carts waiting for the user, then read one for its staged actions and contentHash:

curl https://api.agnt.ai/portal/carts \
  -H "Authorization: Bearer $AGNT_API_KEY" \
  -H "X-User-Email: [email protected]"

curl https://api.agnt.ai/portal/carts/6702c3a9b8c7d6e5f4a3b2c1 \
  -H "Authorization: Bearer $AGNT_API_KEY" \
  -H "X-User-Email: [email protected]"
{
  "ok": true,
  "cart": {
    "id": "6702c3a9b8c7d6e5f4a3b2c1",
    "taskId": "6702c3a9b8c7d6e5f4a3b2c1",
    "taskTitle": "Renew the Brightline Freight service contract",
    "assistantName": "Ava",
    "status": "pending_approval",
    "resolvedApprovalMode": "manual",
    "timeBoxedExpiresAt": null,
    "timeBoxedExpiry": "execute",
    "dispatches": [
      {
        "index": 0,
        "type": "send_message_as_assistant",
        "platform": "email",
        "from": "[email protected]",
        "to": ["[email protected]"],
        "cc": ["[email protected]"],
        "bcc": [],
        "subject": "Harborview service agreement renewal, 2027 terms",
        "body": "Hi Dana,\n\nOur service agreement with Brightline Freight ends on January 1, 2027. Harborview would like to renew. Could you send your proposed 2027 terms and rates by November 20? The current agreement is attached for reference.\n\nBest,\nAva, on behalf of Jane Rivera",
        "description": "Email Brightline Freight legal asking for 2027 renewal terms",
        "payload": null,
        "files": [
          {
            "filename": "Brightline-MSA-2026.pdf",
            "mimeType": "application/pdf",
            "size": 482113,
            "fileId": "6702c804b5c6d7e8f9a0b1c2"
          }
        ],
        "editedByUser": false,
        "currentVersionId": null,
        "validUntil": null,
        "evergreen": false
      }
    ],
    "contentHash": "cv1:3b8f1c2d9e4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c",
    "createdAt": "2026-11-02T16:25:02.000Z",
    "updatedAt": "2026-11-02T16:25:04.000Z"
  }
}

Approve exactly that content:

curl https://api.agnt.ai/portal/carts/6702c3a9b8c7d6e5f4a3b2c1/approve \
  -X POST \
  -H "Authorization: Bearer $AGNT_API_KEY" \
  -H "X-User-Email: [email protected]" \
  -H "Content-Type: application/json" \
  -d '{ "contentHash": "cv1:3b8f1c2d9e4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c" }'
{ "ok": true, "cartId": "6702c3a9b8c7d6e5f4a3b2c1", "status": "approved" }
NameTypeRequiredDescription
contentHashstringYesThe contentHash from the read you showed the user.
reasonstringNoA note recorded with the approval.

Call approve only when the person has chosen to approve in your UI. Never approve from your backend on their behalf.

ErrorStatusMeaning
content_hash_required400contentHash is missing.
cart_already_resolved400The cart is no longer awaiting approval.
cart_task_closed400The task closed and its draft was withdrawn.
cart_content_changed409The content changed since it was read. Read it again and show the user.

Edit, remove or cancel

# Edit a staged message's subject or body. The contentHash changes.
curl https://api.agnt.ai/portal/carts/6702c3a9b8c7d6e5f4a3b2c1/dispatches/0/edit \
  -X PATCH \
  -H "Authorization: Bearer $AGNT_API_KEY" \
  -H "X-User-Email: [email protected]" \
  -H "Content-Type: application/json" \
  -d '{ "subject": "Harborview service agreement renewal, 2027 terms (reply by Nov 20)" }'

# Remove one action from the cart.
curl -X DELETE https://api.agnt.ai/portal/carts/6702c3a9b8c7d6e5f4a3b2c1/dispatches/0 \
  -H "Authorization: Bearer $AGNT_API_KEY" \
  -H "X-User-Email: [email protected]"

# Cancel the whole cart. The task is told and decides what to do next.
curl https://api.agnt.ai/portal/carts/6702c3a9b8c7d6e5f4a3b2c1/cancel \
  -X POST \
  -H "Authorization: Bearer $AGNT_API_KEY" \
  -H "X-User-Email: [email protected]" \
  -H "Content-Type: application/json" \
  -d '{ "reason": "Wait until the Q1 2027 board meeting prep is done" }'

The edit endpoint returns the updated cart with its new contentHash. It accepts subject, body, validUntil and evergreen. Recipients cannot be changed there: to, cc, bcc or payload return 400. Edits are accepted only while the cart is pending_approval or time_boxed, and editing a time_boxed cart extends its countdown.

Undo

# What can still be undone, and until when.
curl https://api.agnt.ai/portal/carts/6702c3a9b8c7d6e5f4a3b2c1/snapshots \
  -H "Authorization: Bearer $AGNT_API_KEY" \
  -H "X-User-Email: [email protected]"
{
  "cartId": "6702c3a9b8c7d6e5f4a3b2c1",
  "count": 1,
  "snapshots": [
    {
      "dispatchIndex": 0,
      "dispatchType": "send_message_as_assistant",
      "resourceType": "email",
      "reversible": false,
      "undoStatus": "available",
      "undoExpiresAt": "2026-11-02T16:31:30.000Z",
      "undoneAt": null,
      "undoAvailable": true
    }
  ]
}
# Undo one action.
curl -X POST https://api.agnt.ai/portal/carts/6702c3a9b8c7d6e5f4a3b2c1/dispatches/0/undo \
  -H "Authorization: Bearer $AGNT_API_KEY" \
  -H "X-User-Email: [email protected]"

# Undo every reversible action, in reverse order.
curl -X POST https://api.agnt.ai/portal/carts/6702c3a9b8c7d6e5f4a3b2c1/undo \
  -H "Authorization: Bearer $AGNT_API_KEY" \
  -H "X-User-Email: [email protected]"

A reversible action, such as a created calendar event, is reverted. An irreversible action, such as a sent email, can be cancelled only while it is inside its undoDelaySec hold. After undoExpiresAt, undo returns an error.

Tasks the assistant proposes

An assistant can propose a task instead of starting it. A proposed task has createdBy: "agent" and approvalGate: "pending_user_approval", and does not run until approved. List proposed tasks with GET /tasks?approvalGate=pending_user_approval. Approve one with POST /tasks/:taskId/approve, decline it with POST /tasks/:taskId/decline (optional { "reason" }), or approve up to 100 with POST /tasks/approve-batch and { "taskIds": [] }.

Kill switch

The account-wide kill switch freezes every outbound action for every user at once. While frozen, staged actions are refused, task creation and runs return 423 with error_code: "KILL_SWITCH_ENGAGED", and inbound messages are not processed.

A person signed in to your hosted app freezes and releases the account. The console, API keys, certificate JWTs and service tokens get 403 (KILL_SWITCH_RELEASE_FORBIDDEN), so a leaked credential cannot release a freeze. Your backend can read the state:

curl https://api.agnt.ai/portal/account/kill-switch \
  -H "Authorization: Bearer $AGNT_API_KEY"
{ "state": "active", "engagedAt": null, "engagedBy": null, "reason": null }

state is frozen while engaged and active otherwise. To stop a single task, use POST /tasks/:taskId/stop.

Example: renew the Brightline Freight contract

Harborview's service agreement with Brightline Freight ends on 2027-01-01. Jane asks Ava to get the 2027 terms. Harborview requires approval for every email Ava sends.

  1. Require approval for assistant email.

    curl https://api.agnt.ai/users/6702b1e8f9a0b1c2d3e4f5a6/preferences/supervision/matrix \
      -X PATCH \
      -H "Authorization: Bearer $AGNT_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{ "matrix": { "email_as_assistant": { "mode": "manual" } } }'
    
  2. Create and start the task. Create it as in Create and run a task, then start it with the MSA attached. The task id is 6702c3a9b8c7d6e5f4a3b2c1.

  3. Ava stages the email. Ava reads Brightline-MSA-2026.pdf, drafts an email to [email protected], and stages it. The task shows the cart:

    curl https://api.agnt.ai/tasks/6702c3a9b8c7d6e5f4a3b2c1 \
      -H "Authorization: Bearer $AGNT_API_KEY" \
      -H "X-User-Email: [email protected]"
    
    {
      "ok": true,
      "task": {
        "id": "6702c3a9b8c7d6e5f4a3b2c1",
        "title": "Renew the Brightline Freight service contract",
        "status": "executing",
        "effectiveApprovalMode": "manual",
        "pendingCart": {
          "status": "pending_approval",
          "label": "Email Brightline Freight legal for 2027 renewal terms",
          "timeBoxedExpiresAt": null,
          "timeBoxedExpiry": null,
          "dispatches": [
            {
              "type": "send_message_as_assistant",
              "platform": "email",
              "to": ["[email protected]"],
              "subject": "Harborview service agreement renewal, 2027 terms",
              "resolvedApprovalMode": "manual"
            }
          ]
        }
      }
    }
    
  4. Jane approves it in your app. Your app reads the cart, shows Jane the email and the attachment, and when she taps Approve, sends the contentHash it showed her (see Review and approve):

    curl https://api.agnt.ai/portal/carts/6702c3a9b8c7d6e5f4a3b2c1/approve \
      -X POST \
      -H "Authorization: Bearer $AGNT_API_KEY" \
      -H "X-User-Email: [email protected]" \
      -H "Content-Type: application/json" \
      -d '{ "contentHash": "cv1:3b8f1c2d9e4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c" }'
    
  5. The email goes out and the task waits. status becomes awaiting_non_user_response, waitingOnContacts lists Dana Okafor, and alarm.wakeAt is set so Ava follows up if Brightline does not reply.

  6. Dana replies with the 2027 terms. The reply is attached to the task and wakes it. Your app makes no call.

  7. The task resumes. Ava compares the proposed terms with the 2026 agreement and asks Jane to confirm a 3% rate increase. status becomes awaiting_user_input. Jane answers with POST /tasks/6702c3a9b8c7d6e5f4a3b2c1/process, and the task continues.

Follow every step with GET /tasks/6702c3a9b8c7d6e5f4a3b2c1/activities.

Endpoints

MethodPathDescription
POST/tasksCreate a task.
GET/tasksList tasks. Filter by status, type, assistant, approvalGate or q.
GET/tasks/:taskIdGet a task.
PUT/tasks/:taskIdUpdate a task, including approvalOverride.
DELETE/tasks/:taskIdDelete a task.
POST/tasks/:taskId/processStart a run, or send the task a message.
GET/tasks/:taskId/activitiesThe timeline, newest first.
POST/tasks/:taskId/stopStop the current run. Status becomes on_hold.
POST/tasks/:taskId/mark-doneMark done.
POST/tasks/:taskId/mark-not-doneReopen a done task.
POST/tasks/:taskId/feedbackLike, dislike or clear. The value is accepted but not yet stored.
POST/tasks/:taskId/approveApprove a proposed task.
POST/tasks/:taskId/declineDecline a proposed task.
POST/tasks/approve-batchApprove several proposed tasks.
POST/skillsCreate a workflow (kind: "workflow").
GET/users/:userId/preferences/supervision/matrixRead a user's autonomy settings and locks.
PATCH/users/:userId/preferences/supervision/matrixChange cells.
PUT/users/:userId/preferences/supervision/matrix/resetClear the user's cells and exceptions.
POST/users/:userId/preferences/supervision/exceptionsAdd a recipient exception.
DELETE/users/:userId/preferences/supervision/exceptions/:exceptionIdRemove a recipient exception.
PATCH/organizations/:orgId/settings/resource-permissionsOrganization cells and locks.
PATCH/teams/:teamId/settings/resource-permissionsTeam cells and locks.
GET/portal/cartsCarts awaiting review.
GET/portal/carts/:cartIdOne cart and its contentHash.
PATCH/portal/carts/:cartId/dispatches/:index/editEdit a staged action's text.
DELETE/portal/carts/:cartId/dispatches/:indexRemove a staged action.
POST/portal/carts/:cartId/approveApprove.
POST/portal/carts/:cartId/cancelCancel.
GET/portal/carts/:cartId/snapshotsWhat can be undone.
POST/portal/carts/:cartId/dispatches/:index/undoUndo one action.
POST/portal/carts/:cartId/undoUndo every reversible action.
GET/portal/account/kill-switchRead the kill switch state.

The SDK covers tasks.create, list, get, update, delete, process, stop, feedback and updateAssignees. Autonomy settings, carts and the kill switch are REST only.

Limits

  • GET /portal/carts returns at most 50 carts and is not paginated. Filter with status=pending_approval,time_boxed.
  • GET /tasks pages with page and perPage. An account key without X-User-Email lists every user's tasks and narrows them with ownerEmail.
  • modelTier can be changed only before a task's first run.
  • Exception timeBoxedWindowMin is 1 to 60 minutes, and undoDelaySec is 0 to 300 seconds.
  • Followers of a shared task can read its cart. Only the owner can approve, edit, cancel or undo it.

See also