Skip to content
Select themeSelect language

`POST /api/workflows` — create a workflow from a JSON body. The DAG is validated by the service; an invalid DAG yields 400.

POST
/api/workflows
curl --request POST \
--url https://example.com/api/workflows \
--header 'Content-Type: application/json' \
--data '{ "name": "example", "nodes": [ { "config": "example", "depends_on": [ { "handle": "example", "key": "example" } ], "key": "example", "kind": "example", "parent_node_key": "example", "position": { "x": 1, "y": 1 } } ], "project_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "steps": [ { "agent_type": "example", "depends_on": [ "example" ], "key": "example", "on_failure": "example", "prompt": "example" } ] }'
Media typeapplication/json

POST /api/workflows body — create a workflow definition in a project. A request may carry either the v1 steps (agent-only) or the typed nodes array; nodes wins when present.

object
name
required
string
nodes
Array<object>

One typed node in a create/update request body (ADR 0020 V8 builder). The builder authors all four kinds; config is the kind-specific blob the spec layer persists verbatim, position is the canvas placement.

object
config

The kind-specific config blob; defaults to {}.

depends_on

This node’s incoming edges.

Array<object>

One incoming-edge declaration of a node in the typed-node wire shape — the source node_key plus the handle it leaves the source by (out for an agent node, true/false for a gate, approved/rejected for a human).

object
handle

The source’s output handle; defaults to out.

string
key
required
string
key
required
string
kind
required

agent / gate / human / end / code / loop / notify_*.

string
parent_node_key

WP V16: when set, this node lives INSIDE the named loop frame’s sub-graph. Omitted (None) means top-level.

string | null
position

A node’s canvas position in a create/update request (ADR 0020 V8).

object
x
number format: double
y
number format: double
project_id
required
string format: uuid
steps
Array<object>

One step in a create/update request body — the v1 agent-only wire shape, kept so existing callers keep working. The V8 builder sends nodes instead.

object
agent_type
required
string
depends_on
Array<string>
key
required
string
on_failure

stop (default) or continue; unknown values fall back to stop.

string | null
prompt
required
string
Examplegenerated
{
"name": "example",
"nodes": [
{
"config": "example",
"depends_on": [
{
"handle": "example",
"key": "example"
}
],
"key": "example",
"kind": "example",
"parent_node_key": "example",
"position": {
"x": 1,
"y": 1
}
}
],
"project_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0",
"steps": [
{
"agent_type": "example",
"depends_on": [
"example"
],
"key": "example",
"on_failure": "example",
"prompt": "example"
}
]
}

Workflow created; body contains the new workflow id

Media typeapplication/json

{ "id": <uuid> } — the create/import response body (the new workflow id); the handlers return this struct directly.

object
id
required
string format: uuid
Examplegenerated
{
"id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0"
}

Structured client error

Media typeapplication/json

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
code
required

Machine-readable, stable error code.

string
Allowed values: not_found unauthorized forbidden bad_request unprocessable precondition_failed conflict method_not_allowed rate_limited quota_exceeded database_error docker_error vault_error internal_error
details
One of:
null
error
required

Human-readable message (the server’s English text; the client may localize by code).

string
Example
{
"code": "not_found"
}

Authentication required

Media typeapplication/json

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
code
required

Machine-readable, stable error code.

string
Allowed values: not_found unauthorized forbidden bad_request unprocessable precondition_failed conflict method_not_allowed rate_limited quota_exceeded database_error docker_error vault_error internal_error
details
One of:
null
error
required

Human-readable message (the server’s English text; the client may localize by code).

string
Example
{
"code": "not_found"
}

Permission denied

Media typeapplication/json

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
code
required

Machine-readable, stable error code.

string
Allowed values: not_found unauthorized forbidden bad_request unprocessable precondition_failed conflict method_not_allowed rate_limited quota_exceeded database_error docker_error vault_error internal_error
details
One of:
null
error
required

Human-readable message (the server’s English text; the client may localize by code).

string
Example
{
"code": "not_found"
}

Structured server error

Media typeapplication/json

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
code
required

Machine-readable, stable error code.

string
Allowed values: not_found unauthorized forbidden bad_request unprocessable precondition_failed conflict method_not_allowed rate_limited quota_exceeded database_error docker_error vault_error internal_error
details
One of:
null
error
required

Human-readable message (the server’s English text; the client may localize by code).

string
Example
{
"code": "not_found"
}