Skip to Content
APIAgent API

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/v1

Auth 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 as Authorization: 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 to done, 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 match runId
  • 409 CONFLICT — a result has already been received for this run (idempotency guard)
  • 404 NOT_FOUNDrunId does 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; }

© 2026 Leadmetrics — Internal use only