Agent Runtime API

Start a run, follow it, steer it, stop it, and call a single tool directly over REST.

The Agent Runtime API is how your own code drives an agent: start a conversation and follow it, or skip the model and call one tool. Every route is authenticated with an agent API key, and the key decides which agent runs. Full request and response schemas are in the API reference; this page is the shape of the thing.

The examples on this page use the tables of a sample invoicing app (invoices, vendors, payments). Your app has only the tables you create, so put your own table and column names in their place. About the example app
export AUTHORIC_URL="https://api.authoric.ai"   # your API's address
export APP_UID="<your app uid>"
export AGENT_KEY="plak_..."

Send the key as a bearer token: Authorization: Bearer plak_…. The x-api-key header works too.

The endpoints

MethodPathPurpose
POST/{appUid}/agent/invokeStart a run
GET/{appUid}/agent/runsList runs
GET/{appUid}/agent/runs/{runUid}Get a run
POST/{appUid}/agent/runs/{runUid}/messagesSend a message to a live run
POST/{appUid}/agent/runs/{runUid}/abortStop a run
GET/{appUid}/agent/toolsList tools
GET/{appUid}/agent/tools/{name}Get a tool
POST/{appUid}/agent/tools/{name}Call a tool
POST/{appUid}/mcpMCP endpoint: the same tools over MCP

There is no route to approve or continue a run with an API key, by design. See Approvals & halts.

Conversations: give it a goal

curl -X POST "$AUTHORIC_URL/$APP_UID/agent/invoke" \
  -H "Authorization: Bearer $AGENT_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: inv-2291-late-refund" \
  -d '{ "message": "Find the order on invoice INV-2291 and refund it if it shipped late." }'

The answer is 202, with the run's handle, before any work starts:

{
  "ok": true,
  "status": "running",
  "runUid": "0199f1d2-4b6a-7c3e-8a1f-2d9e6b0c4a77",
  "message": "",
  "resumable": false,
  "pendingSteps": [],
  "steps": [],
  "actions": {
    "poll": { "method": "GET", "href": "/{appUid}/agent/runs/0199f1d2-4b6a-7c3e-8a1f-2d9e6b0c4a77" },
    "cancel": { "method": "POST", "href": "/{appUid}/agent/runs/0199f1d2-4b6a-7c3e-8a1f-2d9e6b0c4a77/abort" },
    "message": { "method": "POST", "href": "/{appUid}/agent/runs/0199f1d2-4b6a-7c3e-8a1f-2d9e6b0c4a77/messages", "body": { "message": "" } }
  }
}

Asynchronous by default, deliberately

The handle arrives before the work does. A run that outlived your client's HTTP timeout would otherwise be one you could never poll, approve or stop. A handle you hold from the first millisecond cannot be lost, and if you do lose it, GET /agent/runs finds it again.

The body takes:

Field
messageRequired. What you want done.
sessionUidOptional. Continue an earlier conversation; omit it to start a new one. If that conversation's run is still going, your message is delivered into it instead (steered: true).

There is no agent field: the key implies the agent, and an agent named in the body is ignored. An autoApprove field is ignored too. See Approvals & halts.

Waiting for short calls

?wait=true holds the connection until the run ends, up to a ceiling the server sets. Within it you get 200 with the agent's message and the conversation's sessionUid. Past it you get the ordinary 202 envelope and the run carries on, so waiting can turn into polling but never into a lost run.

Retrying safely

Send an Idempotency-Key header on invoke. A retry with the same key and the same request joins the run already started and reports its current state; it does not start a second one or replay an old response. The same key with a different request is 409. Keys are remembered for 24 hours.

Following it

curl "$AUTHORIC_URL/$APP_UID/agent/runs/$RUN_UID" \
  -H "Authorization: Bearer $AGENT_KEY"

The statuses, progress, activity and assets are explained on Runs.

Listing runs

GET /{appUid}/agent/runs answers "what is my agent doing?" without already holding a handle. It returns a summary per run, newest first, with each run's actions.

Query
statusactive (default: running, waiting, awaiting approval or paused) or all.
includeDelegated1 to include runs handed to sub-agents. By default only runs you started.
limit, offsetPage size (default 25, at most 100) and offset.

paging.count is the size of this page, not a total: keep asking until a short page comes back.

Steering and stopping

POST …/runs/{runUid}/messages with { "message": "…" } delivers a new instruction into a run that is still going, and POST …/runs/{runUid}/abort stops one. Both are your key's to use on its own runs; neither can approve anything. See Runs.

Direct: call one tool

When you already know what you want done, skip the model. List the key's tools, then call one by name:

# What can this key do?
curl "$AUTHORIC_URL/$APP_UID/agent/tools" \
  -H "Authorization: Bearer $AGENT_KEY"

# Do exactly this
curl -X POST "$AUTHORIC_URL/$APP_UID/agent/tools/invoices_create" \
  -H "Authorization: Bearer $AGENT_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "values": { "invoice_number": "INV-1042", "amount": 1200 } }'

The body is the tool's arguments, matching its inputSchema. It may also be wrapped as { "input": { … } } or { "arguments": { … } }. Tool names and schemas are explained on Tools.

No model, no planning, no tokens spent, and the same governance: a tool rated above low does not run here either. The HTTP status says what happened:

StatusstatusMeaning
200executedIt ran. output is the result.
202pending_approvalIt halted. Nothing ran; poll the returned runUid for the outcome once someone decides.
403deniedThe agent does not hold this tool, or policy refused the call. error says why.
400failedThe arguments did not fit the tool, or the call failed. error says why.
{
  "ok": true,
  "name": "invoices_delete",
  "status": "pending_approval",
  "runUid": "0199f1d4-0a2e-7d61-9b3c-6f8e1a2d5c90",
  "risk": "high",
  "output": null,
  "error": null
}

An Idempotency-Key header makes a retried call run at most once; a duplicate gets the stored response back. ?mode= chooses how tables are presented as tools (see MCP server).

Errors

CodeStatusWhen
API_KEY_INVALID401The key is missing, malformed, unknown, revoked or expired, or its agent is disabled. One answer for all of them.
AGENT_RUN_NOT_FOUND404No such run for this key. A run that does not exist and someone else's look the same.
AGENT_RUN_NOT_ACTIVE409A message to a run that has finished.
AGENT_SESSION_BUSY409The conversation already has a run going that this key did not start.
AGENT_RUN_CONCURRENCY_LIMIT429Too many runs already in flight. Honor Retry-After.
AGENT_NO_LLM_BINDING409The agent has no AI connection and no included AI credits are available.
MCP_TOOL_NOT_FOUND404GET /agent/tools/{name} for a tool this key does not hold.

Every key is also rate limited, separately from the run limit; over it you get 429. The full list of codes is in Error codes.

What's next

On this page