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.
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 appexport 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
| Method | Path | Purpose |
|---|---|---|
POST | /{appUid}/agent/invoke | Start a run |
GET | /{appUid}/agent/runs | List runs |
GET | /{appUid}/agent/runs/{runUid} | Get a run |
POST | /{appUid}/agent/runs/{runUid}/messages | Send a message to a live run |
POST | /{appUid}/agent/runs/{runUid}/abort | Stop a run |
GET | /{appUid}/agent/tools | List tools |
GET | /{appUid}/agent/tools/{name} | Get a tool |
POST | /{appUid}/agent/tools/{name} | Call a tool |
POST | /{appUid}/mcp | MCP 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 | |
|---|---|
message | Required. What you want done. |
sessionUid | Optional. 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 | |
|---|---|
status | active (default: running, waiting, awaiting approval or paused) or all. |
includeDelegated | 1 to include runs handed to sub-agents. By default only runs you started. |
limit, offset | Page 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:
| Status | status | Meaning |
|---|---|---|
200 | executed | It ran. output is the result. |
202 | pending_approval | It halted. Nothing ran; poll the returned runUid for the outcome once someone decides. |
403 | denied | The agent does not hold this tool, or policy refused the call. error says why. |
400 | failed | The 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
| Code | Status | When |
|---|---|---|
API_KEY_INVALID | 401 | The key is missing, malformed, unknown, revoked or expired, or its agent is disabled. One answer for all of them. |
AGENT_RUN_NOT_FOUND | 404 | No such run for this key. A run that does not exist and someone else's look the same. |
AGENT_RUN_NOT_ACTIVE | 409 | A message to a run that has finished. |
AGENT_SESSION_BUSY | 409 | The conversation already has a run going that this key did not start. |
AGENT_RUN_CONCURRENCY_LIMIT | 429 | Too many runs already in flight. Honor Retry-After. |
AGENT_NO_LLM_BINDING | 409 | The agent has no AI connection and no included AI credits are available. |
MCP_TOOL_NOT_FOUND | 404 | GET /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.