Skip to content

REST API ​

The Agentfleet API is served at https://api.agentfleet.co.za, the same host as the console. All endpoints live under /api and need an Authlink access token for the Agentfleet API, sent as Authorization: Bearer …. The console itself signs in through a backend-for-frontend and sends an HttpOnly session cookie instead. Integrations always send the bearer header.

This page is a working overview of the main endpoints in each feature area, not an exhaustive contract. In Development the API also serves its OpenAPI document (/openapi).

Authorization ​

Every operation is decided by the Authlink policy decision point (PDP), one permission at a time. The API does not check roles itself.

  • [PolicyAuthorize(permission)] endpoints ask the PDP whether the caller holds one permission key, such as agentfleet:create-workflow or agentfleet:run-workflow-instance.
  • [ResourcePolicyAuthorize(permission, …)] endpoints are bound to the record they touch. The record's id is taken from the route, the JSON body or the query, and its tenant, status and creator go to the PDP with the request. This is how tenant isolation is enforced on detail reads and mutations (see resource-scoped policies).
  • List and paged endpoints ask the PDP for the list permission (for example agentfleet:view-agents) and apply the tenant filter the decision returns, so you only see your own tenant's rows.
  • Fail-closed. A denied permission answers 403 with the missing permission key in the body. A list endpoint that cannot reach the PDP answers 502. It never returns unfiltered data.

Permission keys follow agentfleet:<verb>-<entity>. The full catalogue, and the roles that bundle the keys, are provisioned into Authlink from AccessControlVocabularyBuilder. Roles such as agentfleet:workflow-author, agentfleet:operator, the per-domain agentfleet:<domain>-admin roles and the agentfleet:admin superuser mean something only through those Authlink grants. See access-control roles for each role's permission bundle.

Conventions ​

  • Routes follow api/{controller}, e.g. api/resources, api/workflows, api/workflowinstances, api/evalsuites. A few controllers use kebab-case prefixes: api/model-providers, api/assistant-profiles, api/workflow-packages, api/threads. Routes are case-insensitive.
  • Mutations take JSON bodies, and most carry the target id in the body (PUT /api/agents/activate with { "agentId": "…" }), not in the route.
  • List endpoints support searchText and status filters, and most also have a paged variant at /paged?pageNumber=&pageSize=.
  • Errors are problem responses with a code. Validation failures are 400 with per-field detail.
  • An unmatched path under /api answers 404. It never serves the console's HTML.

Resources & tools ​

Method & pathPurpose
POST /api/resourcesRegister an MCP resource (name, description, baseUrl, path).
POST /api/resources/{id}/import-toolsDiscover and upsert the resource's tools. Returns imported/updated counts (import-mcp-tools).
PUT /api/resources/activate / deactivate · DELETE /api/resourcesManage the resource lifecycle.
PUT /api/resources/dpop-requirementRequire DPoP-bound tokens for the resource.
PUT /api/resources/sensitivity-labelsLabel the data the resource's tools return (e.g. pii), checked against model allowlists.
GET /api/tools?resourceId=&status=&searchText=List tools.
PUT /api/tools · activate · deactivate · DELETE /api/toolsUpdate a tool (e.g. correct a scope) and manage its lifecycle.

Skills ​

Reusable, versioned prompt blocks a model step includes in its system prompt.

Method & pathPurpose
POST /api/skills · PUT /api/skillsCreate a skill, or save an edit as its next version.
PUT /api/skills/activate / deactivate · DELETE /api/skillsManage the skill lifecycle. A step that attaches a deactivated skill fails when it runs.
GET /api/skills/{id} · GET /api/skills/pagedRead skills, with their version history.
PUT /api/steps/skillsAttach skills to a step, in prompt order (update-step).

Steps & workflows ​

Method & pathPurpose
POST /api/stepsCreate a step (name, description, instruction, and optionally kind (Model, Deterministic, SubWorkflow), maxRounds, tokenBudget, outputSchema).
POST / PUT / DELETE /api/steps/toolsAdd, reorder or remove a tool on a step's allowlist.
PUT /api/steps/retrieval · PUT /api/steps/clarificationDeclare the tool calls a step makes before its model runs, or let the step ask a person a question.
POST /api/workflowsCreate a workflow (name, description).
POST / PUT / DELETE /api/workflows/stepsAttach, reorder or remove a step (workflowId, stepId, order).
PUT /api/workflows/steps/model-override · steps/condition · steps/parallel-groupRoute a step to another model, skip it on a JMESPath condition, or run adjacent steps in parallel.
PUT /api/workflows/activate / deactivate · DELETE /api/workflowsActivate a workflow so it can run (or deactivate or delete it).
GET /api/workflows/catalogThe workflow catalogue: each workflow with its tier, default agent, schedule, last run and eval status.

Versions and run policy ​

Runs, schedules and triggers use the latest published version by default. See Steps & Workflows and the workflow versions runbook.

Method & pathPurpose
POST /api/workflows/versionsPublish the current draft as the next immutable version (update-workflow).
GET /api/workflows/{id}/versions · versions/{n} · draft · versions/diffVersion history, one frozen version, the live draft, and a diff of two definitions.
PUT /api/workflows/run-policySet the confirmation tier and the default agent used when a launch names none.
PUT /api/workflows/promotion-gate · GET /api/workflows/{id}/promotion-gateSet or read the eval criteria a version must meet before it may auto-apply.
PUT /api/workflows/run-policy/overridePromote to auto-apply despite an unmet gate, with a justification (override-workflow-promotion-gate).
PUT /api/workflows/retry-policy · fallback · purpose-requirementSet max attempts before dead-lettering, the dead-letter fallback workflow, and whether every run must state a purpose.
PUT / DELETE /api/workflows/{id}/mcp-exposureExpose a published workflow to external agents as an MCP tool, or withdraw it (expose-workflows). See MCP Server.

Workflow packages ​

Method & pathPurpose
GET /api/workflow-packages/export?workflowId=&versionNumber=Export a published version as a package document (export-workflow-packages).
POST /api/workflow-packages/previewPreview an import into your tenant (how each requirement resolves). Writes nothing.
POST /api/workflow-packages/importImport in one transaction. Re-importing updates what the earlier import installed (import-workflow-packages).
GET /api/workflow-packages/installationsThe packages installed in your tenant.

Runs ​

Runs are managed through the workflow instances controller. See Runs.

Method & pathPurpose
PUT /api/workflowinstances/runQueue a run. Takes workflowId, optional agentId (defaults to the workflow's default agent), initialContext (see Run Inputs), workflowVersionNumber or useDraft, clientRequestId (idempotency), dryRun and callback. Returns 202 with workflowInstanceId and alreadyQueued (run-workflow-instance).
GET /api/workflowinstances/{id}Run state (Idle, Running, Waiting, AwaitingRetry, Completed, Failed, Cancelled, DeadLettered) and failure reason.
GET /api/workflowinstances/{id}/detail · timeline · summaryComposite run detail, the execution waterfall, and aggregate metrics (steps, tokens, latency, timing).
GET /api/workflowinstances/{id}/context · context/{entryId}The run's context entries with provenance, and one entry's full value.
GET /api/workflowinstances/paged · summaries/pagedPage through runs, or run summaries for dashboards.
GET /api/workflowinstances/statisticsThis month's runs, auto-applied runs and estimated model spend for your tenant.
PUT /api/workflowinstances/cancelCancel a run that has not ended. A queued run never starts; a running one stops at its next checkpoint. Returns 202.

Queue a run ​

bash
curl -X PUT "https://api.agentfleet.co.za/api/workflowinstances/run" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "workflowId": "<workflow-id>",
    "agentId": "<agent-id>",
    "clientRequestId": "order-1042-attempt-1",
    "initialContext": {
      "task_id": "task-7f3a",
      "purpose": "instance-fulfilment",
      "customerRef": "C-1042"
    }
  }'
# → 202 Accepted { "workflowInstanceId": "…", "alreadyQueued": false }

Run callbacks ​

Add "callback": { "url": "…" } to the run request and Agentfleet POSTs signed started, completed, failed and cancelled callbacks to that URL. The URL must sit under a callback target configured on the Agentfleet side (RunCallbacks:Targets). Any other URL is refused with 400. The headers, HMAC signature and retry behaviour are in the run callbacks contract.

Waiting runs: tool confirmations and clarifications ​

A run pauses when a tool call needs a person's approval, or when its model asks a question with request_clarification. Answering resumes the run.

Method & pathPurpose
GET /api/toolconfirmations?status=&workflowInstanceId= · GET /api/toolconfirmations/{id}The pending confirmation queue (pending by default), or one run's confirmations.
POST /api/toolconfirmations/{id}/approve · rejectApprove a call, optionally with edited arguments, or reject it. The run resumes either way (confirm-tool-calls).
GET /api/clarifications?status=&workflowInstanceId= · GET /api/clarifications/{id}The pending question queue, or one run's questions.
POST /api/clarifications/{id}/answerAnswer a question and resume its run (answer-clarifications).

Run operations ​

Operational endpoints for the durable run queue, dead-letter recovery and resuming paused (waiting) instances. The agentfleet:operator role and the run-operations-admin domain role hold these permissions.

Method & pathPurpose
GET /api/runoperations/queuePoint-in-time run-queue depth by disposition (view-run-queue).
GET /api/runoperations/dead-lettersRuns parked in the dead-letter store (view-dead-lettered-runs).
POST /api/runoperations/dead-letters/requeueRequeue a dead-lettered run. Returns 202 (requeue-dead-lettered-run).
GET /api/runoperations/pausedInstances paused on a wait step (view-waiting-instances).
POST /api/runoperations/paused/resumeResume a waiting instance when its wait outcome arrives (resume-workflow-instance).

Agents & model providers ​

Method & pathPurpose
POST /api/agentsCreate an agent (registered as a delegated agent with a secretless client).
PUT /api/agents · activate · deactivate · DELETE /api/agentsManage the agent lifecycle.
PUT /api/agents/workflow-toolsSet the published workflows an Orchestrator agent may call as tools (each call is a child run).
POST /api/model-providersConfigure a model provider (models, default model, max tokens).
PUT /api/model-providers · activate · deactivate · DELETE /api/model-providersManage the provider lifecycle.
PUT /api/model-providers/model-lifecycleMark a model active, deprecated (with an optional sunset date) or sunset. A sunset model is refused.
PUT /api/model-providers/model-sensitivity-allowlistSet the data sensitivity labels a model may receive.

Dependencies & model swaps ​

Method & pathPurpose
GET /api/dependencies/modelsEvery model offered or used, with lifecycle and usage. Deprecated or sunset models still in use come first (view-dependencies).
GET /api/dependencies/graph?rootKind=&provider=&model=&id=What depends on a model, resource, tool or agent, with recent runs, failure rate and cost.
POST /api/dependencies/model-swaps/planPreview swapping one model for another: affected workflows, eval suites and warnings (swap-models).
POST /api/dependencies/model-swaps/evaluateStart an eval experiment per affected suite comparing current vs swapped models. Changes nothing.
POST /api/dependencies/model-swapsApply the swap to the selected targets in one audited operation.

See the model dependencies runbook.

Automation ​

Schedules fire a workflow on a cron cadence. Event triggers fire it on an inbound Service Bus event. Webhook triggers fire it on an authenticated HTTP call. See Automation.

Method & pathPurpose
POST /api/schedulesCreate a schedule (workflowId, agentId, cron expression, input template).
PUT /api/schedules · enable · disable · DELETE /api/schedulesManage the schedule lifecycle.
PUT /api/schedules/fireFire now: trigger a run on demand. Returns 202 (fire-schedule).
GET /api/schedules/{id} · GET /api/schedules/paged?workflowId=&isEnabled=Read schedules.
POST /api/eventtriggersCreate an event trigger (workflowId, agentId, Service Bus topic/subscription, eventType, input mappings, optional condition).
PUT /api/eventtriggers · enable · disable · DELETE /api/eventtriggersManage the trigger lifecycle.
GET /api/eventtriggers/{id} · GET /api/eventtriggers/paged?workflowId=&isEnabled=Read event triggers.
POST /api/webhooktriggersCreate a webhook trigger: workflow (optionally a pinned version), agent, authentication (Hmac or ClientCredentials), payload condition and input mapping.
PUT /api/webhooktriggers · enable · disable · DELETE /api/webhooktriggersManage the webhook trigger lifecycle.
GET /api/webhooktriggers/{id} · GET /api/webhooktriggers/pagedRead webhook triggers.

Webhook deliveries ​

POST /api/webhooks/{webhookTriggerId} is the endpoint callers deliver events to. It does not take an Agentfleet user session: each trigger authenticates its own callers, either with an HMAC signature (X-Agentfleet-Timestamp and X-Agentfleet-Signature: sha256=…) or with a client-credentials bearer token. A repeated Idempotency-Key returns the first delivery's run. Returns 202 with the run that was started, if any. See the triggers runbook.

Evaluations ​

Eval suites are managed at api/evalsuites and eval runs at api/evalruns. See Evaluations.

Method & pathPurpose
POST /api/evalsuitesCreate a suite (name, description, targetWorkflowId, optional targetStepId, agentId, scoringRubric).
PUT /api/evalsuitesUpdate a suite (bumps its version).
POST /api/evalsuites/cases · cases/importAdd a case, or import a batch of cases all-or-nothing.
DELETE /api/evalsuites/{id}/cases/{caseId}Remove a case.
GET /api/evalsuites/{id} · GET /api/evalsuites?searchText=&status=Read suites (with their cases).
POST /api/evalrunsStart a run: evalSuiteId, optional passThreshold (default 1.0), workflowVersionNumber or useDraft. Returns 202.
GET /api/evalruns/{id} · GET /api/evalruns?evalSuiteId=A run with its per-case results, or a list of runs, most recent first.
GET /api/evalruns/score-trend/{evalSuiteId} · promotion-readiness/{evalSuiteId}The suite's score over time, and whether it meets the promotion streak.
GET /api/evalruns/{id}/evidence-reportDownload the completed run's evidence report as a JSON attachment.
GET /api/evalruns/human-grading-queue · PUT /api/evalruns/{id}/results/{resultId}/human-gradeCase executions waiting for a person's grade, and recording one (grade-eval-result).
GET /api/evalruns/judge-agreement/{evalSuiteId}How often the LLM judge agrees with human grades.

Start an eval run ​

bash
curl -X POST "https://api.agentfleet.co.za/api/evalruns" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "evalSuiteId": "<suite-id>", "passThreshold": 0.8 }'
# → 202 Accepted { "evalRunId": "…" }

Experiments and model optimisation ​

Method & pathPurpose
POST /api/evalexperimentsStart an experiment: one eval run per variant (evalSuiteId, name, variants, repetitions, passThreshold) (start-eval-run).
GET /api/evalexperiments/{id} · GET /api/evalexperiments?evalSuiteId=An experiment's progress and comparison against its baseline, or a suite's experiments.
GET /api/evalexperiments/compare?evalSuiteId=&baselineEvalRunId=&evalRunIds=Compare eval runs of one suite against a baseline: pass rate, score, cost, latency and per-case regressions.
POST /api/modeloptimisationsStart a sweep of candidate models per step within an eval budget. It proposes the cheapest passing configuration (optimise-models).
GET /api/modeloptimisations/{id} · GET /api/modeloptimisations?workflowId=An optimisation's ranked configurations and proposal, or the list.
POST /api/modeloptimisations/{id}/cancel · resumeStop an optimisation, or re-drive one whose next run did not start.
POST /api/modeloptimisations/{id}/applyWrite the proposal to the workflow's draft as step model overrides. Nothing is published (update-workflow-step).

Conversations (threads) ​

Multi-turn chats between a signed-in person and an active assistant profile. See Conversations and the threads runbook.

Behind Threads:Enabled

Threads ship off. While Threads:Enabled is false (the default), every api/threads endpoint answers 404 before authentication runs.

Each turn runs synchronously inside the request, as the caller, and a message needs a person's token (service and agent tokens are refused with 403). You only ever see your own threads: another user's thread answers 404.

Method & pathPurpose
POST /api/threadsStart a thread (assistantProfileId, optional purpose, hostContext). The profile's current version is pinned (start-thread).
POST /api/threads/{id}/messagesSend a message and get the assistant's reply: JSON, or an SSE stream (see below) (send-thread-message). 409 while another turn is running.
POST /api/threads/{id}/confirmations/{confirmationId}/approve · rejectDecide the tool call a turn paused on, then continue the turn. Answered like a message, streamed or JSON.
POST /api/threads/{id}/turns/{turnId}/cancelCancel a running turn. Returns 202.
PUT /api/threads/rename · archive · DELETE /api/threadsRename, archive (read-only from then on) or delete a thread.
GET /api/threads/{id} · GET /api/threads/pagedOne of your threads with its turns and cost, or your threads.
GET /api/threads/{id}/conversationThe reconstructed model conversation of every turn, as the provider received it.

Streaming events ​

Send Accept: text/event-stream to the messages, approve and reject endpoints and the turn arrives as server-sent events. Each event is an event: name and one data: line of camelCase JSON:

EventData
turn_started{ turnId, sequence }
text_delta{ text }: a preview fragment. The reply itself is in turn_completed.
tool_call_started · tool_call_completed{ toolName, toolCallId }, plus status (Completed, Failed, Declined) on completion. Never arguments or results.
workflow_run_started{ toolName, toolCallId, workflowInstanceId, workflowName }: a workflow tool queued a run.
confirmation_required{ turnId, confirmationId, toolName, toolCallId, arguments, expiresAt }: the turn paused for your approval. Last event of the request.
turn_completed{ turn }: the same turn the JSON response carries.
error{ status, title, code, detail }: the turn failed after the stream started.

A request refused before its turn starts gets an ordinary status code and problem body, not a stream.

Assistant profiles ​

Method & pathPurpose
POST /api/assistant-profilesCreate a profile: the agent, instruction, tools and skills a thread runs with, plus per-turn limits (create-assistant-profile).
PUT /api/assistant-profilesSave an edit as the profile's next version.
PUT /api/assistant-profiles/activate / deactivate · DELETE /api/assistant-profilesManage the lifecycle. Threads cannot start with an inactive profile.
GET /api/assistant-profiles/{id} · GET /api/assistant-profiles/pagedRead profiles, with their version history.

Usage limits & retention ​

See Governance and the usage governance runbook.

Method & pathPurpose
GET /api/usage/limitsYour tenant's usage limits with month-to-date spend and budget level (view-usage).
POST / PUT /api/usage/limits · DELETE /api/usage/limits/{id}Create a limit (tenant, workflow, provider/model, user or assistant profile), change it, or remove it (manage-usage-limits).
GET /api/usage/history?from=&to=&granularity=&workflowId=Model calls, tokens and cost by hour (up to 14 days) or day (up to 400 days), broken down by provider/model.
GET / PUT /api/usage/thread-retentionRead or set how long deleted threads' content is kept and after how many idle days a thread's vectors are purged (1–3650 days each).
Method & pathPurpose
GET /api/modelcalls?workflowInstanceId=&stepInstanceId= · GET /api/modelcalls/{id}Model calls for a run or step (tokens, latency, round, input/output), paged.
GET /api/toolcalls?workflowInstanceId=&stepInstanceId= · GET /api/toolcalls/{id}Tool calls for a run or step, with arguments and results, paged.
GET /api/stepinstances/summaries/paged · GET /api/stepinstances/{id}/conversationPer-step metrics for a run, and a step's full per-round model conversation.
GET /api/agentinstances · GET /api/stepinstances/pagedThe agent and step instances behind a run.
GET /api/activities/paged?searchText=&entityType=&entityId=The audit activity feed.
GET /api/search?searchText=&limit=Search across agents, steps, tools, resources and workflows (limit defaults to 5). Only the entity types you may view are searched, filtered to your tenant.
GET /health · GET /whoamiUnauthenticated health probe (includes a database check) and service identity.

The agent-instance and step-instance mutation endpoints (run, complete, fail, skip) are run-pipeline internals. You don't need them to queue or observe runs.

Console-only endpoints ​

The console's backend-for-frontend uses a few endpoints that are not meant for integrations:

  • api/auth/callback, refresh, logout, me (Auth): sign-in code exchange and HttpOnly session cookies.
  • GET /api/auth/permissions (AuthPolicy): the signed-in user's effective permission keys from the PDP.
  • POST /api/access/evaluations: rate-limited batch PDP checks the console makes for the current user.
  • GET /api/diagnostics/policy-canary: a diagnostic that only succeeds when the PDP allows agentfleet:policy-canary, used to check the PDP integration end to end.

.NET SDK ​

The Agentfleet.Client.Http NuGet package (current version 1.4.0, with its contracts in Agentfleet.Client.Core; targets net8.0 and net10.0) wraps the run and thread endpoints. AddAgentfleetWorkflowClient(...) registers IAgentfleetWorkflowClient, for queueing a run and awaiting its result (RunWorkflowAndWaitAsync), and IAgentfleetThreadClient, which streams a thread turn's events as an IAsyncEnumerable. Supply the bearer token statically, through a token factory, or through your own IAgentfleetTokenProvider.

Agentfleet — agent workflow orchestration.