Agent API
Endpoints used by LLM runtimes and agent adapters to interact with the Leadmetrics control plane. These are not called by human client apps.
Related: API Overview | Auth | Agent Execution Engine | Task Queue
Base Prefix
/agent/v1Auth model: Two mechanisms, depending on endpoint:
- Task token — short-lived JWT issued by the control plane at dispatch time, scoped to a single
runId. Passed asAuthorization: Bearer <taskToken>. Used for callback and streaming endpoints. - Agent API key — long-lived API key stored in
agent_configs.apiKey, used for health-check and adapter test endpoints where no specific run is in progress.
Run Lifecycle
POST /runs/:runId/result
Deliver the final result of a completed or failed run. This is the primary phone-home endpoint for external agents using the WebhookAdapter.
Auth: Bearer taskToken (scoped to runId)
Request:
{
status: 'success' | 'error';
text?: string; // output text (required when status is 'success')
error?: string; // error message (required when status is 'error')
usage?: {
inputTokens: number;
outputTokens: number;
};
durationMs?: number;
metadata?: Record<string, unknown>; // adapter-specific extra data
}Response 200:
{ received: true; runId: string; }Side effects:
- On
success: activity status set todone, output stored in MongoDB, SSE event fired - On
error: activity run marked failed; BullMQ retry policy determines if a new run is created
Errors:
401 UNAUTHORIZED— token invalid, expired, or does not matchrunId409 CONFLICT— a result has already been received for this run (idempotency guard)404 NOT_FOUND—runIddoes not exist
POST /runs/:runId/stream
Send an output text delta in real time. Called repeatedly as the agent produces tokens, before the final POST /runs/:runId/result. The control plane fans these out via SSE to connected dashboard clients.
Auth: Bearer taskToken
Request:
{
delta: string; // partial text output
sequenceNum: number; // monotonically increasing per run; used to reorder out-of-order deltas
}Response 200:
{ received: true; }POST /runs/:runId/tool-call
Report a tool call made by the agent during execution. Stored in tool_calls for audit and billing.
Auth: Bearer taskToken
Request:
{
toolName: string; // e.g. 'google_search_console', 'semrush_keyword_research'
method: string; // e.g. 'getSearchAnalytics', 'getKeywordData'
input: unknown; // sanitised request payload (no credentials)
output?: unknown; // sanitised response payload
status: 'success' | 'error';
error?: string;
durationMs: number;
costUsd?: number; // if the tool itself has per-call cost (e.g. DataForSEO)
}Response 201:
{ toolCallId: string; }GET /runs/:runId/context
Fetch the full context for a run — the task prompt, skills content, wake reason, and any prior output. Called by external agents (WebhookAdapter) at run start to get everything they need.
Auth: Bearer taskToken
Response 200:
{
runId: string;
activityId: string;
tenantId: string;
agentRole: string;
wakeReason: string;
prompt: string;
systemPrompt?: string;
skills: Array<{
name: string;
content: string;
}>;
priorOutput?: string; // output from a previous run on the same activity (for retries)
rejectionNote?: string; // present when wakeReason is 'rejection' or 'review_feedback'
reviewerFeedback?: string;
subtaskOutput?: string; // present when wakeReason is 'subtask_completed'
model: string;
maxTurns?: number;
timeoutMs: number;
}GET /runs/:runId/status
Check the current status of a run. Useful for external agents that want to verify their token is still valid before beginning a long task.
Auth: Bearer taskToken
Response 200:
{
runId: string;
status: 'pending' | 'running' | 'completed' | 'failed' | 'timeout';
startedAt?: string;
expiresAt: string; // when the task token expires
}Control Plane Callbacks (Agent Tools)
Agents use these endpoints to exercise control plane tools during execution (create subtasks, request approvals, etc.). These mirror the tool schemas defined in Tool Integration Layer.
Auth: Bearer taskToken for all endpoints in this section.
POST /runs/:runId/actions/report-blocker
Signal that the activity is blocked and cannot proceed.
Request:
{
blockerType: 'channel_auth_expired' | 'missing_integration' | 'insufficient_data'
| 'api_unavailable' | 'needs_human_input';
description: string;
channelId?: string; // required when blockerType is 'channel_auth_expired'
resolution?: string; // suggested resolution steps for the human reviewer
}Response 200:
{
activityId: string;
status: 'blocked';
humanTaskCreated: boolean;
}POST /runs/:runId/actions/create-subtask
Delegate work to another agent role. The current activity is suspended until the subtask completes (unless blocking: false).
Request:
{
title: string;
agentRole: string; // target agent role, e.g. 'content_researcher'
prompt: string;
blocking?: boolean; // default true — current activity waits for subtask
priority?: 'normal' | 'high';
}Response 201:
{
subtaskActivityId: string;
blocking: boolean;
parentActivityId: string;
}Errors:
422 UNPROCESSABLE— subtask depth limit exceeded (max depth: 1)422 UNPROCESSABLE— target agent role is not enabled for this tenant
POST /runs/:runId/actions/request-review
Request ad-hoc human review of the current work-in-progress. The activity is paused until the reviewer approves or provides feedback.
Request:
{
title: string;
description: string;
contentRef?: string; // MongoDB refId for content to review (if already written)
}Response 201:
{
approvalId: string;
activityId: string;
status: 'awaiting_review';
}POST /runs/:runId/actions/create-approval
Create a formal approval gate (used for write-impacting actions like publishing or budget spend).
Request:
{
title: string;
type: 'content_review' | 'content_direction' | 'brand_direction'
| 'strategy_change' | 'budget_authorization' | 'channel_action';
description?: string;
options?: string[]; // named approval options
linkedActivityIds?: string[]; // other activities to block on this approval
blockCurrentActivity?: boolean; // default true
}Response 201:
{
approvalId: string;
type: string;
riskLevel: string;
expiresAt: string;
}POST /runs/:runId/actions/reassign
Reassign the current activity to a different agent or human. The current activity is marked reassigned and a new one is created.
Request:
{
toRole?: string; // agent role (mutually exclusive with toUserId)
toUserId?: string; // human user ref_id
reason: string;
}Response 201:
{
originalActivityId: string;
newActivityId: string;
}POST /runs/:runId/actions/add-comment
Add a comment to the activity’s thread. Non-blocking — does not affect activity status.
Request:
{
text: string; // supports @agent:role, @human:userId mention syntax
type?: 'comment' | 'intervention_note';
}Response 201:
{ commentId: string; }Adapter Health Checks
GET /health/:agentRole
Run the adapter health check for a specific agent role. Returns diagnostic results for the adapter configured for this role on the calling tenant.
Auth: Agent API key (Authorization: ApiKey <key>)
Path params: agentRole — e.g. copywriter, seo_specialist
Response 200:
{
agentRole: string;
adapterType: string;
ok: boolean;
message: string;
checks: Array<{
name: string;
ok: boolean;
detail?: string;
}>;
checkedAt: string;
}POST /health/:agentRole/test
Dispatch a minimal probe task to verify end-to-end connectivity: control plane → adapter → LLM → callback. Returns the probe output.
Auth: Agent API key
Response 200:
{
ok: boolean;
probeOutput?: string; // short LLM response from the probe prompt
durationMs: number;
error?: string;
}Skills
GET /skills/:agentRole
Fetch the skill manifest for an agent role — the list of available skill names and descriptions without loading full content. Used by the agent at run start to decide which skills to load.
Auth: Bearer taskToken
Response 200:
{
manifest: Array<{
name: string;
description: string; // "Use when / Don't use when" routing guidance
}>;
}GET /skills/:agentRole/:skillName
Fetch the full content of a specific skill by name. Called by the agent after it decides a skill is relevant.
Auth: Bearer taskToken
Response 200:
{
name: string;
content: string; // full Markdown content
references?: Array<{
name: string;
content: string;
}>;
}Errors:
404 NOT_FOUND— skill not found or not assigned to this agent role
Sessions
PUT /sessions/:agentRole
Upsert a session record for a Claude Code CLI session. Called by the ClaudeAdapter after capturing the session_id from the NDJSON stream.
Auth: Agent API key
Request:
{
sessionId: string; // Claude session ID from system/init event
activityRunId: string;
inputTokensSoFar: number;
outputTokensSoFar: number;
}Response 200:
{ sessionId: string; upserted: true; }GET /sessions/:agentRole/latest
Fetch the most recent session ID for an agent role (for session resumption on the next run).
Auth: Agent API key
Response 200:
{
sessionId?: string; // null if no prior session
inputTokens: number;
outputTokens: number;
createdAt: string;
}