`GET /api/workflows/{id}` — get one workflow with its ordered steps.
const url = 'https://example.com/api/workflows/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0';const options = {method: 'GET'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url https://example.com/api/workflows/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”Workflow id
Responses
Section titled “Responses”A workflow plus its graph — the GET/PUT /api/workflows/{id} body.
steps keeps the v1 agent-only wire shape (every agent node in ordinal
order with depends_on rebuilt from the edge set) so older callers keep
working. nodes + edges is the typed-node graph the V8 builder consumes:
every node kind with its config, position and handle-carrying edges.
object
One directed edge as returned to the client (ADR 0020 V8) — a connection
from source’s source_handle output into target.
object
Issue #110: per-workflow concurrency cap; None = unlimited.
One typed node as returned to the client (ADR 0020 V8). Carries the node’s
kind, its kind-specific config blob and its canvas position — the
shape the Svelte Flow builder renders directly.
object
The node kind (node.kind, workflow_nodes.kind CHECK). Runtime stays
String; the spec narrows it to the closed [workflow_svc::NodeKindSpec].
WP V16: when set, this node lives INSIDE the named loop frame’s
sub-graph. The V8 builder wires up parentId / extent: 'parent'
on Svelte Flow nodes carrying this field.
A node’s canvas position in a response body.
object
A workflow step (an agent node) as returned to the client.
ADR 0020 reshapes the schema to typed nodes + edges; this DTO keeps the v1
agent-step wire shape (step_key + depends_on) so the existing web canvas
stays functional — depends_on is rebuilt from the node’s incoming edges.
object
The node kind (node.kind, workflow_nodes.kind CHECK). Runtime stays
String; the spec narrows it to the closed [workflow_svc::NodeKindSpec].
Example
{ "nodes": [ { "kind": "agent" } ], "steps": [ { "kind": "agent" } ]}Structured client error
The canonical JSON body of every error response — the single source of truth
the frontend binds to. Every AppError serializes as this exact shape, and
the generated OpenAPI component ApiErrorBody (with its ErrorCode enum) is
what the frontend error schema is generated from, so there is no hand-written
error schema on either end.
object
Machine-readable, stable error code.
Present only on a quota-exceeded 403 — the inline upgrade-CTA payload.
object
The entitlement feature key that was hit, e.g. apps.max_count.
The plan’s limit for this key.
Where to send the user to upgrade.
Current usage (count or bytes, per the key).
Human-readable message (the server’s English text; the client may localize
by code).
Example
{ "code": "not_found"}Authentication required
The canonical JSON body of every error response — the single source of truth
the frontend binds to. Every AppError serializes as this exact shape, and
the generated OpenAPI component ApiErrorBody (with its ErrorCode enum) is
what the frontend error schema is generated from, so there is no hand-written
error schema on either end.
object
Machine-readable, stable error code.
Present only on a quota-exceeded 403 — the inline upgrade-CTA payload.
object
The entitlement feature key that was hit, e.g. apps.max_count.
The plan’s limit for this key.
Where to send the user to upgrade.
Current usage (count or bytes, per the key).
Human-readable message (the server’s English text; the client may localize
by code).
Example
{ "code": "not_found"}Permission denied
The canonical JSON body of every error response — the single source of truth
the frontend binds to. Every AppError serializes as this exact shape, and
the generated OpenAPI component ApiErrorBody (with its ErrorCode enum) is
what the frontend error schema is generated from, so there is no hand-written
error schema on either end.
object
Machine-readable, stable error code.
Present only on a quota-exceeded 403 — the inline upgrade-CTA payload.
object
The entitlement feature key that was hit, e.g. apps.max_count.
The plan’s limit for this key.
Where to send the user to upgrade.
Current usage (count or bytes, per the key).
Human-readable message (the server’s English text; the client may localize
by code).
Example
{ "code": "not_found"}Workflow not found
The canonical JSON body of every error response — the single source of truth
the frontend binds to. Every AppError serializes as this exact shape, and
the generated OpenAPI component ApiErrorBody (with its ErrorCode enum) is
what the frontend error schema is generated from, so there is no hand-written
error schema on either end.
object
Machine-readable, stable error code.
Present only on a quota-exceeded 403 — the inline upgrade-CTA payload.
object
The entitlement feature key that was hit, e.g. apps.max_count.
The plan’s limit for this key.
Where to send the user to upgrade.
Current usage (count or bytes, per the key).
Human-readable message (the server’s English text; the client may localize
by code).
Example
{ "code": "not_found"}Structured server error
The canonical JSON body of every error response — the single source of truth
the frontend binds to. Every AppError serializes as this exact shape, and
the generated OpenAPI component ApiErrorBody (with its ErrorCode enum) is
what the frontend error schema is generated from, so there is no hand-written
error schema on either end.
object
Machine-readable, stable error code.
Present only on a quota-exceeded 403 — the inline upgrade-CTA payload.
object
The entitlement feature key that was hit, e.g. apps.max_count.
The plan’s limit for this key.
Where to send the user to upgrade.
Current usage (count or bytes, per the key).
Human-readable message (the server’s English text; the client may localize
by code).
Example
{ "code": "not_found"}