Skip to content

AI Run API Reference

POST /v1/ai/run is the unified execution endpoint. It supports two distinct modes:

  • Mode A: keyed background run with lease semantics
  • Mode B: synchronous governed tool execution

Because the two modes behave differently, this flow is documented separately from the low-level lease endpoints.


Endpoint: POST /v1/ai/run

  • Send key to use the keyed background-run flow
  • Send agent_id + tool to use governed tool execution

The request must use one mode or the other.


This mode starts or attaches to long-running work keyed by an idempotent run key.

The current backend:

  1. Calls the same lease logic used by /v1/ai/lease
  2. Returns the same response shape as /v1/ai/lease
  3. If status is acquired, enqueues background work
  4. Stores final state in /v1/ai/status and /v1/ai/result
  5. Writes run timeline events using run_id
Terminal window
curl -X POST https://api.onceonly.tech/v1/ai/run \
-H "Authorization: Bearer once_live_xxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"key": "support_chat_001",
"ttl": 1800,
"metadata": {
"run_id": "run_support_001",
"agent_id": "support_bot",
"actions": [
{
"tool": "send_email",
"args": {
"to": "user@example.com",
"subject": "Issue resolved"
},
"spend_usd": 0.001
}
]
}
}'

These fields are meaningful in the current backend worker flow:

  • run_id - Optional explicit run id. If omitted, the backend uses key.
  • agent_id - Optional agent id used while executing metadata.actions.
  • actions - List of planned tool calls. Each action can include tool, args, and optional spend_usd.
  • dry_run - Optional boolean-like flag for dry-run tool execution.

The current worker executes up to the first 50 actions from metadata.actions.

{
"ok": true,
"status": "acquired",
"key": "support_chat_001",
"ttl": 1800,
"ttl_left": null,
"lease_id": "lease_abc123xyz",
"version": 1,
"first_seen_at": "2026-03-31T10:30:00Z",
"done_at": null,
"result_hash": null,
"error_code": null,
"retry_after_sec": null,
"usage": 128,
"limit": 100000,
"charged": 1
}

Mode A can also return:

  • polling - Another worker already owns the keyed run
  • completed - The same key already finished successfully
  • failed - The same key already finished with failure
  • Poll GET /v1/ai/status?key=...
  • Read final payload from GET /v1/ai/result?key=...
  • Inspect timeline with GET /v1/runs/{run_id}

This mode executes one governed tool call synchronously through the policy engine.

Terminal window
curl -X POST https://api.onceonly.tech/v1/ai/run \
-H "Authorization: Bearer once_live_xxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "support_bot",
"tool": "send_email",
"args": {
"to": "user@example.com",
"subject": "Hello",
"run_id": "run_support_001"
},
"spend_usd": 0.001
}'
{
"ok": true,
"allowed": true,
"decision": "executed",
"policy_reason": "ok",
"risk_level": "low",
"result": {
"status": "sent"
}
}
{
"ok": true,
"allowed": false,
"decision": "blocked",
"policy_reason": "tool_not_in_allowed_list",
"risk_level": "medium"
}
{
"ok": true,
"allowed": true,
"decision": "dedup",
"policy_reason": "tool_idempotency",
"risk_level": "low",
"result": null
}
  • If you want run timeline events in Mode B, pass run_id inside args.
  • decision can be executed, blocked, or dedup.
  • If spend_usd is omitted, the backend can still derive cost from pricing_rules.
  • Policy blocks and disabled agents are returned as normal 200 blocked responses, not as HTTP 403 errors.

When run_id is present, the backend emits events such as:

  • run_started
  • agent_step
  • tool_call
  • tool_result
  • run_finished

{
"detail": "Missing Authorization Bearer token"
}
{
"detail": "Invalid API key"
}
{
"detail": {
"error": "tool_not_found",
"tool": "send_email",
"scopes_tried": [
"agent:support_bot",
"global"
]
}
}

See also: AI Leases API | Runs & Events API | Policies API