Skip to content
Tracon

Workflows

16 operations. {prefix} is the route prefix passed to MapTracon; the template uses /tracon.

Operation ID: TraconListWorkflows

Lists workflows defined in code and stored in the database.

What the list contains depends on whether the workflow engine is registered. With the engine, both code-defined and stored workflows appear, because only the engine can see the ones built in code. Without it, only stored definitions are listed — managing definitions does not require the engine, but running them does.

Authorization: bearer authentication; Reader role policy when that policy is registered; WorkflowsRead API-key scope.

Response Body Headers
200 OK application/json → array of WorkflowDescriptor —

Operation ID: TraconGetWorkflow

Returns a single workflow definition.

Only stored definitions are editable and only they are returned here. A code-defined workflow is listed and can be run but has no stored definition, so it answers 404 with a distinct ‘No editable definition’ title — different from the plain not-found title used for a name that does not exist at all. Read the structure of a code-defined workflow from the graph endpoint instead.

Authorization: bearer authentication; Reader role policy when that policy is registered; WorkflowsRead API-key scope.

Parameter In Required Type Description and rules
name path yes string —
Response Body Headers
200 OK application/json → WorkflowDefinition —

Operation ID: TraconSaveWorkflow

Creates or updates a workflow definition.

The definition is validated at save time with the same rules the compiler applies, so a shape that could not run is rejected with 400 instead of failing on the first run. Which fields are required depends on the kind — a manager driven workflow needs its manager agent, for example. A function node’s ‘settings’ must be a JSON object that fits the settings type its function declares (see settingsSchema on GET /api/workflows/functions): an unknown field, a missing required member and a value of the wrong type are all refused with a message that names the node and the member, and so is any settings on an agent node or on a function that declares none. Settings are stored in the definition: never put a secret in them, name its configuration key instead. A node’s ‘timeout’ (function or agent node, hh:mm:ss) must be from 1 ms to about 49.7 days, 30 seconds less on an agent node; it is not checked against the run’s timeout. An agent node’s ‘agentVersion’ pins the step to that version of the agent; it must be 1 or more, only an agent node may carry one, and the agent must have that version (an agent defined in code keeps no versions): anything else is refused with 400. ‘runTimeout’ bounds one run of this workflow: it may only shorten Tracon:Workflows:RunTimeout unless the host sets Tracon:Workflows:MaxRunTimeout, and a value above that ceiling is refused with 400. The call replaces the whole definition: omitted fields are cleared, not merged. The name comes from the path and is not taken from the body. The name ‘functions’ is reserved (400): GET /api/workflows/functions uses it. Every save appends a version rather than overwriting; the previous content stays readable through GET /api/workflows/{name}/versions.

Authorization: bearer authentication; Admin role policy when that policy is registered; WorkflowsAdmin API-key scope.

Parameter In Required Type Description and rules
name path yes string —

Request body (required):

Response Body Headers
200 OK application/json → WorkflowDefinition —

Operation ID: TraconDeleteWorkflow

Deletes a workflow definition.

Only a stored definition can be deleted; a code-defined workflow is removed by changing the application, and asking for one here returns 404. Runs and checkpoints already recorded are kept, so past executions stay readable, but a checkpoint cannot be resumed once the definition it needs is gone. The version history is kept too, so a version number is never given to a second content: saving the name again continues the numbering.

Authorization: bearer authentication; Admin role policy when that policy is registered; WorkflowsAdmin API-key scope.

Parameter In Required Type Description and rules
name path yes string —
Response Body Headers
204 No Content — —

Operation ID: TraconGetWorkflowGraph

Returns the compiled graph of the workflow.

Node IDs are identical to the executor IDs in run events; this is how the UI colors nodes live. The response also carries the Mermaid text generated by Microsoft Agent Framework.

Authorization: bearer authentication; Reader role policy when that policy is registered; WorkflowsRead API-key scope.

Parameter In Required Type Description and rules
name path yes string —
Response Body Headers
200 OK application/json → WorkflowGraph —

POST {prefix}/api/workflows/{name}/rollback

Section titled “POST {prefix}/api/workflows/{name}/rollback”

Operation ID: TraconRollbackWorkflow

Writes a workflow definition as a new version with the content of a previous version.

A rollback moves forward, not backward: the old content is appended as a NEW version and the history is never rewritten, so the rollback itself stays auditable (‘workflow.rollback’) and can be rolled back in turn. The content is checked the way a save is: a version that names a function that is no longer registered, or an agent version that no longer exists, is refused with 400 and nothing is written. An unknown version number returns 404; a workflow defined in code returns 409. A run that is waiting keeps the version it recorded, so a rollback does not change what it resumes with.

Authorization: bearer authentication; Admin role policy when that policy is registered; WorkflowsAdmin API-key scope.

Parameter In Required Type Description and rules
name path yes string —

Request body (required):

Response Body Headers
200 OK application/json → WorkflowDefinition —
400 Bad Request application/problem+json → ProblemDetails —
404 Not Found application/problem+json → ProblemDetails —
409 Conflict application/problem+json → ProblemDetails —

Operation ID: TraconRunWorkflow

Runs the workflow and streams its events over SSE, or queues it with ‘Prefer: respond-async’.

Each frame carries a RunEvent. The first frame reports the run ID; every agent invoked within the workflow opens its own runs row, viewable as a tree via GET /api/runs/{runId}/tree. If a registered IRunAuthorizationHandler denies the caller, the run does not start and a 403 is returned, before the quota check. When session ownership is turned on, naming another user’s session in ‘sessionId’ is refused the same way, and so is opening a NEW session when no authenticated identity can be resolved to own it. A streamed run belongs to the connection: if the client stops reading, the run closes as Canceled. A request carrying ‘Prefer: respond-async’ is checked the same way and then queued: the answer is ‘202 Accepted’ with a ‘Location’ header and the run id, the run executes in the background worker, and its events are read from GET /api/runs/{runId}/events. A queued run does not depend on any connection, and with ResumeInterruptedRuns on it is resumed from its latest checkpoint after a restart. ‘Idempotency-Key’ is accepted only together with ‘Prefer: respond-async’ (400 otherwise); a repeated request returns the same 202 and queues nothing. With queuing disabled (Tracon:AsyncRun:Enabled = false) the preference is answered with 501.

Authorization: bearer authentication; Operator role policy when that policy is registered; RunsWrite API-key scope.

Parameter In Required Type Description and rules
name path yes string —

Request body (optional):

Response Body Headers
200 OK text/event-stream → string —
202 Accepted application/json → AcceptedRunResponse —
400 Bad Request application/problem+json → ProblemDetails —
403 Forbidden application/problem+json → ProblemDetails —
404 Not Found application/problem+json → ProblemDetails —
429 Too Many Requests application/problem+json → ProblemDetails —
501 Not Implemented application/problem+json → ProblemDetails —
503 Service Unavailable application/problem+json → ProblemDetails —

GET {prefix}/api/workflows/{name}/versions

Section titled “GET {prefix}/api/workflows/{name}/versions”

Operation ID: TraconListWorkflowVersions

Lists a workflow definition’s version history, newest first.

Every entry is a full definition snapshot, not a delta, so a single entry is enough to inspect or restore a past state. The workflow must have a current stored definition; a deleted name returns 404 even though its versions are kept (a version number is never reused). A workflow defined in code also returns 404, with a reason that says so: it is not stored by Tracon and has no version history. The ‘agentVersion’ of a run’s row is the workflow version it was compiled from.

Authorization: bearer authentication; Reader role policy when that policy is registered; WorkflowsRead API-key scope.

Parameter In Required Type Description and rules
name path yes string —
Response Body Headers
200 OK application/json → array of WorkflowDefinition —
404 Not Found application/problem+json → ProblemDetails —

GET {prefix}/api/workflows/{name}/versions/{a}/diff/{b}

Section titled “GET {prefix}/api/workflows/{name}/versions/{a}/diff/{b}”

Operation ID: TraconGetWorkflowVersionDiff

Returns two definition versions as raw JSON; the diff is computed in the UI.

The server does no diffing and takes no position on how a change should be displayed; it returns both snapshots verbatim as ‘left’ and ‘right’ so the client chooses the presentation. The two version numbers may be given in any order. When either version is missing the response is 404 and names the one that was not found; a workflow defined in code returns 404 saying it has no version history.

Authorization: bearer authentication; Reader role policy when that policy is registered; WorkflowsRead API-key scope.

Parameter In Required Type Description and rules
name path yes string —
a path yes integer (int32) pattern `^-?(?:0\
b path yes integer (int32) pattern `^-?(?:0\
Response Body Headers
200 OK application/json → WorkflowVersionDiffResponse —
404 Not Found application/problem+json → ProblemDetails —

Operation ID: TraconListWorkflowFunctions

Lists function nodes registered in code.

Function nodes are defined only in code, with AddWorkflowFunction - the same code-only boundary AddTool draws for tools. This endpoint does not offer a write path; the console picks from this list when an operator builds a Sequential workflow’s node list. A function that takes settings carries settingsSchema, a JSON schema of the object a node of it may carry in ‘settings’; a function that takes none has settingsSchema null and its nodes must carry no settings. ‘timeout’ is the time limit the function was registered with, which a node’s own ‘timeout’ replaces; null means none. The schema is for display: saving the workflow does the checking. An empty list means no function was registered, or the workflow engine was never turned on with UseWorkflows - either way, existing agent-only workflows are unaffected.

Authorization: bearer authentication; Reader role policy when that policy is registered; WorkflowsRead API-key scope.

Response Body Headers
200 OK application/json → array of WorkflowFunctionResponse —

Operation ID: TraconListWorkflowInbox

Lists the human input requests the tenant’s workflow runs are waiting on.

One item per request, oldest first. The same request id in the same session is ONE request even when several runs hold it (an answered run stays ‘AwaitingInput’ and the continuation republishes the requests that are still open); the item names the newest run that waits on it, which is the run to answer. ‘state’ is ‘pending’ (the default: nobody has answered), ‘answered’ (answered, but the run still waits) or ‘all’; ‘workflowName’ narrows the list to one workflow. The filter runs before the page, so ‘skip’ and ‘take’ (1-200, default 50) page over the filtered list. Each item carries ‘expiresAt’ (when the workflow sets a request timeout), ‘answered’ and ‘lastResponseRunId’. A run whose request expired is closed and leaves the list. The list is the tenant’s: a registered IRunAuthorizationHandler that denies reading runs rejects it with 403 and never filters it, so a page is never shorter than the caller is allowed to see. An installation that has not registered the workflow engine answers 501. Runs that started waiting before this list existed are not in it; read them with GET /api/workflows/runs/{runId}/requests.

Authorization: bearer authentication; Reader role policy when that policy is registered; RunsRead API-key scope.

Parameter In Required Type Description and rules
state query no string —
workflowName query no string —
skip query no integer (int32) pattern `^-?(?:0\
take query no integer (int32) pattern `^-?(?:0\
Response Body Headers
200 OK application/json → array of WorkflowPendingRequest —
400 Bad Request application/problem+json → ProblemDetails —
403 Forbidden application/problem+json → ProblemDetails —
501 Not Implemented application/problem+json → ProblemDetails —

GET {prefix}/api/workflows/runs/{runId}/checkpoints

Section titled “GET {prefix}/api/workflows/runs/{runId}/checkpoints”

Operation ID: TraconListWorkflowCheckpoints

Lists the checkpoints of a workflow run.

Checkpoints are the points a run can be resumed from; each entry’s id is what the resume endpoint takes. A run belonging to another tenant is reported as 404 rather than 403, so the API does not confirm that it exists. An empty list means the run wrote no checkpoint — checkpointing is a property of how the workflow was built, not something this endpoint can turn on. Checkpoints are subject to retention, so an old run may have none left. A denial by a registered IRunAuthorizationHandler produces the same 404.

Authorization: bearer authentication; Reader role policy when that policy is registered; RunsRead API-key scope.

Parameter In Required Type Description and rules
runId path yes string (uuid) —
Response Body Headers
200 OK application/json → array of WorkflowCheckpointRecord —

GET {prefix}/api/workflows/runs/{runId}/requests

Section titled “GET {prefix}/api/workflows/runs/{runId}/requests”

Operation ID: TraconListWorkflowRequests

Lists a run’s pending human input requests.

Only a run in the ‘AwaitingInput’ state returns requests. The prompt and the form are read from the run’s event stream; ‘expiresAt’, ‘answered’ and ‘lastResponseRunId’ come from the inbox row the run wrote when it started waiting (see GET /api/workflows/requests). A run belonging to another tenant, and a denial by a registered IRunAuthorizationHandler, both return the same 404.

Authorization: bearer authentication; Reader role policy when that policy is registered; RunsRead API-key scope.

Parameter In Required Type Description and rules
runId path yes string (uuid) —
Response Body Headers
200 OK application/json → array of WorkflowPendingRequest —
404 Not Found application/problem+json → ProblemDetails —

POST {prefix}/api/workflows/runs/{runId}/respond

Section titled “POST {prefix}/api/workflows/runs/{runId}/respond”

Operation ID: TraconRespondWorkflowRequest

Responds to a pending request and resumes the run, streamed or queued with ‘Prefer: respond-async’.

The response is matched to the request re-published with the same ID in the execution resumed from the checkpoint. Resuming opens a NEW runs row; events stream over SSE — so this STARTS a run, and a registered IRunAuthorizationHandler is asked with the source run’s id; a denial returns 403 before any run row is opened. The answer is checked before the stream opens: a response of the wrong shape, a run that is not waiting and an unknown request id are all 400; an unknown run is 404. The run continues with the version of the workflow’s definition it recorded, or with the stored version ‘definitionVersion’ names (a version the workflow does not have is 400). With ‘Prefer: respond-async’ it is then queued: the reply is ‘202 Accepted’ and the run continues in the background worker, so a machine that answers a request does not have to keep a connection open. The queued answer is stored with the job until the job is removed; do not put a secret in it. ‘Idempotency-Key’ is accepted only together with ‘Prefer: respond-async’. Every answer that starts a run is written to the audit trail as ‘workflow.respond’ before the run starts, with a SHA-256 of the answer and never the answer itself; when that entry cannot be written the answer is refused with 500 and nothing is started. A workflow whose responseMode is ‘SingleAnswer’ takes one answer per request: repeating the same answer (approved, text and data; the checkpoint and version do not count) starts nothing and follows the run the first one started - the same SSE frames read from the stored run, or the same 202 with ‘Prefer: respond-async’ - and a different answer is 409, which names neither the run nor the other answer. An answer whose run failed or was cancelled before the workflow received it can be given again and starts a new run. With ‘Branch’, the default, every answer opens a new run. A request whose ‘form’ is ‘ToolApproval’ is an agent’s tool call that waits for approval: answer it with ‘approved’, a reason in ‘text’ that the model reads, and ‘remember’ to also save the approval as a rule for that agent and tool. It takes no ‘data’: the tool call comes from the request the workflow recorded, so an answer cannot approve a different one. The decision is audited as ‘approval.decision’ before it is applied, and ‘remember’ with ‘approved’ false, or on any other form, is 400.

Authorization: bearer authentication; Operator role policy when that policy is registered; RunsWrite API-key scope.

Parameter In Required Type Description and rules
runId path yes string (uuid) —

Request body (optional):

Response Body Headers
200 OK text/event-stream → string —
202 Accepted application/json → AcceptedRunResponse —
400 Bad Request application/problem+json → ProblemDetails —
403 Forbidden application/problem+json → ProblemDetails —
404 Not Found application/problem+json → ProblemDetails —
409 Conflict application/problem+json → ProblemDetails —
501 Not Implemented application/problem+json → ProblemDetails —
503 Service Unavailable application/problem+json → ProblemDetails —

GET {prefix}/api/workflows/runs/{runId}/responses

Section titled “GET {prefix}/api/workflows/runs/{runId}/responses”

Operation ID: TraconListWorkflowResponses

Lists the answers given to a run’s human input requests.

One entry per answer that started a run, oldest first: the request it answered, the run it started (responseRunId), who answered and when, and a SHA-256 of the answer (answerHash) - never the answer itself. The hash tells two answers apart; it does not hide an answer with few possible values, such as a yes or no. ‘claimScope’ is set when the workflow takes one answer per request; ‘status’ is Accepted until the workflow received the answer (Delivered), and Abandoned for an answer whose run stopped and was started again. A run belonging to another tenant, and a denial by a registered IRunAuthorizationHandler, both return the same 404.

Authorization: bearer authentication; Reader role policy when that policy is registered; RunsRead API-key scope.

Parameter In Required Type Description and rules
runId path yes string (uuid) —
Response Body Headers
200 OK application/json → array of WorkflowResponseRecord —
404 Not Found application/problem+json → ProblemDetails —

POST {prefix}/api/workflows/runs/{runId}/resume

Section titled “POST {prefix}/api/workflows/runs/{runId}/resume”

Operation ID: TraconResumeWorkflow

Resumes from a checkpoint and streams events over SSE, or queues it with ‘Prefer: respond-async’.

Resuming opens a NEW run rather than continuing the old one: the original run row is never rewritten, and the first streamed frame reports the new run id. The body is optional — without a checkpoint id the run resumes from its latest checkpoint. The run resumes with the version of the workflow’s definition that it recorded (‘agentVersion’ of its row), so an edit made while it waited changes nothing; ‘definitionVersion’ names another stored version, and a version the workflow does not have is 400, never a silent fall-back to the current one. A version whose graph differs from the checkpoint’s fails the run with ‘the graph’s structure differs’. A run that recorded no version resumes with the current definition. The engine must be registered; otherwise the response is 501. The source run and its checkpoint are checked before the stream opens: an unknown run is 404, and a run that is not a workflow run or has no such checkpoint is 400. A failure after the stream opens arrives as an SSE error frame. Resuming STARTS a run, so a registered IRunAuthorizationHandler is asked with the SOURCE run’s id; a denial returns 403 before any run row is opened. With ‘Prefer: respond-async’ the resume is queued and answered with ‘202 Accepted’, like a queued run, after the same checks. A queued resume is not counted against the quota, the same as a streamed one. ‘Idempotency-Key’ is accepted only together with ‘Prefer: respond-async’.

Authorization: bearer authentication; Operator role policy when that policy is registered; RunsWrite API-key scope.

Parameter In Required Type Description and rules
runId path yes string (uuid) —

Request body (optional):

Response Body Headers
200 OK text/event-stream → string —
202 Accepted application/json → AcceptedRunResponse —
400 Bad Request application/problem+json → ProblemDetails —
403 Forbidden application/problem+json → ProblemDetails —
404 Not Found application/problem+json → ProblemDetails —
501 Not Implemented application/problem+json → ProblemDetails —
503 Service Unavailable application/problem+json → ProblemDetails —