Skip to main content

Backend API Specification

Definitive API contract for River Agents -- all 61 HTTP endpoints served by Backend (:8005), exposed exclusively through TLO Gateway (:8001). Every request is JWT-validated and ACL-enforced at the gateway before reaching the backend. The river-agent microservice (:8007) never exposes endpoints directly.

Quick Navigation

API Conventions

Base URL

All endpoints are prefixed with /api/v1. TLO Gateway proxies requests from :8001/api/v1/* to Backend at :8005/api/v1/* after JWT validation and ACL enforcement.

Authentication

Every request requires Authorization: Bearer <access_token>. TLO Gateway middleware:

  1. Validates the JWT signature and expiry
  2. Extracts user context and injects headers: X-User-ID, X-Org-ID, X-Workspace-ID, X-Internal-Call: true
  3. Checks per-endpoint ACL permissions before forwarding

Backend resolves these headers via Depends(get_current_active_user) and enforces WHERE org_id = {X-Org-ID} on every query.

Response Envelope

Success:

{
"success": true,
"data": {},
"message": "Operation successful"
}

Error:

{
"success": false,
"error": {
"code": "AGENT_NOT_FOUND",
"message": "Agent with id a1b2c3d4 does not exist in this workspace."
}
}

Pagination Envelope

All list endpoints return:

{
"items": [],
"total": 142,
"page": 1,
"page_size": 20,
"total_pages": 8
}

Default page_size is 20. Maximum page_size is 100.

Common Error Codes

HTTP StatusError CodeMeaning
400VALIDATION_ERRORRequest body or query parameter failed validation
401UNAUTHORIZEDMissing or invalid JWT
403FORBIDDENValid JWT but insufficient permissions
404NOT_FOUNDResource does not exist or belongs to another org
409CONFLICTState transition conflict or duplicate resource
422UNPROCESSABLE_ENTITYSemantically invalid (e.g., agent config fails validation)
429RATE_LIMITEDToo many requests; Retry-After header included
500INTERNAL_ERRORUnexpected server error
502UPSTREAM_ERRORDownstream service (river-agent, Temporal) unavailable
504TIMEOUTUpstream service did not respond in time

Soft Delete

Agents use soft delete (deleted_at IS NOT NULL). All list endpoints exclude soft-deleted records unless include_deleted=true is explicitly passed.

ID and Timestamp Format

Top-level entity IDs (agents, templates, policies, executions, approvals) are UUID v4 strings. Child record IDs (triggers, versions, bindings) are integers. All timestamps are ISO 8601 with timezone: "2026-04-23T14:30:00Z".


Endpoint Group Summary

GroupCountPage(s) Served
Agent CRUD6Agent Library, Create Guided, Agent Detail
Agent Lifecycle5Agent Detail (hero actions)
Agent Versions4Agent Detail -- Versions tab
Agent Triggers4Agent Detail -- Triggers tab
Agent Data Sources3Agent Detail -- Data Sources tab
Agent Tools2Agent Detail -- Tools tab
Agent Policies4Agent Detail -- Governance tab
Agent Metrics and Executions3Agent Detail -- Metrics tab, Runs tab, Audit tab
AI-Powered Creation3AI Create page
Templates5Template Library, Template Detail
Executions and Runs7Runs List, Run Detail
Approvals5Runs page (approval modal)
Monitoring4System Monitoring page
Settings7Settings page (6 tabs)
Audit and Logs3Audit and Logs page
Total6512 pages

Agent CRUD

MethodPathPermissionDescription
GET/api/v1/agentsagent:readList agents with filtering, search, and pagination
GET/api/v1/agents/statsagent:readWorkspace-level KPI aggregates for the Agent Library dashboard
POST/api/v1/agentsagent:createCreate a new agent in draft status
GET/api/v1/agents/{id}agent:readGet full agent detail with computed fields
PUT/api/v1/agents/{id}agent:updateUpdate agent configuration; creates a new version if deployed
DELETE/api/v1/agents/{id}agent:deleteSoft-delete agent; preserves execution history and audit logs

GET /api/v1/agents

Query parameters:

ParameterTypeRequiredDefaultDescription
searchstringNo--Full-text search on name and description (max 255 chars)
statusstringNo--Comma-separated lifecycle statuses: draft, configured, validated, deployed, active, paused, archived
categorystringNo--Business function: customer_support, sales, finance, risk_compliance, data_analyst, operations, executive, custom
action_levelstringNo--read_respond, recommend, act_with_approval, fully_automated
owner_user_iduuidNo--Filter by agent owner
pageintegerNo1Page number
page_sizeintegerNo20Items per page (max 100)
sort_bystringNoupdated_atname, status, created_at, updated_at, health_status
sort_orderstringNodescasc or desc

Response includes per-agent trigger_summary and metrics_summary fields (7-day aggregates) computed on read. These are non-blocking reads from agent_metrics_hourly and do not add meaningful latency.

GET /api/v1/agents/stats

Returns workspace-level aggregate counts for the Agent Library KPI cards. No query parameters.

{
"total_agents": 28,
"active_agents": 15,
"running_agents": 3,
"pending_approvals": 7,
"runs_today": 142,
"success_rate_7d": 0.94,
"paused_agents": 4,
"draft_agents": 6,
"archived_agents": 3
}
FieldDescription
running_agentsAgents with at least one running execution at request time
pending_approvalsapproval_requests with status = pending across all workspace agents
runs_todayExecutions with started_at in the last 24 hours
success_rate_7dRatio of completed to completed + failed executions in last 7 days

POST /api/v1/agents

Request body:

FieldTypeRequiredConstraintsDescription
namestringYes1-255 charsAgent display name
descriptionstringNomax 2000 charsAgent purpose description
business_functionstringYesEnum (see query params above)Business category
domainstringNomax 100 charsBusiness domain tag (e.g., "Billing", "Logistics")
action_levelstringYesEnum: read_respond, recommend, act_with_approval, fully_automatedAutonomy level
governance_levelstringNoEnum: standard, strict, custom. Default: standardPolicy strictness
instruction_setstringYes1-10000 charsNatural language goal and behavioral instructions
template_iduuidNoValid template UUIDSource template
toolsarrayNo--Initial tool bindings
tools[].tool_namestringYes (if tools provided)max 100 charsTool identifier
tools[].tool_configobjectNo--Tool-specific configuration overrides
data_sourcesarrayNo--Initial data source bindings
data_sources[].data_source_iduuidYes (if data_sources provided)Valid UUID in workspaceData source to connect
data_sources[].access_levelstringNoread_only or read_write. Default: read_onlyAccess level
triggersarrayNo--Initial trigger configurations
triggers[].trigger_typestringYes (if triggers provided)manual, scheduled, event, api, threshold, workflowTrigger type
triggers[].trigger_configobjectYes (if triggers provided)Type-specific schemaTrigger configuration
triggers[].is_activebooleanNoDefault: trueWhether trigger starts enabled
approval_rulesobjectNo--Approval gate configuration (see data-model doc for JSONB schema)
notification_configobjectNo--Notification channel configuration

Returns 201 Created with the full agent object. status is always draft on creation.

Error codes:

HTTPCodeCondition
400VALIDATION_ERRORMissing required fields, invalid enum values, instruction_set too long
404NOT_FOUNDReferenced template_id or data_source_id does not exist
409CONFLICTAgent with same name already exists in workspace

GET /api/v1/agents/{id}

Returns the full agent record plus a computed field block:

Computed FieldTypeDescription
uptime_secondsintegerSeconds since agent was last deployed (null if never deployed)
uptime_humanstringHuman-readable uptime: "13d 0h"
deployed_atdatetimeTimestamp of last deployment (null if never deployed)
trigger_summaryobject{total, types[], next_scheduled}
recent_runs_countintegerExecution count in last 7 days
recent_success_ratefloatSuccess ratio in last 7 days (0.0-1.0)
recent_avg_duration_msintegerAverage execution duration in last 7 days

PUT /api/v1/agents/{id}

All fields are optional -- only provided fields are updated. If the agent is in deployed, active, or paused status, this automatically creates a new version snapshot. If in draft or configured status, the current version record is updated in place.

Returns 200 OK with the updated full agent object.

Error codes:

HTTPCodeCondition
409CONFLICTAgent is archived and cannot be updated

DELETE /api/v1/agents/{id}

Soft-delete: sets deleted_at to current timestamp. Active triggers are deactivated. Running executions are cancelled with reason: agent_deleted. Execution history, audit logs, and version history are preserved. Returns 204 No Content.


Agent Lifecycle

All lifecycle endpoints enforce the agent state machine. Invalid transitions return 409 CONFLICT.

MethodPathPermissionDescription
POST/api/v1/agents/{id}/deployagent:deployValidate config and transition to deployed; activates triggers
POST/api/v1/agents/{id}/pauseagent:updateSuspend all triggers; running executions complete normally
POST/api/v1/agents/{id}/resumeagent:updateReactivate triggers; transition paused -> active
POST/api/v1/agents/{id}/archiveagent:deleteDeactivate all triggers; cancel running executions; terminal state
POST/api/v1/agents/{id}/validateagent:readRun pre-deployment checks without changing status

POST /api/v1/agents/{id}/deploy

Performs: (1) pre-deployment validation, (2) immutable version snapshot creation, (3) status transition to deployed, (4) trigger registration with Temporal.

Response 200 OK:

{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "deployed",
"version_number": 3,
"deployed_at": "2026-04-23T14:30:00Z",
"validation_result": {
"passed": true,
"checks": [
{ "check": "data_source_connectivity", "status": "passed", "details": "All 2 data sources reachable" },
{ "check": "tool_availability", "status": "passed", "details": "All 4 tools available" },
{ "check": "policy_compliance", "status": "passed", "details": "No policy violations" },
{ "check": "trigger_validity", "status": "passed", "details": "All 2 triggers valid" }
]
},
"triggers_activated": 2
}

Error codes:

HTTPCodeCondition
409CONFLICTAgent is already deployed or active, or is archived
422VALIDATION_FAILEDPre-deployment check failed; response includes validation_result with status: failed entries

If trigger registration fails for any configured trigger after version creation, deployment is rolled back and the agent returns to validated status.

POST /api/v1/agents/{id}/validate

Runs checks without deploying. Returns identical validation_result shape as deploy. Check names: data_source_connectivity, tool_availability, policy_compliance, trigger_validity, instruction_set. Status values: passed, failed, warning.

Returns 200 OK with:

{
"passed": false,
"checks": [
{ "check": "data_source_connectivity", "status": "passed", "details": "All 2 data sources reachable" },
{ "check": "policy_compliance", "status": "failed", "details": "Tool 'issue_refund' requires governance_level 'strict' but agent is set to 'standard'" },
{ "check": "instruction_set", "status": "warning", "details": "Instruction set is under 50 characters -- consider adding more detail" }
]
}

POST /api/v1/agents/{id}/pause

Response:

{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "paused",
"paused_at": "2026-04-23T14:30:00Z",
"triggers_suspended": 2,
"running_executions": 1
}

running_executions is the count of in-flight executions that will complete normally before the agent fully pauses.

POST /api/v1/agents/{id}/resume

Response:

{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "active",
"resumed_at": "2026-04-23T14:30:00Z",
"triggers_reactivated": 2
}

POST /api/v1/agents/{id}/archive

Response:

{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "archived",
"archived_at": "2026-04-23T14:30:00Z",
"executions_cancelled": 0,
"triggers_removed": 2
}

archived is a terminal state. The agent cannot be re-deployed. Use soft-delete (DELETE) to remove the agent from all list views.


Agent Versions

MethodPathPermissionDescription
GET/api/v1/agents/{id}/versionsagent:readList version history ordered by version_number DESC
GET/api/v1/agents/{id}/versions/{version_id}agent:readGet a specific version record with full configuration snapshot
GET/api/v1/agents/{id}/versions/diffagent:readStructured diff between two version records
POST/api/v1/agents/{id}/versionsagent:updateManually create a checkpoint version snapshot
POST/api/v1/agents/{id}/versions/{version_id}/rollbackagent:deployRoll back to a prior version by creating a copy as the new latest

GET /api/v1/agents/{id}/versions

Per-version response fields:

FieldTypeDescription
idintegerVersion row ID (internal)
version_numberintegerSequential version number
deployment_statestringdraft, active, or archived
instruction_setstringAgent instructions at this version
toolsarrayTools bound at this version
data_sourcesarrayData sources bound at this version
approval_rulesobjectApproval rules at this version
trigger_configobjectTrigger config snapshot
created_byobject{id, name} of the user who created this version
created_atdatetimeVersion creation timestamp
change_summarystringUser-provided or auto-generated change description (null if not set)

GET /api/v1/agents/{id}/versions/diff

Query parameters: from (version number) and to (version number). Returns a structured diff of instruction_set, tools, data_sources, approval_rules, and trigger_config between the two versions.

POST /api/v1/agents/{id}/versions/{version_id}/rollback

Rollback does not restore the old record. It creates a new agent_versions record as an exact copy of the target version, increments version_number, and sets that as current_version_id. This preserves the linear version history. Audit records agent.version_rolled_back with both source and target version IDs.


Agent Triggers

MethodPathPermissionDescription
GET/api/v1/agents/{id}/triggersagent:readList all trigger configurations for the agent
POST/api/v1/agents/{id}/triggersagent:updateAdd a new trigger
PUT/api/v1/agents/{id}/triggers/{trigger_id}agent:updateUpdate an existing trigger
DELETE/api/v1/agents/{id}/triggers/{trigger_id}agent:updateRemove a trigger

GET /api/v1/agents/{id}/triggers

Per-trigger response fields:

FieldTypeDescription
idintegerTrigger ID
trigger_typestringmanual, scheduled, event, api, threshold, workflow
trigger_configobjectType-specific configuration (see data-model doc, section JSONB Schema Specifications)
is_activebooleanWhether the trigger is currently enabled
last_fired_atdatetimeTimestamp of the last execution started by this trigger (null if never fired)
next_fire_atdatetimeNext scheduled fire time (null for non-scheduled triggers)
created_atdatetimeCreation timestamp

POST /api/v1/agents/{id}/triggers

Request body:

FieldTypeRequiredDescription
trigger_typestringYesTrigger type enum
trigger_configobjectYesType-specific configuration
is_activebooleanNoDefault: true

PUT /api/v1/agents/{id}/triggers/{trigger_id}

All fields optional. Returns updated trigger object. For a deployed agent, trigger config changes take effect on the next trigger fire -- they do not require a re-deploy for is_active changes. Changes to trigger_config on an active agent do require re-deploy to take effect on the version snapshot.


Agent Data Sources

MethodPathPermissionDescription
GET/api/v1/agents/{id}/data-sourcesagent:readList bound data sources with connection status
POST/api/v1/agents/{id}/data-sourcesagent:updateBind a data source (connectivity tested before binding)
DELETE/api/v1/agents/{id}/data-sources/{binding_id}agent:updateUnbind a data source

GET /api/v1/agents/{id}/data-sources

Per-binding response fields:

FieldTypeDescription
binding_idstringBinding record ID
data_source_iduuidData source ID (references platform data_sources table)
namestringData source display name
typestringsaas_api, database, file, warehouse
connector_typestringzendesk, postgres, confluence, etc.
access_levelstringread_only or read_write
schema_filterobjectColumn/table restrictions (allowed_tables, excluded_columns) -- null if unrestricted
statusstringconnected, disconnected, error
last_tested_atdatetimeLast successful connectivity check (null if never tested)

POST /api/v1/agents/{id}/data-sources

Request body:

FieldTypeRequiredDescription
data_source_iduuidYesData source to bind (must exist in same workspace)
access_levelstringNoDefault: read_only
schema_filterobjectNo{allowed_tables: [], excluded_columns: []}

A connectivity test is performed before the binding record is created. Returns 409 CONFLICT if the data source is already bound.


Agent Tools

MethodPathPermissionDescription
GET/api/v1/agents/{id}/toolsagent:readList tools bound to the agent's active version
PUT/api/v1/agents/{id}/toolsagent:updateReplace all tool bindings (full replacement, not partial)

GET /api/v1/agents/{id}/tools

Per-tool response fields:

FieldTypeDescription
tool_namestringTool identifier
tool_configobjectConfiguration overrides (null if using defaults)
categorystringreasoning, execution, or interaction
descriptionstringHuman-readable tool description
requires_approvalbooleanWhether this tool is in the agent's approval_rules.require_approval_for list

PUT /api/v1/agents/{id}/tools

The provided tools array becomes the complete replacement set -- tools not included are unbound. Returns the updated tool list. Returns 404 NOT_FOUND if any tool_name does not exist in the tool registry.


Agent Policies

MethodPathPermissionDescription
GET/api/v1/agents/{id}/policiesagent:readList bound policies including inherited org-wide policies
POST/api/v1/agents/{id}/policiesagent:updateBind a governance policy to the agent
PUT/api/v1/agents/{id}/policies/{policy_id}agent:updateToggle binding active state
DELETE/api/v1/agents/{id}/policies/{policy_id}agent:updateUnbind a workspace-specific policy

Org-wide policies (those with workspace_id = NULL) are automatically evaluated for all agents and appear in the list response with scope: organization. They cannot be unbound per-agent via DELETE -- use PUT to toggle the binding off if the agent requires an exemption (subject to governance approval).

GET /api/v1/agents/{id}/policies

Per-binding response fields:

FieldTypeDescription
binding_idintegerPolicy binding ID
policy.iduuidPolicy identifier
policy.namestringPolicy name
policy.descriptionstringPolicy description
policy.scopestringorganization or workspace
policy.conditionsobjectPolicy condition expressions
policy.enforcementstringblock, gate, alert, log
policy.is_activebooleanWhether the policy is globally active
is_activebooleanWhether this binding is active for this specific agent
bound_atdatetimeWhen the policy was bound to this agent

POST /api/v1/agents/{id}/policies

Request body: { "policy_id": "pol-001" }. The policy must already exist at org or workspace level.


Agent Metrics and Executions

MethodPathPermissionDescription
GET/api/v1/agents/{id}/metricsagent:readDaily aggregate metrics over a configurable time range
GET/api/v1/agents/{id}/executionsagent:readPaginated execution list for a specific agent
GET/api/v1/agents/{id}/auditagent:readAudit log entries scoped to a single agent

GET /api/v1/agents/{id}/metrics

Query parameters: period (24h, 7d, 30d, 90d; default 7d), granularity (hour, day; default day).

Response:

{
"agent_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"period": "7d",
"summary": {
"total_executions": 42,
"successful": 40,
"failed": 2,
"success_rate": 0.952,
"avg_duration_ms": 12400,
"avg_turns": 4.2,
"total_tokens_input": 128000,
"total_tokens_output": 45000,
"total_approvals_requested": 15,
"total_approvals_approved": 14,
"total_approvals_rejected": 1
},
"daily": [
{
"date": "2026-04-23",
"executions": 8,
"successful": 7,
"failed": 1,
"avg_duration_ms": 11200,
"avg_turns": 3.8,
"tokens_input": 21000,
"tokens_output": 7200
}
]
}

GET /api/v1/agents/{id}/executions

Query parameters: status (comma-separated execution statuses), page, page_size. Returns paginated execution objects. See Executions and Runs for the full execution object shape.

GET /api/v1/agents/{id}/audit

Query parameters: page, page_size. Returns paginated audit log entries scoped to this agent. See Audit and Logs for the full audit entry shape.


AI-Powered Creation

MethodPathPermissionDescription
POST/api/v1/agents/ai/generateagent:createGenerate full agent config from natural language; returns SSE stream
POST/api/v1/agents/ai/suggest-goalagent:createGenerate a suggested instruction_set from name, description, and business function
POST/api/v1/agents/ai/refineagent:createRefine an AI-generated draft using a follow-up prompt

POST /api/v1/agents/ai/generate

Accepts a natural language description and orchestrates generation via the river-agent microservice. The agent is NOT created by this endpoint -- the frontend displays the generated config for user review, then calls POST /api/v1/agents to persist it.

Request body:

FieldTypeRequiredConstraintsDescription
promptstringYes10-5000 charsNatural language description of the desired agent
quick_starter_idstringNoValid quick starter IDPre-defined starter prompt (e.g., customer_support, data_pipeline)

Returns Server-Sent Events (SSE). The connection stays open for the duration of generation. Each event corresponds to one of four generation stages.

SSE event format:

event: stage_update
data: {"stage": 1, "label": "Understanding Requirements", "progress": 25}

event: stage_update
data: {"stage": 2, "label": "Selecting Tools and Data Sources", "progress": 50}

event: stage_update
data: {"stage": 3, "label": "Drafting Instruction Set", "progress": 75}

event: stage_update
data: {"stage": 4, "label": "Applying Governance", "progress": 100}

event: generation_complete
data: {"generation_id": "gen-abc-123", "configuration": { ... }}

The configuration object in generation_complete has the same shape as the POST /api/v1/agents request body. The caller passes this directly to create the agent.

Error codes:

HTTPCodeCondition
400VALIDATION_ERRORprompt too short or too long
502UPSTREAM_ERRORriver-agent microservice unavailable
504TIMEOUTGeneration did not complete within 60 seconds

POST /api/v1/agents/ai/suggest-goal

Generates a suggested instruction_set string from lightweight inputs. Used by the Guided Wizard "Generate with AI" button on the Instructions step.

Request body:

FieldTypeRequiredDescription
namestringYesAgent name
descriptionstringNoShort description of agent purpose
business_functionstringYesBusiness category enum

Returns 200 OK:

{
"suggestion": "You are a billing support specialist. Your goal is to ..."
}

POST /api/v1/agents/ai/refine

Accepts a generation_id from a prior generation and a follow-up prompt to refine the configuration. Returns a new SSE stream with the same format as /generate.

Request body:

FieldTypeRequiredDescription
generation_idstringYesID from a prior generation_complete event
promptstringYesFollow-up refinement instruction

Templates

MethodPathPermissionDescription
GET/api/v1/templatesagent:readList templates -- platform-provided and workspace-custom
GET/api/v1/templates/{id}agent:readGet full template including required tools and data source types
POST/api/v1/templatesagent:createPublish a custom template from an existing agent configuration
PATCH/api/v1/templates/{id}agent:updateUpdate a custom template (platform templates are read-only)
DELETE/api/v1/templates/{id}agent:deleteDelete a custom template (platform templates cannot be deleted)

GET /api/v1/templates

Query parameters:

ParameterTypeDescription
categorystringFilter by business_function
searchstringText search on name and description
typestringplatform (built-in only) or custom (workspace-created only)
pageintegerPage number
page_sizeintegerItems per page (max 100)

Per-template response fields:

FieldTypeDescription
iduuidTemplate ID
namestringTemplate name
descriptionstringTemplate description
categorystringBusiness function category
typestringplatform or custom
icon_namestringIcon identifier for UI rendering
icon_bgstringIcon background color (hex)
icon_colorstringIcon foreground color (hex)
governance_defaultstringDefault governance level when creating from this template
required_toolsarrayTools required for this template
required_data_source_typesarrayData source connector types the template expects
usage_countintegerNumber of agents created from this template
created_byobject{id, name} -- null for platform templates
created_atdatetimeCreation timestamp

POST /api/v1/templates

Request body:

FieldTypeRequiredDescription
source_agent_iduuidYesAgent whose current version configuration becomes the template base
namestringYesTemplate name
descriptionstringYesTemplate description
categorystringYesBusiness function category
template_variablesarrayNoParameterized fields that users fill in when creating from template

Returns 201 Created with the full template object.


Executions and Runs

MethodPathPermissionDescription
GET/api/v1/agents/runsagent:readList runs across all workspace agents
GET/api/v1/agents/{id}/runsagent:readList runs for a specific agent
GET/api/v1/agents/runs/{execution_id}agent:readGet a single execution record with full detail
GET/api/v1/agents/runs/{execution_id}/logsagent:readGet turn-by-turn log entries for an execution
POST/api/v1/agents/{id}/runsagent:executeManually trigger an agent execution
POST/api/v1/agents/runs/{execution_id}/stopagent:executeCancel a running execution
POST/api/v1/agents/runs/{execution_id}/retryagent:executeRe-trigger with the same context as the original run

GET /api/v1/agents/runs

Query parameters:

ParameterTypeDescription
agent_iduuidFilter to a specific agent
statusstringComma-separated: queued, running, paused, completed, failed, cancelled, approval_pending, approval_expired
trigger_typestringFilter by trigger type
fromISO 8601Start of started_at range
toISO 8601End of started_at range
pageintegerPage number
page_sizeintegerItems per page (max 100)

GET /api/v1/agents/runs/{execution_id}

Returns the full execution record:

{
"id": "exec-001-uuid",
"agent_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"agent_name": "Customer Support Agent",
"agent_version_id": 3,
"version_number": 3,
"status": "completed",
"trigger_type": "event",
"trigger_payload": {
"ticket_id": "TKT-9912",
"priority": "high"
},
"started_at": "2026-04-23T14:30:00Z",
"completed_at": "2026-04-23T14:30:45Z",
"duration_ms": 45200,
"turn_count": 4,
"tokens_input": 3200,
"tokens_output": 1100,
"approval_count": 1,
"output_summary": "Drafted response to TKT-9912. Refund of $75 approved and issued.",
"error_message": null
}

GET /api/v1/agents/runs/{execution_id}/logs

Returns the turn-by-turn log:

{
"items": [
{
"id": 1,
"execution_id": "exec-001-uuid",
"turn_number": 1,
"log_type": "reasoning",
"content": {
"thought": "I need to look up the ticket details and check the customer's history.",
"next_action": "get_ticket_history"
},
"model_used": "balanced",
"tokens_input": 800,
"tokens_output": 220,
"latency_ms": 1240,
"created_at": "2026-04-23T14:30:02Z"
},
{
"id": 2,
"execution_id": "exec-001-uuid",
"turn_number": 2,
"log_type": "tool_call",
"content": {
"tool_name": "get_ticket_history",
"arguments": { "ticket_id": "TKT-9912" },
"result": { "history": [...] },
"governance_decision": "executed"
},
"model_used": null,
"tokens_input": null,
"tokens_output": null,
"latency_ms": 340,
"created_at": "2026-04-23T14:30:04Z"
}
],
"total": 8,
"page": 1,
"page_size": 20,
"total_pages": 1
}

log_type values: reasoning, tool_call, tool_result, approval_requested, approval_resolved, error, observation.

POST /api/v1/agents/{id}/runs

Request body:

FieldTypeRequiredDescription
trigger_payloadobjectNoOptional context payload passed to the agent as the trigger input
input_overridesobjectNoOverride specific agent_version fields for this run only (test mode)

Returns 202 Accepted:

{
"execution_id": "exec-001-uuid",
"status": "queued"
}

The Temporal workflow is started immediately. Poll GET /api/v1/agents/runs/{execution_id} or connect to /ws/agent-runs/{execution_id} for live status.

POST /api/v1/agents/runs/{execution_id}/stop

Sends a cancellation signal to the Temporal workflow. The current tool call is aborted. Execution transitions to cancelled with reason: user_requested. Returns 200 OK with the updated execution object.

POST /api/v1/agents/runs/{execution_id}/retry

Creates a new execution using the same agent_version_id and trigger_payload as the original run. Returns 202 Accepted with a new execution_id.

Error codes:

HTTPCodeCondition
400AGENT_NOT_ACTIVEAgent is not in active status; manual runs require active status
404EXECUTION_NOT_FOUND{execution_id} does not exist
429RATE_LIMITEDWorkspace concurrent run limit exceeded

Approvals

MethodPathPermissionDescription
GET/api/v1/agents/approvalsagent:approveList approval requests; defaults to status=pending
GET/api/v1/agents/approvals/{id}agent:approveGet a single approval request with full context
GET/api/v1/agents/{id}/approvalsagent:readList all approval requests for a specific agent
PATCH/api/v1/agents/approvals/{id}agent:approveResolve an approval (approve, reject, or edit-and-approve)
POST/api/v1/agents/approvals/{id}/expireagent:deployForce-expire a pending approval (emergency use; Workspace Admin only)

GET /api/v1/agents/approvals

Query parameters:

ParameterTypeDescription
statusstringDefault: pending. Also: approved, rejected, expired, auto_approved
agent_iduuidFilter to a specific agent
fromISO 8601Start of created_at range
toISO 8601End of created_at range
pageintegerPage number
page_sizeintegerItems per page (max 100)

GET /api/v1/agents/approvals/{id}

Returns the full approval request with all context for the review screen:

{
"id": "apr-001-uuid",
"execution_id": "exec-001-uuid",
"agent_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"agent_name": "Customer Support Agent",
"status": "pending",
"tool_name": "issue_refund",
"tool_arguments": {
"amount": 150.00,
"charge_id": "ch_abc123",
"reason": "Product defect -- customer reported within 30 days"
},
"reasoning_summary": "The customer reported a product defect within the 30-day window. The refund amount of $150 exceeds the $100 auto-approve threshold, requiring manual approval per policy.",
"risk_context": {
"policy_checks": [
{ "policy": "Refund Amount Limit", "result": "triggered", "detail": "Amount $150 exceeds $100 threshold" }
],
"data_classification": "internal"
},
"historical_precedent": {
"similar_approvals_30d": 12,
"approval_rate": 0.917,
"last_approved_at": "2026-04-21T10:30:00Z"
},
"assigned_approver_id": "user-001",
"expires_at": "2026-04-24T14:30:00Z",
"created_at": "2026-04-23T14:30:00Z",
"resolved_at": null,
"resolved_by": null,
"resolution_note": null,
"modified_args": null
}

PATCH /api/v1/agents/approvals/{id}

Three resolution paths:

Approve:

{
"status": "APPROVED",
"note": "Verified against policy; customer is within 30-day window."
}

Reject:

{
"status": "REJECTED",
"reason": "Customer is outside the 30-day refund window per updated policy."
}

Edit and Approve:

{
"status": "APPROVED",
"modified_args": { "amount": 75.00, "charge_id": "ch_abc123" },
"note": "Approved for partial refund only -- full amount not warranted."
}

After resolution, TLO Gateway sends the approval_resolved signal to the Temporal workflow. Execution resumes on the next Temporal heartbeat. modified_args replaces the original tool arguments in the dispatch if provided.

Error codes:

HTTPCodeCondition
404NOT_FOUNDApproval request does not exist
409CONFLICTRequest is already resolved (not in pending status)
410GONERequest has passed expires_at

Monitoring

MethodPathPermissionDescription
GET/api/v1/agents/monitoring/summaryagent:monitorWorkspace aggregate: active count, 24h runs, avg latency, failure rate
GET/api/v1/agents/monitoring/throughputagent:monitorHourly run counts for the last 24 hours, broken down by status
GET/api/v1/agents/monitoring/clusteragent:monitorInfrastructure health: per-instance CPU, memory, active runs
GET/api/v1/agents/monitoring/alertsagent:monitorActive anomaly alerts and auto-pause events

GET /api/v1/agents/monitoring/summary

{
"active_agents": 15,
"running_executions": 3,
"pending_approvals": 7,
"runs_24h": 142,
"success_rate_24h": 0.944,
"avg_latency_ms_24h": 11800,
"failure_rate_24h": 0.056,
"token_cost_24h_usd": 12.40
}

GET /api/v1/agents/monitoring/throughput

Returns an array of hourly buckets for the last 24 hours:

{
"series": [
{
"hour": "2026-04-23T13:00:00Z",
"completed": 8,
"failed": 1,
"running": 2,
"approval_pending": 0
}
]
}

GET /api/v1/agents/monitoring/cluster

Returns per-instance infrastructure health. Used by the cluster health panel on the Monitoring page.

{
"instances": [
{
"instance_id": "worker-01",
"cpu_percent": 42,
"memory_percent": 61,
"active_runs": 2,
"uptime_seconds": 864000,
"status": "healthy"
}
]
}

GET /api/v1/agents/monitoring/alerts

Returns active anomaly alerts and auto-pause events:

{
"items": [
{
"id": "alert-001",
"type": "auto_pause",
"agent_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"agent_name": "Finance Reconciliation Agent",
"reason": "3 consecutive failures detected",
"severity": "warning",
"created_at": "2026-04-23T12:00:00Z",
"resolved_at": null
}
],
"total": 1
}

Settings

MethodPathPermissionDescription
GET/api/v1/workspace/settingsagent:readGet all workspace-level River Agents settings
PATCH/api/v1/workspace/settingsagent:updateUpdate general workspace settings
GET/api/v1/workspace/settings/api-keysagent:readList workspace API keys
POST/api/v1/workspace/settings/api-keysagent:updateCreate a new workspace API key
DELETE/api/v1/workspace/settings/api-keys/{key_id}agent:updateRevoke an API key
POST/api/v1/workspace/settings/webhooksagent:updateRegister a new outbound webhook
DELETE/api/v1/workspace/settings/webhooks/{webhook_id}agent:updateRemove a webhook registration

GET /api/v1/workspace/settings

Returns all settings across all tabs:

FieldTypeDefaultDescription
default_action_levelstringrecommendDefault action level for new agents created in this workspace
max_concurrent_runsinteger10Maximum simultaneous executions across all workspace agents
default_max_turnsinteger15Default max_turns applied to new agent versions
default_tool_timeout_secondsinteger30Default per-tool call timeout
approval_timeout_hoursinteger24Default expiry for pending approval requests
approval_escalation_hoursinteger8Hours before escalation notification fires
max_agentsinteger50Maximum agents in the workspace (quota)
max_runs_per_dayinteger1000Maximum daily executions across all workspace agents
default_model_tierstringbalancedDefault LLM tier: fast, balanced, reasoning, coding
governance_levelstringstandardWorkspace-wide governance level applied unless overridden per agent
notification_channelsobject{}Configured notification channels (Slack, email, PagerDuty)
webhooksarray[]Registered outbound webhooks
api_keysarray[]Workspace API keys (masked -- only last 4 chars visible after creation)

POST /api/v1/workspace/settings/api-keys

Request body:

FieldTypeRequiredDescription
namestringYesHuman-readable key name
scopesarrayYesPermissions granted to this key (subset of agent:* permissions)
expires_atdatetimeNoKey expiration (null for non-expiring)

Returns 201 Created with the full key value. The raw key is only returned once. Subsequent reads return a masked version.

POST /api/v1/workspace/settings/webhooks

Request body:

FieldTypeRequiredDescription
urlstringYesHTTPS endpoint URL
eventsarrayYesEvent types to deliver (e.g., execution.completed, tool.approval_requested)
secretstringNoHMAC signing secret for payload verification

Returns 201 Created. A test ping is sent to the URL before the webhook is activated.


Audit and Logs

MethodPathPermissionDescription
GET/api/v1/auditagent:auditQuery the immutable audit log with filtering
GET/api/v1/audit/{entry_id}agent:auditGet a single audit log entry with full payload
POST/api/v1/audit/exportagent:auditQueue or stream an export of filtered audit records

GET /api/v1/audit

Query parameters:

ParameterTypeDescription
agent_iduuidScope to a specific agent
event_typestringFilter by event type or prefix (e.g., tool. matches all tool events)
actor_typestringhuman, agent, or system
outcomestringsuccess, failure, or blocked
fromISO 8601Start of created_at range
toISO 8601End of created_at range
pageintegerPage number (default: 1)
page_sizeintegerItems per page (default: 50, max: 200)

Per-entry response fields:

FieldTypeDescription
iduuidAudit log entry ID
event_typestringEvent type (see governance-safety doc for full taxonomy)
actor_typestringhuman, agent, or system
actor_user_iduuidUser ID (null for system events; may be nulled for GDPR erasure)
agent_iduuidAgent ID (null for workspace-level events)
execution_iduuidExecution ID (null for non-execution events)
event_payloadobjectEvent-specific payload fields
ip_addressstringSource IP (for human actor events)
user_agentstringBrowser or client identifier (for human actor events)
created_atdatetimeTimestamp of the event (write time)

The audit log is write-once. POST, PATCH, and DELETE requests to /api/v1/audit return 405 Method Not Allowed. There is no endpoint to delete or modify audit entries.

POST /api/v1/audit/export

Request body:

FieldTypeRequiredDescription
filtersobjectYesSame filter fields as GET /api/v1/audit
formatstringYescsv or json
deliverystringYesstream (chunked response) or email (queued delivery)

delivery: stream returns a chunked response for immediate download. delivery: email queues the export and delivers to the requesting user's email -- use for exports exceeding 10,000 rows. Returns 202 Accepted with { "export_id": "exp-001", "estimated_rows": 4200 }.