Skip to main content

Workflows API

Flow drafts and published versions (W1).

This page lists 53 endpoints (OpenAPI tag workflow). It is generated from openapi.json; see the REST API overview for authentication, CSRF and error conventions.

MethodPathOperation idNotes
GET/api/ws/{workspace}/workflows/executionslist_executions
GET/api/ws/{workspace}/workflows/executions/{id}get_execution
GET/api/ws/{workspace}/workflows/executions/{id}/filedownload_execution_file
GET/api/ws/{workspace}/workflows/executions/{id}/file/metasexecution_file_metas
GET/api/ws/{workspace}/workflows/executions/{id}/file/previewpreview_execution_file
GET/api/ws/{workspace}/workflows/executions/{id}/graphget_execution_graph
POST/api/ws/{workspace}/workflows/executions/{id}/killkill_executionKill an execution that has not ended.
GET/api/ws/{workspace}/workflows/executions/{id}/logsget_execution_logsAn execution's log lines after a cursor, in id order.
POST/api/ws/{workspace}/workflows/executions/{id}/replayreplay_executionRun a finished execution again.
POST/api/ws/{workspace}/workflows/executions/{id}/resumeresume_executionResume a PAUSED execution by hand.
GET/api/ws/{workspace}/workflows/flowslist_flows
POST/api/ws/{workspace}/workflows/flowscreate_flow
POST/api/ws/{workspace}/workflows/flows/graphgraph_unsaved_flow
POST/api/ws/{workspace}/workflows/flows/validatevalidate_unsaved_flow
GET/api/ws/{workspace}/workflows/flows/{id}get_flow
PUT/api/ws/{workspace}/workflows/flows/{id}update_flowReplace a flow's draft.
DELETE/api/ws/{workspace}/workflows/flows/{id}delete_flow
POST/api/ws/{workspace}/workflows/flows/{id}/executionsstart_flow_execution
GET/api/ws/{workspace}/workflows/flows/{id}/graphget_flow_graph
POST/api/ws/{workspace}/workflows/flows/{id}/publishpublish_flow
GET/api/ws/{workspace}/workflows/flows/{id}/triggerslist_flow_triggers
POST/api/ws/{workspace}/workflows/flows/{id}/triggers/{trigger_id}/backfillcreate_trigger_backfill
DELETE/api/ws/{workspace}/workflows/flows/{id}/triggers/{trigger_id}/backfilldelete_trigger_backfill
PUT/api/ws/{workspace}/workflows/flows/{id}/triggers/{trigger_id}/backfill/pausedset_trigger_backfill_paused
PUT/api/ws/{workspace}/workflows/flows/{id}/triggers/{trigger_id}/disabledset_trigger_disabled
POST/api/ws/{workspace}/workflows/flows/{id}/validatevalidate_flow
GET/api/ws/{workspace}/workflows/flows/{id}/versionslist_flow_versions
GET/api/ws/{workspace}/workflows/flows/{id}/versions/{version}get_flow_version
GET/api/ws/{workspace}/workflows/namespaceslist_namespaces
GET/api/ws/{workspace}/workflows/namespaces/{namespace}get_namespace
GET/api/ws/{workspace}/workflows/namespaces/{namespace}/dependenciesnamespace_dependencies
GET/api/ws/{workspace}/workflows/namespaces/{namespace}/filesdownload_namespace_file
POST/api/ws/{workspace}/workflows/namespaces/{namespace}/filesupload_namespace_file
PUT/api/ws/{workspace}/workflows/namespaces/{namespace}/filesmove_namespace_file
DELETE/api/ws/{workspace}/workflows/namespaces/{namespace}/filesdelete_namespace_file
GET/api/ws/{workspace}/workflows/namespaces/{namespace}/files/directorylist_namespace_directory
POST/api/ws/{workspace}/workflows/namespaces/{namespace}/files/directorycreate_namespace_directory
GET/api/ws/{workspace}/workflows/namespaces/{namespace}/files/exportexport_namespace_files
GET/api/ws/{workspace}/workflows/namespaces/{namespace}/files/revisionsnamespace_file_revisions
GET/api/ws/{workspace}/workflows/namespaces/{namespace}/files/searchsearch_namespace_files
GET/api/ws/{workspace}/workflows/namespaces/{namespace}/files/statsnamespace_file_stats
GET/api/ws/{workspace}/workflows/namespaces/{namespace}/kvlist_kv
DELETE/api/ws/{workspace}/workflows/namespaces/{namespace}/kvdelete_kv_values
GET/api/ws/{workspace}/workflows/namespaces/{namespace}/kv/inheritancelist_inherited_kv
GET/api/ws/{workspace}/workflows/namespaces/{namespace}/kv/{key}get_kv_value
PUT/api/ws/{workspace}/workflows/namespaces/{namespace}/kv/{key}put_kv_value
DELETE/api/ws/{workspace}/workflows/namespaces/{namespace}/kv/{key}delete_kv_value
GET/api/ws/{workspace}/workflows/namespaces/{namespace}/kv/{key}/revisionskv_revisions
GET/api/ws/{workspace}/workflows/schemaget_flow_schema
GET/api/ws/{workspace}/workflows/triggerslist_triggers
POST/api/ws/{workspace}/workflows/triggers/backfill/deletedelete_triggers_backfill
PUT/api/ws/{workspace}/workflows/triggers/backfill/pausedset_triggers_backfill_paused
PUT/api/ws/{workspace}/workflows/triggers/disabledset_triggers_disabled

GET /api/ws/{workspace}/workflows/executions​

Operation id: list_executions. Auth: Session cookie. Forbidden (403): Missing workflow:read permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
flow_idquerystring (uuid)noOnly executions started from this draft. A trashed draft still matches: FlowRepo's delete is soft, so the column keeps pointing at it.
namespacequerystringnoExactly this namespace. Cannot be combined with namespace_prefix (400).
namespace_prefixquerystringnoThis namespace and every namespace beneath it, dot-anchored: a.b matches a.b and a.b.c, never a.bc. A _ or % is a literal character, not a wildcard. Cannot be combined with namespace (400).
flow_keyquerystringnoThe YAML's own id — the only filter that still finds an execution whose flow_id was NULLed by a real DELETE.
statequerystringnoOne or more states, comma-separated (RUNNING,FAILED): a run list shows failures beside what is in flight.
sincequerystring (date-time)noWindow over the execution's created_at, inclusive.
untilquerystring (date-time)noWindow over the execution's created_at, exclusive, so consecutive windows tile without double-counting the row on the boundary.
root_onlyquerybooleannotrue: hide child executions — a loop iteration (loop_index set) and a subflow or flow-trigger child (trigger_execution_id set). A CREATE_NEW_EXECUTION retry is NOT hidden: it carries parent_execution_id without a loop_index, and...
parentquerystring (uuid)noOnly the direct children of this execution: the rows whose parent_execution_id or trigger_execution_id is this id. An id from another workspace answers an empty page, never an error. Cannot be combined with root_only=true (400).
limitqueryinteger (int64)noHow many rows to return. Default 50, maximum 200; a larger value is clamped rather than refused, and the clamped value comes back in the response's own limit.
offsetqueryinteger (int64)noHow many rows to skip. Negative is clamped to zero.

Response 200 (application/json): ExecutionPageDto

FieldTypeRequiredDescription
rowsExecutionListItemDto[]yes
totalinteger (int64)yesEvery execution matching the filter, not just this page's. Counted by a second statement carrying the same predicates, workspace one included.
limitinteger (int64)yesThe page size actually used, after the clamp.
offsetinteger (int64)yesThe offset actually used, after the clamp.
StatusMeaning
200One page of the workspace's executions, newest first, with the total behind it
400The query string does not decode — a malformed flow_id/parent/since/until, a root_only that is not true/false, a non-numeric limit/offset, or a repeated key (?state=A&state=B answers duplicate field state; several...
401Not authenticated
403Missing workflow:read permission, or the workflows module is disabled for this workspace
404No such workspace
500Internal error

GET /api/ws/{workspace}/workflows/executions/{id}​

Operation id: get_execution. Auth: Session cookie. Forbidden (403): Missing workflow:read permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesExecution id
workspacepathstringyes

Response 200 (application/json): ExecutionDto

FieldTypeRequiredDescription
idstring (uuid)yes
flow_idstring (uuid), nullablenoThe draft this execution came from, and NULL only if something outside this crate issued a real DELETE — trashing a flow does not clear it, because FlowRepo's delete is soft and nothing in egret-workflow/src issues a `DELETE...
namespacestringyes
flow_keystringyesThe YAML's own id; flow_id is taken by the draft's uuid above.
statestringyesKestra's wire spelling — RUNNING, SUCCESS, FAILED, …
historystring[]yesThe state timeline, as stored: an array of state NAMES, e.g. ["CREATED","RUNNING","SUCCESS"]. It carries no timestamps — see [TaskRunDto::history], which is written by the same function.
inputsobjectyes
seqinteger (int64)yes
execution_triggerobject, nullablenoThe trigger record, NULL for an API start.
trigger_execution_idstring (uuid), nullableno
trigger_run_ixinteger (int32), nullableno
parent_execution_idstring (uuid), nullableno
parent_run_ixinteger (int32), nullableno
loop_indexinteger (int32), nullableno
loop_valuestring, nullableno
attempt_numberinteger (int32)yes
origin_offset_msinteger (int64)yes
replayed_from_execution_idstring (uuid), nullablenoThe execution this one is a manual replay of (POST …/replay), NULL for every other start. A CREATE_NEW_EXECUTION retry is NOT linked here; it carries parent_execution_id instead.
started_atstring (date-time), nullablenoThe first time the execution entered RUNNING. NULL before it runs, for one that never ran (an SLA that cancelled it at creation), and for an execution recorded before these times existed — a UI shows that last case as estimated, never...
ended_atstring (date-time), nullablenoWhen the execution entered a terminal state; NULL while it has not (a paused execution has none), and for an execution recorded before these times existed. Written once: later writes to a finished execution do not move it.
created_atstring (date-time)yes
updated_atstring (date-time)yes
labelsLabelDto[], nullablenoThe execution's own label column; null for none. At start it holds the labels beyond the flow's own labels: (a backfill's, a replay's copy); once a Labels task has run it holds the full merged list, the flow's labels included. The...
backfill_idstring (uuid), nullablenoThe backfill that fired this execution (W7f), null otherwise.
sourcestringyesThe flow source this execution runs, frozen at start. The plan is pure over it, which is why a detail page can draw the topology from this string alone.
runsTaskRunDto[]yesEvery task run, in run_ix order — the executor's creation order.
can_managebooleanyesWhether the caller may resume and replay this execution: they hold workflow:manage in this workspace. A detail page hides both actions when this is false; the routes still check for themselves.
effective_labelsLabelDto[]yesWhat the run sees as labels: the flow's, then labels, the later key winning. Empty when the frozen source does not parse.
StatusMeaning
200The execution, its frozen source, and every task run in run_ix order
400\{id\} is not a UUID. Decided by axum's Path extractor before any handler runs — and AFTER Auth, so an anonymous caller still gets 401 and this leaks no existence
401Not authenticated
403Missing workflow:read permission, or the workflows module is disabled for this workspace
404No such execution in this workspace. An execution belonging to another workspace answers exactly this, indistinguishably from one that never existed: a 403 would confirm the id is real.
500Internal error

GET /api/ws/{workspace}/workflows/executions/{id}/file​

Operation id: download_execution_file. Auth: Session cookie. Forbidden (403): Missing workflow:read permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesExecution id: any id of the file's loop family (its loop root or any iteration under it)
pathquerystringyesThe file's kestra:///… URI, as the execution's outputs or inputs name it.
workspacepathstringyes

Response 200 (application/octet-stream): array of integer (int32)

StatusMeaning
200The file's bytes, streamed. Content-Type: application/octet-stream, Content-Disposition: attachment with the file's name (sanitised, and percent-encoded in filename*), X-Content-Type-Options: nosniff.
401Not authenticated
403Missing workflow:read permission, or the workflows module is disabled for this workspace
404No such execution in this workspace, or path is not a file of its loop family: malformed, another execution's (a trigger's or a replay source's too -- ask that execution by its own id), never stored, or its contents are gone. **One answer...
500Internal error
503Internal storage is unavailable or not configured; the request can be retried.

GET /api/ws/{workspace}/workflows/executions/{id}/file/metas​

Operation id: execution_file_metas. Auth: Session cookie. Forbidden (403): Missing workflow:read permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesExecution id: any id of the file's loop family
pathquerystringyesThe file's kestra:///… URI, as the execution's outputs or inputs name it.
workspacepathstringyes

Response 200 (application/json): FileMetasDto

FieldTypeRequiredDescription
sizeinteger (int64)yesThe file's size in bytes, as indexed when it was stored.
StatusMeaning
200The file's size, from the index (the store is not asked).
401Not authenticated
403Missing workflow:read permission, or the workflows module is disabled for this workspace
404No such execution in this workspace, or path is not a file of its loop family (one answer, never a redirect).
500Internal error

GET /api/ws/{workspace}/workflows/executions/{id}/file/preview​

Operation id: preview_execution_file. Auth: Session cookie. Forbidden (403): Missing workflow:read permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesExecution id: any id of the file's loop family
pathquerystringyesThe file's kestra:///… URI, as the execution's outputs or inputs name it.
maxRowsqueryinteger (int32)noAt most this many rows (default 100; anything above 5000 is 5000, below 1 is 1).
workspacepathstringyes

Response 200 (application/json): FilePreviewDto

FieldTypeRequiredDescription
previewablebooleanyesfalse (with no rows) for a file that is neither Ion nor UTF-8 text, Ion that does not parse, or Ion nested deeper than 100 levels.
rowsobject[]yes.ion: one JSON value per top-level Ion value (a struct's null fields omitted, a timestamp as its Ion text, a decimal as a number). Anything else: one string per line.
truncatedbooleanyesMore rows follow than maxRows, or the preview's byte budget (workflow.storage.max_read_bytes) ended the read.
StatusMeaning
200Up to maxRows rows (default 100, at most 5000), read from the start of the file and never more than workflow.storage.max_read_bytes of it. A .ion file (text or binary Ion) gives one JSON value per top-level value; any other file whose...
401Not authenticated
403Missing workflow:read permission, or the workflows module is disabled for this workspace
404No such execution in this workspace, or path is not a file of its loop family, or its contents are gone (one answer, never a redirect).
500Internal error
503Internal storage is unavailable or not configured; the request can be retried.

GET /api/ws/{workspace}/workflows/executions/{id}/graph​

Operation id: get_execution_graph. Auth: Session cookie. Forbidden (403): Missing workflow:read permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesExecution id
subflowsquerystring[]noUids of Subflow nodes to expand in place, repeated (subflows=a&subflows=b). A Subflow whose run started a child execution expands from that execution's frozen source, with its states; otherwise from the child flow's current draft,...
workspacepathstringyes

Response 200 (application/json): ExecutionGraph

FieldTypeRequiredDescription
graphFlowGraphyes
statesobjectyesNode uid -> its state. A node with no run has no entry.
StatusMeaning
200The graph of the execution's frozen source, and the state of every node that has a run. A task with no run has no entry; a task in a Loop body is folded over every iteration by Kestra's priority, with iterations and no run_id
400\{id\} is not a UUID
401Not authenticated
403Missing workflow:read permission, or the workflows module is disabled for this workspace
404No such execution in this workspace; one of another workspace answers exactly this
422The graph, counted after expansion, has more than 5,000 nodes; the message names the count
500Internal error

POST /api/ws/{workspace}/workflows/executions/{id}/kill​

Operation id: kill_execution. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing workflow:manage permission, or the workflows module is disabled for this workspace. workflow:read is not enough..

Kill an execution that has not ended.

Tasks retrying, paused or not yet started end KILLED at once; a running task is stopped by a worker -- the one running it, or the next one to claim it -- and the execution is KILLING until it has. With cascade (the default) its Loop iterations and Subflow child executions are killed the same way.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesExecution id
cascadequerybooleannoAlso kill the execution's child executions -- its Loop iterations and its Subflow children, recursively (default true). A replay of it, or an execution a Flow trigger fired on it, is not a child. With false, the children run on, and...
workspacepathstringyes

Response 202 (application/json): ExecutionDto

FieldTypeRequiredDescription
idstring (uuid)yes
flow_idstring (uuid), nullablenoThe draft this execution came from, and NULL only if something outside this crate issued a real DELETE — trashing a flow does not clear it, because FlowRepo's delete is soft and nothing in egret-workflow/src issues a `DELETE...
namespacestringyes
flow_keystringyesThe YAML's own id; flow_id is taken by the draft's uuid above.
statestringyesKestra's wire spelling — RUNNING, SUCCESS, FAILED, …
historystring[]yesThe state timeline, as stored: an array of state NAMES, e.g. ["CREATED","RUNNING","SUCCESS"]. It carries no timestamps — see [TaskRunDto::history], which is written by the same function.
inputsobjectyes
seqinteger (int64)yes
execution_triggerobject, nullablenoThe trigger record, NULL for an API start.
trigger_execution_idstring (uuid), nullableno
trigger_run_ixinteger (int32), nullableno
parent_execution_idstring (uuid), nullableno
parent_run_ixinteger (int32), nullableno
loop_indexinteger (int32), nullableno
loop_valuestring, nullableno
attempt_numberinteger (int32)yes
origin_offset_msinteger (int64)yes
replayed_from_execution_idstring (uuid), nullablenoThe execution this one is a manual replay of (POST …/replay), NULL for every other start. A CREATE_NEW_EXECUTION retry is NOT linked here; it carries parent_execution_id instead.
started_atstring (date-time), nullablenoThe first time the execution entered RUNNING. NULL before it runs, for one that never ran (an SLA that cancelled it at creation), and for an execution recorded before these times existed — a UI shows that last case as estimated, never...
ended_atstring (date-time), nullablenoWhen the execution entered a terminal state; NULL while it has not (a paused execution has none), and for an execution recorded before these times existed. Written once: later writes to a finished execution do not move it.
created_atstring (date-time)yes
updated_atstring (date-time)yes
labelsLabelDto[], nullablenoThe execution's own label column; null for none. At start it holds the labels beyond the flow's own labels: (a backfill's, a replay's copy); once a Labels task has run it holds the full merged list, the flow's labels included. The...
backfill_idstring (uuid), nullablenoThe backfill that fired this execution (W7f), null otherwise.
sourcestringyesThe flow source this execution runs, frozen at start. The plan is pure over it, which is why a detail page can draw the topology from this string alone.
runsTaskRunDto[]yesEvery task run, in run_ix order — the executor's creation order.
can_managebooleanyesWhether the caller may resume and replay this execution: they hold workflow:manage in this workspace. A detail page hides both actions when this is false; the routes still check for themselves.
effective_labelsLabelDto[]yesWhat the run sees as labels: the flow's, then labels, the later key winning. Empty when the frozen source does not parse.
StatusMeaning
202The kill is recorded. The body is the execution afterwards: KILLING while a running task still has to be stopped by a worker (it then becomes KILLED on its own), or KILLED if nothing was running. Every run that was retrying, paused or...
400cascade is not true or false
401Not authenticated
403Missing workflow:manage permission, or the workflows module is disabled for this workspace. workflow:read is not enough.
404No such execution in this workspace, indistinguishably from one that never existed
409The execution has already ended (code execution_terminated). Nothing is written.
500Internal error

GET /api/ws/{workspace}/workflows/executions/{id}/logs​

Operation id: get_execution_logs. Auth: Session cookie. Forbidden (403): Missing workflow:read permission, or the workflows module is disabled for this workspace.

An execution's log lines after a cursor, in id order.

Lines appear about 2 seconds after they are written (the settle lag, [crate::logs::SETTLE_LAG]). A page stops before the first line whose inserted_at is less than 2 s old, and serves nothing above it. The reason is out-of-order commits: bigserial ids are allocated at insert and committed later, so with two writers (two egret replicas) id 100 can commit after id 101. A client that had read 101 and moved its cursor past it would never see 100. Holding lines back until the lowest unserved one has settled lets the lower id commit first, provided a log write lasts less than half the lag (a log batch is one short INSERT).

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesExecution id
afterqueryinteger (int64)noThe cursor: only lines with an id greater than this. Omit it for the first call, then pass the previous response's next_after.
limitqueryinteger (int64)noHow many lines to return, 1..=2000 (default 500). Outside that range is a 400, not a clamp.
task_idquerystringnoOnly lines of this task (the YAML's task id).
task_run_idquerystring (uuid)noOnly lines of this task run.
min_levelqueryLogLevelnoOnly lines at this level or above. The five names, upper case, compared case-sensitively; anything else is a 400.
workspacepathstringyes

Response 200 (application/json): LogPageDto

FieldTypeRequiredDescription
itemsLogLineDto[]yesIn id order, at most limit of them.
next_afterinteger (int64), nullablenoThe last returned id -- the next call's after -- or null when nothing was returned (keep the after you sent).
execution_statestringyesThe execution's state (Kestra's wire spelling, RUNNING, SUCCESS, ...), read on this call. For display: do not stop polling on a terminal state alone -- see complete.
completebooleanyesThe execution is terminal AND became so more than the 2 s settle lag ago. Stop polling when complete is true and items is empty: then every stored line has been served. A terminal execution_state alone is not enough -- the run's...
StatusMeaning
200Up to limit settled lines after after, in id order, with the next cursor, the execution's current state, and complete. Lines appear about 2 s after they are written (the settle lag guards against out-of-order commits). Stop polling on...
400limit outside 1..=2000, a min_level that is not one of TRACE/DEBUG/INFO/WARN/ERROR, or a malformed \{id\}/after/task_run_id
401Not authenticated
403Missing workflow:read permission, or the workflows module is disabled for this workspace
404No such execution in this workspace. An execution belonging to another workspace answers exactly this, indistinguishably from one that never existed.
500Internal error

POST /api/ws/{workspace}/workflows/executions/{id}/replay​

Operation id: replay_execution. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing workflow:manage permission, or the workflows module is disabled for this workspace. workflow:read is not enough..

Run a finished execution again.

It is a start, deliberately, and from the FROZEN source

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesExecution id to replay
workspacepathstringyes

Response 201 (application/json): ExecutionDto

FieldTypeRequiredDescription
idstring (uuid)yes
flow_idstring (uuid), nullablenoThe draft this execution came from, and NULL only if something outside this crate issued a real DELETE — trashing a flow does not clear it, because FlowRepo's delete is soft and nothing in egret-workflow/src issues a `DELETE...
namespacestringyes
flow_keystringyesThe YAML's own id; flow_id is taken by the draft's uuid above.
statestringyesKestra's wire spelling — RUNNING, SUCCESS, FAILED, …
historystring[]yesThe state timeline, as stored: an array of state NAMES, e.g. ["CREATED","RUNNING","SUCCESS"]. It carries no timestamps — see [TaskRunDto::history], which is written by the same function.
inputsobjectyes
seqinteger (int64)yes
execution_triggerobject, nullablenoThe trigger record, NULL for an API start.
trigger_execution_idstring (uuid), nullableno
trigger_run_ixinteger (int32), nullableno
parent_execution_idstring (uuid), nullableno
parent_run_ixinteger (int32), nullableno
loop_indexinteger (int32), nullableno
loop_valuestring, nullableno
attempt_numberinteger (int32)yes
origin_offset_msinteger (int64)yes
replayed_from_execution_idstring (uuid), nullablenoThe execution this one is a manual replay of (POST …/replay), NULL for every other start. A CREATE_NEW_EXECUTION retry is NOT linked here; it carries parent_execution_id instead.
started_atstring (date-time), nullablenoThe first time the execution entered RUNNING. NULL before it runs, for one that never ran (an SLA that cancelled it at creation), and for an execution recorded before these times existed — a UI shows that last case as estimated, never...
ended_atstring (date-time), nullablenoWhen the execution entered a terminal state; NULL while it has not (a paused execution has none), and for an execution recorded before these times existed. Written once: later writes to a finished execution do not move it.
created_atstring (date-time)yes
updated_atstring (date-time)yes
labelsLabelDto[], nullablenoThe execution's own label column; null for none. At start it holds the labels beyond the flow's own labels: (a backfill's, a replay's copy); once a Labels task has run it holds the full merged list, the flow's labels included. The...
backfill_idstring (uuid), nullablenoThe backfill that fired this execution (W7f), null otherwise.
sourcestringyesThe flow source this execution runs, frozen at start. The plan is pure over it, which is why a detail page can draw the topology from this string alone.
runsTaskRunDto[]yesEvery task run, in run_ix order — the executor's creation order.
can_managebooleanyesWhether the caller may resume and replay this execution: they hold workflow:manage in this workspace. A detail page hides both actions when this is false; the routes still check for themselves.
effective_labelsLabelDto[]yesWhat the run sees as labels: the flow's, then labels, the later key winning. Empty when the frozen source does not parse.
StatusMeaning
201A NEW execution, started from the replayed one's frozen source and inputs. The body is the new execution, not the old one — read its id.
400The execution is a loop iteration (replay its loop root instead); or the flow's current draft does not parse, so whether it is disabled cannot be decided; or the replayed execution's frozen source no longer plans, or uses a task...
401Not authenticated
403Missing workflow:manage permission, or the workflows module is disabled for this workspace. workflow:read is not enough.
404No such execution in this workspace, indistinguishably from one that never existed — or its flow is in the trash, or no longer exists at all. A replay is a run of the flow and answers to the flow's current state.
409The execution has not finished, or its flow is disabled (by the state column or by its own YAML's disabled: true). A replay of something still running would put two copies of one flow in flight at once.
500Internal error

POST /api/ws/{workspace}/workflows/executions/{id}/resume​

Operation id: resume_execution. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing workflow:manage permission, or the workflows module is disabled for this workspace. workflow:read is not enough..

Resume a PAUSED execution by hand.

W7b Task 3 fix round 1, the user's ruling of 2026-10-11, after review found the old route released nothing a human needs: it only re-settled, which ends a pause whose deadline had passed -- what the waker does anyway. It now calls worker::resume_by_hand, Kestra's ExecutionService.resume: every paused Pause run ends SUCCESS now, through the natural end's own path, and the execution settles on.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesExecution id
workspacepathstringyes

Response 200 (application/json): ExecutionDto

FieldTypeRequiredDescription
idstring (uuid)yes
flow_idstring (uuid), nullablenoThe draft this execution came from, and NULL only if something outside this crate issued a real DELETE — trashing a flow does not clear it, because FlowRepo's delete is soft and nothing in egret-workflow/src issues a `DELETE...
namespacestringyes
flow_keystringyesThe YAML's own id; flow_id is taken by the draft's uuid above.
statestringyesKestra's wire spelling — RUNNING, SUCCESS, FAILED, …
historystring[]yesThe state timeline, as stored: an array of state NAMES, e.g. ["CREATED","RUNNING","SUCCESS"]. It carries no timestamps — see [TaskRunDto::history], which is written by the same function.
inputsobjectyes
seqinteger (int64)yes
execution_triggerobject, nullablenoThe trigger record, NULL for an API start.
trigger_execution_idstring (uuid), nullableno
trigger_run_ixinteger (int32), nullableno
parent_execution_idstring (uuid), nullableno
parent_run_ixinteger (int32), nullableno
loop_indexinteger (int32), nullableno
loop_valuestring, nullableno
attempt_numberinteger (int32)yes
origin_offset_msinteger (int64)yes
replayed_from_execution_idstring (uuid), nullablenoThe execution this one is a manual replay of (POST …/replay), NULL for every other start. A CREATE_NEW_EXECUTION retry is NOT linked here; it carries parent_execution_id instead.
started_atstring (date-time), nullablenoThe first time the execution entered RUNNING. NULL before it runs, for one that never ran (an SLA that cancelled it at creation), and for an execution recorded before these times existed — a UI shows that last case as estimated, never...
ended_atstring (date-time), nullablenoWhen the execution entered a terminal state; NULL while it has not (a paused execution has none), and for an execution recorded before these times existed. Written once: later writes to a finished execution do not move it.
created_atstring (date-time)yes
updated_atstring (date-time)yes
labelsLabelDto[], nullablenoThe execution's own label column; null for none. At start it holds the labels beyond the flow's own labels: (a backfill's, a replay's copy); once a Labels task has run it holds the full merged list, the flow's labels included. The...
backfill_idstring (uuid), nullablenoThe backfill that fired this execution (W7f), null otherwise.
sourcestringyesThe flow source this execution runs, frozen at start. The plan is pure over it, which is why a detail page can draw the topology from this string alone.
runsTaskRunDto[]yesEvery task run, in run_ix order — the executor's creation order.
can_managebooleanyesWhether the caller may resume and replay this execution: they hold workflow:manage in this workspace. A detail page hides both actions when this is false; the routes still check for themselves.
effective_labelsLabelDto[]yesWhat the run sees as labels: the flow's, then labels, the later key winning. Empty when the frozen source does not parse.
StatusMeaning
200Every paused Pause run was released at once and ends SUCCESS, whatever its pauseDuration: or timeout: (Kestra: a pause resumed by hand always succeeds); the execution then runs on. The body is its detail afterwards.
401Not authenticated
403Missing workflow:manage permission, or the workflows module is disabled for this workspace. workflow:read is not enough.
404No such execution in this workspace, indistinguishably from one that never existed
409The execution is not PAUSED (or its pause ended before the resume took the execution's lock), or it is PAUSED only because a LoopUntil waits for its next iteration and no Pause task is waiting. A resume that changes nothing must not...
500Internal error

GET /api/ws/{workspace}/workflows/flows​

Operation id: list_flows. Auth: Session cookie. Forbidden (403): Missing workflow:read permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
folder_idquerystring (uuid)noList only flows in this folder
namespacequerystringnoList only flows in this namespace
statequerystringnoList only flows in this state (draft, live, disabled)

Response 200 (application/json): array of FlowListItemDto

FieldTypeRequiredDescription
idstring (uuid)yes
folder_idstring (uuid), nullableno
namespacestringyes
flow_idstringyes
statestringyes
live_version_idstring (uuid), nullableno
created_bystring (uuid), nullableno
created_by_namestring, nullablenoThe creator's display name: the profile name, else the email. Null when created_by is null or the user no longer exists (W7a spec §7.4).
latest_versioninteger (int32), nullablenoThe flow's highest version number; null when it has none. Versions are snapshots to compare and restore: executions run the saved draft (W7a spec §4, §5.3).
created_atstring (date-time)yes
updated_atstring (date-time)yes
StatusMeaning
200Flow drafts in the workspace, newest first
401Not authenticated
403Missing workflow:read permission, or the workflows module is disabled for this workspace
500Internal error

POST /api/ws/{workspace}/workflows/flows​

Operation id: create_flow. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing workflow:manage permission, or the workflows module is disabled for this workspace, or the flow calls secret() and the caller lacks workflow:use_secrets.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug

Request body (application/json): CreateFlowRequest

FieldTypeRequiredDescription
sourcestringyesThe flow's YAML, byte for byte. namespace/flow_id are DERIVED from it (parsed, never accepted as separate body fields) so the stored identity can never disagree with what the YAML itself declares.
folder_idstring (uuid), nullableno

Response 201 (application/json): FlowDto

FieldTypeRequiredDescription
idstring (uuid)yes
folder_idstring (uuid), nullableno
namespacestringyes
flow_idstringyes
sourcestringyes
planobjectyes
statestringyes
live_version_idstring (uuid), nullableno
created_bystring (uuid), nullableno
created_by_namestring, nullablenoThe creator's display name: the profile name, else the email. Null when created_by is null or the user no longer exists (W7a spec §7.4).
latest_versioninteger (int32), nullablenoThe flow's highest version number; null when it has none. Versions are snapshots to compare and restore: executions run the saved draft (W7a spec §4, §5.3).
created_atstring (date-time)yes
updated_atstring (date-time)yes
validationValidationReportDtoyesA flow's validation report, over the wire. Errors block publish; warnings do not — see [ValidationReport]'s own doc comment.
can_managebooleanyesWhether the caller may save, publish, run and delete this flow: they hold workflow:manage in this workspace. An editor opens read-only when this is false; every mutating route still checks for itself.
StatusMeaning
201Draft created, with its validation report
400The YAML does not parse
401Not authenticated
403Missing workflow:manage permission, or the workflows module is disabled for this workspace, or the flow calls secret() and the caller lacks workflow:use_secrets
409A flow with this namespace and id already exists in the workspace
500Internal error

POST /api/ws/{workspace}/workflows/flows/graph​

Operation id: graph_unsaved_flow. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing workflow:manage permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
subflowsquerystring[]noUids of Subflow nodes to expand in place, repeated (subflows=a&subflows=b). A uid inside an expansion is \{subflow_uid\}/\{child_uid\}; a uid that names no Subflow node is ignored

Request body (application/json): FlowGraphRequest

FieldTypeRequiredDescription
sourcestringyes

Response 200 (application/json): FlowGraph

FieldTypeRequiredDescription
nodesNode[]yes
edgesEdge[]yes
clustersCluster[]yes
StatusMeaning
200The topology of the unsaved YAML. A flow that parses but fails validation still gets its graph; its refused tasks carry refusal. Nothing is written
400The YAML does not parse; the message carries the line and column
401Not authenticated
403Missing workflow:manage permission, or the workflows module is disabled for this workspace
422The graph, counted after expansion, has more than 5,000 nodes; the message names the count
500Internal error

POST /api/ws/{workspace}/workflows/flows/validate​

Operation id: validate_unsaved_flow. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing workflow:manage permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug

Request body (application/json): ValidateFlowRequest

FieldTypeRequiredDescription
sourcestringyes

Response 200 (application/json): ValidationReportDto

FieldTypeRequiredDescription
errorsFindingDto[]yes
warningsFindingDto[]yes
StatusMeaning
200The validation report of a source that belongs to no saved flow yet (the create page). The same report POST /flows/\{id\}/validate gives for the same source; nothing is written
400The YAML does not parse; the message carries the line and column
401Not authenticated
403Missing workflow:manage permission, or the workflows module is disabled for this workspace
500Internal error

GET /api/ws/{workspace}/workflows/flows/{id}​

Operation id: get_flow. Auth: Session cookie. Forbidden (403): Missing workflow:read permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesFlow id
workspacepathstringyes

Response 200 (application/json): FlowDto

FieldTypeRequiredDescription
idstring (uuid)yes
folder_idstring (uuid), nullableno
namespacestringyes
flow_idstringyes
sourcestringyes
planobjectyes
statestringyes
live_version_idstring (uuid), nullableno
created_bystring (uuid), nullableno
created_by_namestring, nullablenoThe creator's display name: the profile name, else the email. Null when created_by is null or the user no longer exists (W7a spec §7.4).
latest_versioninteger (int32), nullablenoThe flow's highest version number; null when it has none. Versions are snapshots to compare and restore: executions run the saved draft (W7a spec §4, §5.3).
created_atstring (date-time)yes
updated_atstring (date-time)yes
validationValidationReportDtoyesA flow's validation report, over the wire. Errors block publish; warnings do not — see [ValidationReport]'s own doc comment.
can_managebooleanyesWhether the caller may save, publish, run and delete this flow: they hold workflow:manage in this workspace. An editor opens read-only when this is false; every mutating route still checks for itself.
StatusMeaning
200The draft, with its validation report
401Not authenticated
403Missing workflow:read permission, or the workflows module is disabled for this workspace
404No such flow in this workspace
500Internal error

PUT /api/ws/{workspace}/workflows/flows/{id}​

Operation id: update_flow. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing workflow:manage permission, or the workflows module is disabled for this workspace, or the flow calls secret() and the caller lacks workflow:use_secrets.

Replace a flow's draft.

With if_updated_at, the save happens only if the draft is still the one the editor opened; otherwise it is refused with 409 and nothing is written. Saving and publishing both move updated_at, so after a publish the editor reads the draft again before saving.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesFlow id
workspacepathstringyes

Request body (application/json): UpdateFlowRequest

FieldTypeRequiredDescription
sourcestringyes
folder_idstring (uuid), nullableno
if_updated_atstring (date-time), nullablenoThe draft's updated_at as the editor last read it (RFC 3339, the exact string FlowDto.updated_at carried -- microseconds included). When present and no longer the row's, the save is refused with 409 and nothing is written; absent, the...

Response 200 (application/json): FlowDto

FieldTypeRequiredDescription
idstring (uuid)yes
folder_idstring (uuid), nullableno
namespacestringyes
flow_idstringyes
sourcestringyes
planobjectyes
statestringyes
live_version_idstring (uuid), nullableno
created_bystring (uuid), nullableno
created_by_namestring, nullablenoThe creator's display name: the profile name, else the email. Null when created_by is null or the user no longer exists (W7a spec §7.4).
latest_versioninteger (int32), nullablenoThe flow's highest version number; null when it has none. Versions are snapshots to compare and restore: executions run the saved draft (W7a spec §4, §5.3).
created_atstring (date-time)yes
updated_atstring (date-time)yes
validationValidationReportDtoyesA flow's validation report, over the wire. Errors block publish; warnings do not — see [ValidationReport]'s own doc comment.
can_managebooleanyesWhether the caller may save, publish, run and delete this flow: they hold workflow:manage in this workspace. An editor opens read-only when this is false; every mutating route still checks for itself.
StatusMeaning
200Draft updated, with its validation report
400The YAML does not parse
401Not authenticated
403Missing workflow:manage permission, or the workflows module is disabled for this workspace, or the flow calls secret() and the caller lacks workflow:use_secrets
404No such flow in this workspace
409Another flow already claims this namespace and id in the workspace, or if_updated_at was sent and the draft was changed since (code is draft_changed; the other conflict carries no code); nothing was written
500Internal error

DELETE /api/ws/{workspace}/workflows/flows/{id}​

Operation id: delete_flow. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing workflow:manage permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesFlow id
workspacepathstringyes

Response 200 (application/json): Ack

FieldTypeRequiredDescription
okbooleanyes
StatusMeaning
200Draft soft-deleted
401Not authenticated
403Missing workflow:manage permission, or the workflows module is disabled for this workspace
404No such flow in this workspace
500Internal error

POST /api/ws/{workspace}/workflows/flows/{id}/executions​

Operation id: start_flow_execution. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing workflow:manage permission, or the workflows module is disabled for this workspace. workflow:read is not enough — starting an execution is a write..

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesFlow id
workspacepathstringyes

Request body (application/json): StartExecutionRequest

FieldTypeRequiredDescription
inputsobjectnoThe flow's inputs:, as a JSON object.

Response 201 (application/json): ExecutionDto

FieldTypeRequiredDescription
idstring (uuid)yes
flow_idstring (uuid), nullablenoThe draft this execution came from, and NULL only if something outside this crate issued a real DELETE — trashing a flow does not clear it, because FlowRepo's delete is soft and nothing in egret-workflow/src issues a `DELETE...
namespacestringyes
flow_keystringyesThe YAML's own id; flow_id is taken by the draft's uuid above.
statestringyesKestra's wire spelling — RUNNING, SUCCESS, FAILED, …
historystring[]yesThe state timeline, as stored: an array of state NAMES, e.g. ["CREATED","RUNNING","SUCCESS"]. It carries no timestamps — see [TaskRunDto::history], which is written by the same function.
inputsobjectyes
seqinteger (int64)yes
execution_triggerobject, nullablenoThe trigger record, NULL for an API start.
trigger_execution_idstring (uuid), nullableno
trigger_run_ixinteger (int32), nullableno
parent_execution_idstring (uuid), nullableno
parent_run_ixinteger (int32), nullableno
loop_indexinteger (int32), nullableno
loop_valuestring, nullableno
attempt_numberinteger (int32)yes
origin_offset_msinteger (int64)yes
replayed_from_execution_idstring (uuid), nullablenoThe execution this one is a manual replay of (POST …/replay), NULL for every other start. A CREATE_NEW_EXECUTION retry is NOT linked here; it carries parent_execution_id instead.
started_atstring (date-time), nullablenoThe first time the execution entered RUNNING. NULL before it runs, for one that never ran (an SLA that cancelled it at creation), and for an execution recorded before these times existed — a UI shows that last case as estimated, never...
ended_atstring (date-time), nullablenoWhen the execution entered a terminal state; NULL while it has not (a paused execution has none), and for an execution recorded before these times existed. Written once: later writes to a finished execution do not move it.
created_atstring (date-time)yes
updated_atstring (date-time)yes
labelsLabelDto[], nullablenoThe execution's own label column; null for none. At start it holds the labels beyond the flow's own labels: (a backfill's, a replay's copy); once a Labels task has run it holds the full merged list, the flow's labels included. The...
backfill_idstring (uuid), nullablenoThe backfill that fired this execution (W7f), null otherwise.
sourcestringyesThe flow source this execution runs, frozen at start. The plan is pure over it, which is why a detail page can draw the topology from this string alone.
runsTaskRunDto[]yesEvery task run, in run_ix order — the executor's creation order.
can_managebooleanyesWhether the caller may resume and replay this execution: they hold workflow:manage in this workspace. A detail page hides both actions when this is false; the routes still check for themselves.
effective_labelsLabelDto[]yesWhat the run sees as labels: the flow's, then labels, the later key winning. Empty when the frozen source does not parse.
StatusMeaning
201The execution was created and driven as far as it goes without a worker; the body is its detail, read back after the start committed. Its uploaded files and its row were committed in one transaction.
400inputs is not a JSON object; the flow's stored source does not parse or plan, or uses a task type this deployment does not serve; a FILE input's value is not a readable kestra:// URI or its extension is not allowed; a multipart part...
401Not authenticated
403Missing workflow:manage permission, or the workflows module is disabled for this workspace. workflow:read is not enough — starting an execution is a write.
404No such flow in this workspace, or it is in the trash. A flow belonging to another workspace answers exactly this, indistinguishably from one that never existed.
409The flow is disabled — by its state column or by its own YAML's disabled: true
413An uploaded file is over workflow.storage.max_file_bytes (the message names the input and the cap), a text part is over 1 MiB, or the JSON body is over 2 MiB. Nothing is created.
415A Content-Type that is neither application/json nor multipart/form-data. A request with no Content-Type is read as JSON (an empty body is \{\}).
500Internal error
503Internal storage failed while an uploaded file was being stored. Nothing is created; the request can be retried.

GET /api/ws/{workspace}/workflows/flows/{id}/graph​

Operation id: get_flow_graph. Auth: Session cookie. Forbidden (403): Missing workflow:read permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesFlow id
versionqueryinteger (int32)noDraw this published version's frozen source instead of the draft
subflowsquerystring[]noUids of Subflow nodes to expand in place, repeated (subflows=a&subflows=b). A uid inside an expansion is \{subflow_uid\}/\{child_uid\}; a uid that names no Subflow node is ignored
workspacepathstringyes

Response 200 (application/json): FlowGraph

FieldTypeRequiredDescription
nodesNode[]yes
edgesEdge[]yes
clustersCluster[]yes
StatusMeaning
200The topology of the draft, or of the version
400version is not an integer
401Not authenticated
403Missing workflow:read permission, or the workflows module is disabled for this workspace
404No such flow, or no such version of it, in this workspace
422The graph, counted after expansion, has more than 5,000 nodes; the message names the count
500Internal error

POST /api/ws/{workspace}/workflows/flows/{id}/publish​

Operation id: publish_flow. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing workflow:manage permission, or the workflows module is disabled for this workspace, or the flow calls secret() and the caller lacks workflow:use_secrets.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesFlow id
workspacepathstringyes

Request body (application/json): PublishFlowRequest

FieldTypeRequiredDescription
notestringno

Response 200 (application/json): FlowVersionDto

FieldTypeRequiredDescription
idstring (uuid)yes
flow_idstring (uuid)yes
versioninteger (int32)yes
snapshotobjectyes
notestringyes
created_bystring (uuid), nullableno
created_by_namestring, nullablenoThe publisher's display name: the profile name, else the email. Null when created_by is null or the user no longer exists (W7a spec §7.4).
created_atstring (date-time)yes
StatusMeaning
200A new immutable version was frozen and is now live
400The draft does not parse or validate, a task names an unknown type or a type this deployment does not serve (task_type_not_served), or a script task is refused by the container gate (workflow_containers off, no or empty allowed-images for...
401Not authenticated
403Missing workflow:manage permission, or the workflows module is disabled for this workspace, or the flow calls secret() and the caller lacks workflow:use_secrets
404No such flow in this workspace, or a task references an object that does not exist or belongs to another workspace
500Internal error

GET /api/ws/{workspace}/workflows/flows/{id}/triggers​

Operation id: list_flow_triggers. Auth: Session cookie. Forbidden (403): Missing workflow:read permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesFlow id
workspacepathstringyes

Response 200 (application/json): FlowTriggersDto

FieldTypeRequiredDescription
flow_disabledbooleanyesThe flow's YAML says disabled: true, or its state is disabled.
flow_deletedbooleanyesThe flow is in the trash: every trigger is effective-disabled.
scheduler_enabledbooleanyesThis deployment runs the schedule loop.
worker_enabledbooleanyesThis deployment runs the worker (and the Flow-trigger processor).
webhooks_enabledbooleanyesThis deployment serves webhooks.
triggersTriggerEntryDto[]yes
StatusMeaning
200Every trigger the flow's saved draft declares, in declaration order, with its runtime switch, its schedule or listener state, its webhook path and its last execution. A trashed flow answers too, with flow_deleted: true.
400The flow's saved source does not parse, so its triggers are unknown
401Not authenticated
403Missing workflow:read permission, or the workflows module is disabled for this workspace
404No such flow in this workspace
500Internal error

POST /api/ws/{workspace}/workflows/flows/{id}/triggers/{trigger_id}/backfill​

Operation id: create_trigger_backfill. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing workflow:manage permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesFlow id
trigger_idpathstringyesThe trigger's id in the flow's YAML
workspacepathstringyes

Request body (application/json): CreateBackfillRequest

FieldTypeRequiredDescription
startstring (date-time)yesThe window's first instant (inclusive): the first tick at or after it fires first.
endstring (date-time), nullablenoThe window's last instant (inclusive); absent: the server's now. Must not be after the server's now.
inputsobject, nullablenoOverlaid on the schedule's inputs: key by key. An object; no key may name a FILE input.
labelsLabelDto[]noAdded to every execution the backfill fires, in this order. A list of \{key, value\} or a map.

Response 201 (application/json): TriggerEntryDto

FieldTypeRequiredDescription
trigger_idstringyes
typestringyesThe YAML's type, in full.
kindTriggerKindDtoyesWhat a trigger is, as egret runs it: one of the three kinds it fires, or other (a Leaf: any other type, which egret never fires).
yaml_disabledbooleanyesThe flow's or the trigger's YAML says disabled: true.
runtime_disabledbooleanyesSwitched off at runtime (workflow.disabled_triggers).
disabled_bystring (uuid), nullableno
disabled_by_namestring, nullablenoThe switcher's display name.
disabled_atstring (date-time), nullableno
effective_disabledbooleanyesWhat the scheduler, the listener and the webhook route honour: the YAML (flow or trigger), the runtime switch, the flow's state being disabled, or the flow being in the trash.
can_togglebooleanyesWhether the UI's switch is enabled. It is disabled for a trigger the YAML disables (toggle_refusal: yaml_disabled), but the switch route still accepts switching such a trigger OFF; only switching it ON is refused there (409...
toggle_refusalToggleRefusalno
duplicate_idbooleanyesThe flow declares this trigger id more than once (a save-time error, duplicate_trigger_id); the state is the id's.
scheduleScheduleInfoDtono
flowFlowTriggerInfoDtono
webhookWebhookInfoDtono
last_executionLastExecutionDtono
backfillBackfillDtono
can_backfillbooleanyesWhether the Backfill button is usable; the create route checks for itself.
backfill_refusalCannotBackfillno
StatusMeaning
201Created. The window [start, end] is inclusive at both ends; the trigger's next date moves to the window's first tick, so the scheduler fires the window one tick per pass, then resumes the regular schedule from where it stood under its...
400code: source_does_not_parse, invalid_body, backfill_window_invalid (start not before end), backfill_end_in_future (the message gives the server's time), backfill_start_too_early (more than ten years back), backfill_no_ticks,...
401Not authenticated
403Missing workflow:manage permission, or the workflows module is disabled for this workspace
404No such flow in this workspace, the flow is in the trash, or its source declares no trigger with this id (code: not_found)
409code: backfill_not_supported (not a Schedule), trigger_disabled (the trigger is effective-disabled), trigger_off_queue (the schedule has no next date; the message gives why) or backfill_exists
413The body is over 64 KiB (code: body_too_large)
500Internal error

DELETE /api/ws/{workspace}/workflows/flows/{id}/triggers/{trigger_id}/backfill​

Operation id: delete_trigger_backfill. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing workflow:manage permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesFlow id
trigger_idpathstringyesThe trigger's id in the flow's YAML
workspacepathstringyes

Response 200 (application/json): TriggerEntryDto

FieldTypeRequiredDescription
trigger_idstringyes
typestringyesThe YAML's type, in full.
kindTriggerKindDtoyesWhat a trigger is, as egret runs it: one of the three kinds it fires, or other (a Leaf: any other type, which egret never fires).
yaml_disabledbooleanyesThe flow's or the trigger's YAML says disabled: true.
runtime_disabledbooleanyesSwitched off at runtime (workflow.disabled_triggers).
disabled_bystring (uuid), nullableno
disabled_by_namestring, nullablenoThe switcher's display name.
disabled_atstring (date-time), nullableno
effective_disabledbooleanyesWhat the scheduler, the listener and the webhook route honour: the YAML (flow or trigger), the runtime switch, the flow's state being disabled, or the flow being in the trash.
can_togglebooleanyesWhether the UI's switch is enabled. It is disabled for a trigger the YAML disables (toggle_refusal: yaml_disabled), but the switch route still accepts switching such a trigger OFF; only switching it ON is refused there (409...
toggle_refusalToggleRefusalno
duplicate_idbooleanyesThe flow declares this trigger id more than once (a save-time error, duplicate_trigger_id); the state is the id's.
scheduleScheduleInfoDtono
flowFlowTriggerInfoDtono
webhookWebhookInfoDtono
last_executionLastExecutionDtono
backfillBackfillDtono
can_backfillbooleanyesWhether the Backfill button is usable; the create route checks for itself.
backfill_refusalCannotBackfillno
StatusMeaning
200Deleted. The ticks not yet fired are dropped; the executions already fired stay. The regular schedule resumes from the later of where it stood at create and the backfill's next tick, under its recoverMissedSchedules (absent: ALL); a...
400code: source_does_not_parse
401Not authenticated
403Missing workflow:manage permission, or the workflows module is disabled for this workspace
404code: not_found (no such flow or trigger) or no_backfill
409code: backfill_not_supported (not a Schedule)
500Internal error

PUT /api/ws/{workspace}/workflows/flows/{id}/triggers/{trigger_id}/backfill/paused​

Operation id: set_trigger_backfill_paused. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing workflow:manage permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesFlow id
trigger_idpathstringyesThe trigger's id in the flow's YAML
workspacepathstringyes

Request body (application/json): SetBackfillPausedRequest

FieldTypeRequiredDescription
pausedbooleanyes

Response 200 (application/json): TriggerEntryDto

FieldTypeRequiredDescription
trigger_idstringyes
typestringyesThe YAML's type, in full.
kindTriggerKindDtoyesWhat a trigger is, as egret runs it: one of the three kinds it fires, or other (a Leaf: any other type, which egret never fires).
yaml_disabledbooleanyesThe flow's or the trigger's YAML says disabled: true.
runtime_disabledbooleanyesSwitched off at runtime (workflow.disabled_triggers).
disabled_bystring (uuid), nullableno
disabled_by_namestring, nullablenoThe switcher's display name.
disabled_atstring (date-time), nullableno
effective_disabledbooleanyesWhat the scheduler, the listener and the webhook route honour: the YAML (flow or trigger), the runtime switch, the flow's state being disabled, or the flow being in the trash.
can_togglebooleanyesWhether the UI's switch is enabled. It is disabled for a trigger the YAML disables (toggle_refusal: yaml_disabled), but the switch route still accepts switching such a trigger OFF; only switching it ON is refused there (409...
toggle_refusalToggleRefusalno
duplicate_idbooleanyesThe flow declares this trigger id more than once (a save-time error, duplicate_trigger_id); the state is the id's.
scheduleScheduleInfoDtono
flowFlowTriggerInfoDtono
webhookWebhookInfoDtono
last_executionLastExecutionDtono
backfillBackfillDtono
can_backfillbooleanyesWhether the Backfill button is usable; the create route checks for itself.
backfill_refusalCannotBackfillno
StatusMeaning
200Paused or resumed (idempotent: already in that state is a 200 with no write and no audit event). Only the backfill row is written: a paused backfill is not fired, and a resumed one fires its next tick on the next pass. A switched-off...
400code: source_does_not_parse or invalid_body
401Not authenticated
403Missing workflow:manage permission, or the workflows module is disabled for this workspace
404code: not_found (no such flow or trigger) or no_backfill
409code: backfill_not_supported (not a Schedule)
413The body is over 64 KiB (code: body_too_large)
500Internal error

PUT /api/ws/{workspace}/workflows/flows/{id}/triggers/{trigger_id}/disabled​

Operation id: set_trigger_disabled. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing workflow:manage permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesFlow id
trigger_idpathstringyesThe trigger's id in the flow's YAML
workspacepathstringyes

Request body (application/json): SetTriggerDisabledRequest

FieldTypeRequiredDescription
disabledbooleanyestrue: off; false: on.
recover_missedbooleannoOn a re-enable of a switched-off, overdue Schedule only (an already-on trigger keeps its dates): false (the default) skips the missed ticks (the next date becomes the first tick after now); true follows the trigger's...

Response 200 (application/json): TriggerEntryDto

FieldTypeRequiredDescription
trigger_idstringyes
typestringyesThe YAML's type, in full.
kindTriggerKindDtoyesWhat a trigger is, as egret runs it: one of the three kinds it fires, or other (a Leaf: any other type, which egret never fires).
yaml_disabledbooleanyesThe flow's or the trigger's YAML says disabled: true.
runtime_disabledbooleanyesSwitched off at runtime (workflow.disabled_triggers).
disabled_bystring (uuid), nullableno
disabled_by_namestring, nullablenoThe switcher's display name.
disabled_atstring (date-time), nullableno
effective_disabledbooleanyesWhat the scheduler, the listener and the webhook route honour: the YAML (flow or trigger), the runtime switch, the flow's state being disabled, or the flow being in the trash.
can_togglebooleanyesWhether the UI's switch is enabled. It is disabled for a trigger the YAML disables (toggle_refusal: yaml_disabled), but the switch route still accepts switching such a trigger OFF; only switching it ON is refused there (409...
toggle_refusalToggleRefusalno
duplicate_idbooleanyesThe flow declares this trigger id more than once (a save-time error, duplicate_trigger_id); the state is the id's.
scheduleScheduleInfoDtono
flowFlowTriggerInfoDtono
webhookWebhookInfoDtono
last_executionLastExecutionDtono
backfillBackfillDtono
can_backfillbooleanyesWhether the Backfill button is usable; the create route checks for itself.
backfill_refusalCannotBackfillno
StatusMeaning
200Switched (idempotent: off twice, or on with no switch, is a 200). The answer is the trigger's entry as GET .../triggers returns it. Off stops the trigger's schedule claim, Flow-trigger listener and webhook; a fire already claimed commits...
400The flow's saved source does not parse (code: source_does_not_parse), or the body is not a switch request: bad JSON, a missing or mistyped field, or no JSON content type (code: invalid_body)
401Not authenticated
403Missing workflow:manage permission, or the workflows module is disabled for this workspace
404No such flow in this workspace, the flow is in the trash, or its source declares no trigger with this id (code: not_found)
409code: trigger_disabled_in_source (switching on a trigger whose flow or trigger YAML says disabled: true; switching it off is accepted), trigger_not_supported (a trigger type egret does not run), or recover_missed_unknown...
413The body is over 2 MiB (code: body_too_large)
500Internal error

POST /api/ws/{workspace}/workflows/flows/{id}/validate​

Operation id: validate_flow. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing workflow:manage permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesFlow id — scopes the request to this workspace, but the YAML checked is the request body, not the stored draft
workspacepathstringyes

Request body (application/json): ValidateFlowRequest

FieldTypeRequiredDescription
sourcestringyes

Response 200 (application/json): ValidationReportDto

FieldTypeRequiredDescription
errorsFindingDto[]yes
warningsFindingDto[]yes
StatusMeaning
200The validation report — never blocks on errors, since this route is called on unsaved edits
400The YAML does not parse
401Not authenticated
403Missing workflow:manage permission, or the workflows module is disabled for this workspace
404No such flow in this workspace
500Internal error

GET /api/ws/{workspace}/workflows/flows/{id}/versions​

Operation id: list_flow_versions. Auth: Session cookie. Forbidden (403): Missing workflow:read permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesFlow id
workspacepathstringyes

Response 200 (application/json): array of FlowVersionDto

FieldTypeRequiredDescription
idstring (uuid)yes
flow_idstring (uuid)yes
versioninteger (int32)yes
snapshotobjectyes
notestringyes
created_bystring (uuid), nullableno
created_by_namestring, nullablenoThe publisher's display name: the profile name, else the email. Null when created_by is null or the user no longer exists (W7a spec §7.4).
created_atstring (date-time)yes
StatusMeaning
200Published versions, newest first
401Not authenticated
403Missing workflow:read permission, or the workflows module is disabled for this workspace
404No such flow in this workspace
500Internal error

GET /api/ws/{workspace}/workflows/flows/{id}/versions/{version}​

Operation id: get_flow_version. Auth: Session cookie. Forbidden (403): Missing workflow:read permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
idpathstring (uuid)yesFlow id
versionpathinteger (int32)yesVersion number
workspacepathstringyes

Response 200 (application/json): FlowVersionDto

FieldTypeRequiredDescription
idstring (uuid)yes
flow_idstring (uuid)yes
versioninteger (int32)yes
snapshotobjectyes
notestringyes
created_bystring (uuid), nullableno
created_by_namestring, nullablenoThe publisher's display name: the profile name, else the email. Null when created_by is null or the user no longer exists (W7a spec §7.4).
created_atstring (date-time)yes
StatusMeaning
200One published version's frozen snapshot
401Not authenticated
403Missing workflow:read permission, or the workflows module is disabled for this workspace
404No such flow, or no such version of it, in this workspace
500Internal error

GET /api/ws/{workspace}/workflows/namespaces​

Operation id: list_namespaces. Auth: Session cookie. Forbidden (403): Missing workflow:read permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
prefixquerystringnoOnly this namespace and the ones beneath it, dot-anchored: company matches company and company.team, never companyx. Empty means no filter.

Response 200 (application/json): array of WorkflowNamespaceDto

FieldTypeRequiredDescription
namespacestringyes
flowsinteger (int64)yesFlows in exactly this namespace that are not deleted.
filesinteger (int64)yesLive namespace files (a path whose latest revision is not deleted; several revisions of one path are one file; directories are not counted).
kv_keysinteger (int64)yesLive KV keys (the latest revision neither deleted nor expired).
ownbooleanyesFalse when the namespace is present only as a parent by dots of another (its counts are then all zero). True for a source, whose counts can all be zero when it holds only a live empty directory.
StatusMeaning
200The workspace's namespaces, from flows that are not deleted, live namespace files and live KV keys, plus every parent by dots (own: false); a namespace holding only a live directory is listed (own: true, files: 0); sorted by namespace...
401Not authenticated
403Missing workflow:read permission, or the workflows module is disabled for this workspace
500Internal error

GET /api/ws/{workspace}/workflows/namespaces/{namespace}​

Operation id: get_namespace. Auth: Session cookie. Forbidden (403): Missing workflow:read permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
namespacepathstringyesThe namespace
workspacepathstringyes

Response 200 (application/json): WorkflowNamespaceDetailDto

FieldTypeRequiredDescription
namespacestringyes
flowsinteger (int64)yesFlows in exactly this namespace that are not deleted.
filesinteger (int64)yesLive namespace files (directories are not counted).
kv_keysinteger (int64)yesLive KV keys (the latest revision neither deleted nor expired).
ownbooleanyesFalse when the namespace is present only as a parent by dots of another.
can_managebooleanyesThe caller holds workflow:manage in this workspace: the same PDP decision as the namespace file and KV write routes, which still check for themselves. The UI disables its writes when this is false.
StatusMeaning
200The namespace's own counts; own: false when it is only a parent by dots of another; can_manage whether the caller holds workflow:manage
400Not a valid namespace name (^[a-z0-9][a-z0-9._-]*, 1-150 characters)
401Not authenticated
403Missing workflow:read permission, or the workflows module is disabled for this workspace
404Nothing lives in this namespace or beneath it in this workspace
500Internal error

GET /api/ws/{workspace}/workflows/namespaces/{namespace}/dependencies​

Operation id: namespace_dependencies. Auth: Session cookie. Forbidden (403): Missing workflow:read permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
namespacepathstringyesThe namespace; its children (dot-anchored) are inside it
workspacepathstringyes

Response 200 (application/json): NamespaceDependenciesDto

FieldTypeRequiredDescription
nodesNamespaceDependencyNodeDto[]yesThe namespace's flows and its children's, then every flow elsewhere with a direct edge to or from one of them; by namespace, then flow id.
edgesNamespaceDependencyEdgeDto[]yesEdges with at least one end in the namespace; one per (source, target, kind).
unparsableinteger (int64)yesDrafts in the WORKSPACE (not only this namespace) whose YAML does not parse. Each is still a node (unparsable: true) when it is in the namespace or an edge reaches it, but its own edges are unknown.
StatusMeaning
200The flow-to-flow graph of the namespace, built from every flow's saved draft: subflow edges from Subflow tasks with a literal target, flow_trigger edges from Flow triggers' dependsOn entries naming a flow. A namespace with no...
400Not a valid namespace name (^[a-z0-9][a-z0-9._-]*, 1-150 characters)
401Not authenticated
403Missing workflow:read permission, or the workflows module is disabled for this workspace
422The workspace has more than 2000 flows (not deleted), every one of which would be read (code: dependencies_too_large)
500Internal error

GET /api/ws/{workspace}/workflows/namespaces/{namespace}/files​

Operation id: download_namespace_file. Auth: Session cookie. Forbidden (403): Missing workflow:read permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
namespacepathstringyesThe namespace; one with a _files segment, an empty segment or an invalid name is refused (400). A namespace with no flow can hold files.
pathquerystringyesThe file's path in the namespace (a leading / is added when missing).
revisionqueryinteger (int32)noA given revision, served even when the path is soft-deleted; none = the latest, which must be live.
workspacepathstringyes

Response 200 (application/octet-stream): array of integer (int32)

StatusMeaning
200The file's bytes, streamed. Content-Type: application/octet-stream, Content-Disposition: attachment with the file's name (sanitised, and percent-encoded in filename*), X-Content-Type-Options: nosniff.
400A path rule (named), a refused namespace, /_flows, or the path is a directory (named): a directory has no contents. Also a revision whose object is gone from internal storage (named; egret never falls back to another revision).
401Not authenticated
403Missing workflow:read permission, or the workflows module is disabled for this workspace
404No such file in this workspace's namespace, no such revision of it, or (with no revision) the path is soft-deleted. A given revision of a soft-deleted path IS served.
503Internal storage or the database is unavailable or not configured; the request can be retried.

POST /api/ws/{workspace}/workflows/namespaces/{namespace}/files​

Operation id: upload_namespace_file. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing workflow:manage permission, or the workflows module is disabled for this workspace. workflow:read is not enough..

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
namespacepathstringyesThe namespace; it needs no flow
pathquerystringyesThe path in the namespace (a leading / is added when missing).
if_revisionqueryinteger (int32)noWrite only if the path's current revision is this one, else 409 with code: "file_changed" and nothing written. The current revision is the latest LIVE one: 0 means "the path must not exist" (a path that never existed, or one...
workspacepathstringyes

Request body (multipart/form-data): NsFileUploadForm

FieldTypeRequiredDescription
fileContentstring (binary)yes
StatusMeaning
200Stored, as the path's next revision. No content and no content type (Kestra's answer).
400A path rule (named), a refused namespace, /_flows, no fileContent part or another part before it (named), a malformed multipart body, headers over the budget, or an if_revision that is not a whole number from 0
401Not authenticated
403Missing workflow:manage permission, or the workflows module is disabled for this workspace. workflow:read is not enough.
408No byte of the body arrived for 30 seconds, or the body took longer than 12 hours in all; nothing was stored.
409A directory is at path, a file is where one of its parent directories goes, or a soft-deleted entry of the other kind still holds history there (named; only a flow's PurgeFiles task removes history -- the API has no purge route). Also...
413The file is over workflow.storage.max_file_bytes, or the body over its limit (named)
415Not multipart/form-data
503Internal storage or the database is unavailable or not configured; nothing was stored and the request can be retried.

PUT /api/ws/{workspace}/workflows/namespaces/{namespace}/files​

Operation id: move_namespace_file. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing workflow:manage permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
namespacepathstringyesThe namespace
fromquerystringyesThe file or directory to move; it must exist.
toquerystringyesWhere it goes; nothing may be there, not even a deleted path's history.
workspacepathstringyes
StatusMeaning
200Moved: every revision of the file (or of every path under the directory), numbers kept; the source is gone, to's missing parents exist. No content and no content type (Kestra's answer). A move runs to completion once it has started:...
400A path rule (named) for either path, a refused namespace, /_flows, or a move onto or under itself
401Not authenticated
403Missing workflow:manage permission, or the workflows module is disabled for this workspace
404Nothing live at from in this workspace's namespace (named); nothing is written
409to has any history -- a live entry, or a soft-deleted path's revisions at it, under it, of the other kind, or a file where one of its parents goes (named); nothing is moved and nothing purged (only a flow's PurgeFiles task removes...
413Refused before anything is copied: from holds more rows -- revisions and directories -- than one move may copy (workflow.storage.max_namespace_files), or its revisions hold more bytes in all than one move may copy...
503Internal storage or the database is unavailable; every copy made was rolled back and the source is untouched.

DELETE /api/ws/{workspace}/workflows/namespaces/{namespace}/files​

Operation id: delete_namespace_file. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing workflow:manage permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
namespacepathstringyesThe namespace
pathquerystringyesThe path in the namespace (a leading / is added when missing).
workspacepathstringyes
StatusMeaning
200Soft-deleted: the path and, for a directory, every path under it; parents left empty stay. Revisions are kept (listed by revisions, served by ?revision=N) until a flow's PurgeFiles removes them. A path with nothing live is not an...
400A path rule (named), the root, a refused namespace, or /_flows
401Not authenticated
403Missing workflow:manage permission, or the workflows module is disabled for this workspace
409The path is busy: a move or another write holds its lock for longer than the API waits (5 s); nothing was deleted, try again.
503The database is unavailable; the request can be retried.

GET /api/ws/{workspace}/workflows/namespaces/{namespace}/files/directory​

Operation id: list_namespace_directory. Auth: Session cookie. Forbidden (403): Missing workflow:read permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
namespacepathstringyesThe namespace
pathquerystringnoA path in the namespace; none (or /) = the namespace's root.
workspacepathstringyes

Response 200 (application/json): array of NsFileStatsDto

FieldTypeRequiredDescription
pathstringyesThe stored path: a leading /; a directory's ends with /.
typestringyesFile or Directory.
sizeinteger (int64)yesBytes; 0 for a directory.
revisioninteger (int32)yesThe latest revision; always 1 for a directory.
createdstring (date-time), nullablenoWhen the latest revision was written; null only for the namespace's virtual root (stats with no path), which has no row.
StatusMeaning
200The live children (files and directories) directly under the directory, in byte order; with no path, the namespace root's (an empty list for a namespace with no file).
400A path rule (named), a refused namespace, /_flows, or the path is a FILE (named): only a directory has children.
401Not authenticated
403Missing workflow:read permission, or the workflows module is disabled for this workspace
404No live directory at path in this workspace's namespace
413The directory holds more entries than one answer may hold (workflow.storage.max_namespace_files, named).
503The database is unavailable; the request can be retried.

POST /api/ws/{workspace}/workflows/namespaces/{namespace}/files/directory​

Operation id: create_namespace_directory. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing workflow:manage permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
namespacepathstringyesThe namespace; it needs no flow
pathquerystringyesThe path in the namespace (a leading / is added when missing).
workspacepathstringyes
StatusMeaning
200The directory and each missing parent exist (an existing live directory is not an error). No content and no content type (Kestra's answer).
400A path rule (named), the root, a refused namespace, or /_flows
401Not authenticated
403Missing workflow:manage permission, or the workflows module is disabled for this workspace
409A file is at path or where one of its parents goes, live or soft-deleted with its history (named; only a flow's PurgeFiles task removes history -- the API has no purge route). Also 409 when the path is busy: a move or another write...
503The database is unavailable; the request can be retried.

GET /api/ws/{workspace}/workflows/namespaces/{namespace}/files/export​

Operation id: export_namespace_files. Auth: Session cookie. Forbidden (403): Missing workflow:read permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
namespacepathstringyesThe namespace
workspacepathstringyes

Response 200 (application/zip): array of integer (int32)

StatusMeaning
200A zip archive of the latest live revision of every FILE of the namespace (no directory entry, no flow, no soft-deleted file), each named by its path without the leading /; stored (not compressed), each file read twice (once for its CRC,...
400A refused namespace, or a file whose path cannot be a zip entry name (its first segment looks like a Windows drive, C:; named)
401Not authenticated
403Missing workflow:read permission, or the workflows module is disabled for this workspace
413Refused before any byte is sent: the namespace holds more entries (files and directories) than one export may hold (workflow.storage.max_namespace_files, named), or its files hold more bytes in all than one export may read...
503Internal storage or the database is unavailable or not configured; the request can be retried.

GET /api/ws/{workspace}/workflows/namespaces/{namespace}/files/revisions​

Operation id: namespace_file_revisions. Auth: Session cookie. Forbidden (403): Missing workflow:read permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
namespacepathstringyesThe namespace
pathquerystringyesThe path in the namespace (a leading / is added when missing).
workspacepathstringyes

Response 200 (application/json): array of NsFileRevisionDto

FieldTypeRequiredDescription
revisioninteger (int32)yes
deletedbooleanyesThe path was soft-deleted at this revision (its latest); its bytes are still served by GET …/files?path&revision.
sizeinteger (int64)yes
createdstring (date-time)yes
StatusMeaning
200Every revision of the file, ascending, a soft-deleted path's included, each flagged deleted when the path was deleted at it.
400A path rule (named), a refused namespace, /_flows, or the path is a directory (named): a directory has no revisions.
401Not authenticated
403Missing workflow:read permission, or the workflows module is disabled for this workspace
404The path has never held a file in this workspace's namespace (or its history was purged)
503The database is unavailable; the request can be retried.

GET /api/ws/{workspace}/workflows/namespaces/{namespace}/files/search​

Operation id: search_namespace_files. Auth: Session cookie. Forbidden (403): Missing workflow:read permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
namespacepathstringyesThe namespace
qquerystringyesA case-insensitive substring of a file's path; "" finds nothing.
workspacepathstringyes

Response 200 (application/json): array of string

StatusMeaning
200The paths of the live FILES whose path contains q, case-insensitively (Kestra's rule), in byte order; directories are never listed; q="" finds nothing.
400No q, or a refused namespace
401Not authenticated
403Missing workflow:read permission, or the workflows module is disabled for this workspace
413More files match than one answer may hold (workflow.storage.max_namespace_files, named); narrow q.
503The database is unavailable; the request can be retried.

GET /api/ws/{workspace}/workflows/namespaces/{namespace}/files/stats​

Operation id: namespace_file_stats. Auth: Session cookie. Forbidden (403): Missing workflow:read permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
namespacepathstringyesThe namespace
pathquerystringnoA path in the namespace; none (or /) = the namespace's root.
workspacepathstringyes

Response 200 (application/json): NsFileStatsDto

FieldTypeRequiredDescription
pathstringyesThe stored path: a leading /; a directory's ends with /.
typestringyesFile or Directory.
sizeinteger (int64)yesBytes; 0 for a directory.
revisioninteger (int32)yesThe latest revision; always 1 for a directory.
createdstring (date-time), nullablenoWhen the latest revision was written; null only for the namespace's virtual root (stats with no path), which has no row.
StatusMeaning
200The live file or directory at path. With no path (or /): the namespace's virtual root, \{path: "/", type: "Directory", size: 0, revision: 1, created: null\} -- nothing is created, in any namespace, with or without files.
400A path rule (named), a refused namespace, or /_flows
401Not authenticated
403Missing workflow:read permission, or the workflows module is disabled for this workspace
404Nothing live at path in this workspace's namespace
503The database is unavailable; the request can be retried.

GET /api/ws/{workspace}/workflows/namespaces/{namespace}/kv​

Operation id: list_kv. Auth: Session cookie. Forbidden (403): Missing workflow:read permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
namespacepathstringyesThe namespace; one with a _files or _kv segment, an empty segment or an invalid name is refused (400). A namespace with no flow can hold keys; one that holds none (or that only another workspace holds) answers [].
workspacepathstringyes

Response 200 (application/json): array of KvEntryDto

FieldTypeRequiredDescription
keystringyes
typestringyesSTRING, NUMBER, BOOLEAN, DATETIME, DATE, DURATION or JSON: the type stored with the latest revision.
sizeinteger (int64)yesThe stored value's size in bytes (its Ion text).
descriptionstring, nullableno
expiresAtstring (date-time), nullablenoWhen the key expires; null never.
revisioninteger (int32)yesThe latest revision.
updatedstring (date-time)yesWhen the latest revision was written.
StatusMeaning
200The namespace's live keys (neither soft-deleted nor expired), each its latest revision, in the order their latest revisions were written.
400A refused namespace (named)
401Not authenticated
403Missing workflow:read permission, or the workflows module is disabled for this workspace
413The namespace holds more live keys than one answer may hold (workflow.storage.max_namespace_files, named).
503Internal storage is not configured, or the database is unavailable; the request can be retried.

DELETE /api/ws/{workspace}/workflows/namespaces/{namespace}/kv​

Operation id: delete_kv_values. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing workflow:manage permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
namespacepathstringyesThe namespace
workspacepathstringyes

Request body (application/json): KvKeysBody

FieldTypeRequiredDescription
keysstring[]yes

Response 200 (application/json): KvKeysBody

FieldTypeRequiredDescription
keysstring[]yes
StatusMeaning
200\{"keys": [...]\}: the keys that were live and are now soft-deleted, ascending; a key that was not live is left out. One transaction: all or nothing.
400A malformed or missing body, a key that breaks the key rule (named; nothing is deleted), or a refused namespace
401Not authenticated
403Missing workflow:manage permission, or the workflows module is disabled for this workspace
409A key is busy (named), or other bulk deletes are running, for longer than the API waits (5 s); nothing was deleted, try again.
413More than 1,000 keys, or a body over 1 MiB (each cap is named); nothing was deleted. Send several requests.
503Internal storage is not configured, or the database is unavailable; nothing was deleted and the request can be retried.

GET /api/ws/{workspace}/workflows/namespaces/{namespace}/kv/inheritance​

Operation id: list_inherited_kv. Auth: Session cookie. Forbidden (403): Missing workflow:read permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
namespacepathstringyesThe namespace whose PARENTS are listed (cut at dots: a.b.c lists a.b, then a).
workspacepathstringyes

Response 200 (application/json): array of KvInheritedDto

FieldTypeRequiredDescription
keystringyes
typestringyesSTRING, NUMBER, BOOLEAN, DATETIME, DATE, DURATION or JSON: the type stored with the latest revision.
sizeinteger (int64)yesThe stored value's size in bytes (its Ion text).
descriptionstring, nullableno
expiresAtstring (date-time), nullablenoWhen the key expires; null never.
revisioninteger (int32)yesThe latest revision.
updatedstring (date-time)yesWhen the latest revision was written.
namespacestringyesThe ancestor namespace the key is read from.
StatusMeaning
200The live keys of the namespace's ancestors only (not its own), deepest first; a key in two ancestors is listed once, from the deeper (Kestra's KVController, :73-100). Each entry names its namespace. **This path is also where a key named...
400A refused namespace (named)
401Not authenticated
403Missing workflow:read permission, or the workflows module is disabled for this workspace
413The ancestors hold more live keys in all than one answer may hold (workflow.storage.max_namespace_files, named).
503Internal storage is not configured, or the database is unavailable; the request can be retried.

GET /api/ws/{workspace}/workflows/namespaces/{namespace}/kv/{key}​

Operation id: get_kv_value. Auth: Session cookie. Forbidden (403): Missing workflow:read permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
namespacepathstringyesThe namespace
keypathstringyesThe key: [a-zA-Z0-9][a-zA-Z0-9._-]*, at most 350 bytes. GET …/kv/inheritance is the inheritance listing, not the key inheritance; that key is read here with any letter of it percent-encoded (inheritanc%65), since the route is...
revisionqueryinteger (int32)noA given revision, served even when the key is soft-deleted (not when it has expired); none = the latest, which must be live.
workspacepathstringyes

Response 200 (application/json): KvDetailDto

FieldTypeRequiredDescription
typestringyesThe stored type (never re-inferred on read).
valueobjectyesThe value: a DATETIME as 2025-01-02T03:04:05Z, a DATE as 2025-01-02, a DURATION as Java prints it (PT24H), a decimal with every digit, a JSON value as itself; any JSON type.
revisioninteger (int32)yes
updatedstring (date-time)yesWhen this revision was written.
descriptionstring, nullableno
expiresAtstring (date-time), nullableno
StatusMeaning
200The value with its stored type. With no revision, the latest, which must be live; with one, that revision, served when the key is soft-deleted.
400The key rule, a refused namespace, a revision that is not an integer, or a stored object that does not match its record (named)
401Not authenticated
403Missing workflow:read permission, or the workflows module is disabled for this workspace
404No such key in this workspace's namespace, a latest read of a soft-deleted or expired key, an expired or unknown revision. Nothing is written by the read.
413The stored value is over workflow.storage.max_read_bytes (named)
503Internal storage or the database is unavailable or not configured; the request can be retried.

PUT /api/ws/{workspace}/workflows/namespaces/{namespace}/kv/{key}​

Operation id: put_kv_value. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing workflow:manage permission, or the workflows module is disabled for this workspace. workflow:read is not enough..

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
namespacepathstringyesThe namespace; it needs no flow
keypathstringyesThe key: [a-zA-Z0-9][a-zA-Z0-9._-]*, at most 350 bytes (inheritance included)
descriptionheaderstringnoThe key's description, stored with this revision ("" is kept as given).
ttlheaderstringnoAn ISO-8601 duration (PT1H, P1D): the key expires that long after the write. PT0S is accepted (expired at once); a negative one, a malformed one, or one over 1,000 years is 400.
If-None-Matchheaderstringno* makes the write a create: it is refused (409 kv_exists) when the key exists, that is when its latest revision is live (neither deleted nor expired, judged under the key's lock). A key whose latest revision is deleted or expired does...
workspacepathstringyes

Request body (text/plain): string

StatusMeaning
200Stored as the key's next revision (it overwrites unless If-None-Match: *). No content and no content type (Kestra's answer).
400The key rule, a refused namespace, an If-None-Match other than *, a malformed or negative ttl (Cannot convert value 'x' to Duration, ttl cannot be negative), an empty or whitespace-only body (empty body), a body that is a single...
401Not authenticated
403Missing workflow:manage permission, or the workflows module is disabled for this workspace. workflow:read is not enough.
408No byte of the body arrived for 30 seconds, or the body took longer than 12 hours in all; nothing was stored.
409code kv_exists: If-None-Match: * was sent and the key exists (its latest revision is live); nothing was written. Without a code: the key is busy, another write holds its lock for longer than the API waits (5 s); nothing was written,...
413The body, or the value as stored, is over workflow.storage.max_read_bytes; or the value holds more values than the dense-value limit (max_read_bytes/64), or a number of more than 1,000 digits (each named). Nothing was stored.
415A Content-Type other than text/plain
503Internal storage or the database is unavailable or not configured; nothing was stored and the request can be retried.

DELETE /api/ws/{workspace}/workflows/namespaces/{namespace}/kv/{key}​

Operation id: delete_kv_value. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing workflow:manage permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
namespacepathstringyesThe namespace
keypathstringyesThe key (inheritance included)
workspacepathstringyes

Response 200 (text/plain): boolean

StatusMeaning
200true: the key was live and is now soft-deleted (its revisions are kept, listed by …/revisions and served by ?revision=N); false: there was no live key (never written, already deleted, or expired), nothing done.
400The key rule, or a refused namespace
401Not authenticated
403Missing workflow:manage permission, or the workflows module is disabled for this workspace
409The key is busy: another write holds its lock for longer than the API waits (5 s); nothing was deleted, try again.
503Internal storage is not configured, or the database is unavailable; the request can be retried.

GET /api/ws/{workspace}/workflows/namespaces/{namespace}/kv/{key}/revisions​

Operation id: kv_revisions. Auth: Session cookie. Forbidden (403): Missing workflow:read permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
namespacepathstringyesThe namespace
keypathstringyesThe key (inheritance included)
workspacepathstringyes

Response 200 (application/json): array of KvRevisionDto

FieldTypeRequiredDescription
revisioninteger (int32)yes
typestringyes
sizeinteger (int64)yes
descriptionstring, nullableno
expiresAtstring (date-time), nullableno
createdstring (date-time)yes
deletedbooleanyesThe key was soft-deleted at this revision (its latest); the revision is still served by GET …/kv/\{key\}?revision=N.
expiredbooleanyesThis revision has expired: it is not served.
StatusMeaning
200Every revision of the key, ascending, each flagged deleted (soft-deleted at it) and expired.
400The key rule, or a refused namespace
401Not authenticated
403Missing workflow:read permission, or the workflows module is disabled for this workspace
404The key has no revision in this workspace's namespace
503Internal storage is not configured, or the database is unavailable; the request can be retried.

GET /api/ws/{workspace}/workflows/schema​

Operation id: get_flow_schema. Auth: Session cookie. Forbidden (403): Missing workflow:read permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug

Response 200 (application/json): object

StatusMeaning
200The JSON Schema (draft 2020-12) of one flow document as this workspace may publish it: Kestra's definitions filtered to the types and properties egret honours, egret's own types, and the script and plugin types only when this workspace's...
304If-None-Match names the current ETag
401Not authenticated
403Missing workflow:read permission, or the workflows module is disabled for this workspace
500Internal error

GET /api/ws/{workspace}/workflows/triggers​

Operation id: list_triggers. Auth: Session cookie. Forbidden (403): Missing workflow:read permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
namespace_prefixquerystringnoThis namespace and every namespace beneath it, dot-anchored: a.b matches a.b and a.b.c, never a.bc. Must be a valid namespace name (400 otherwise).
flow_idquerystring (uuid)noOnly this flow (its uuid).
kindquerystringnoOne or more kinds, comma-separated: schedule, webhook, flow, other. Anything else is a 400. Empty (kind=) is no filter.
statequerystringnoenabled or disabled, on effective_disabled. Anything else is a 400. Empty (state=) is no filter.
backfillquerystringnorunning (a backfill that is not paused), paused or any. Anything else is a 400. Empty (backfill=) is no filter.
qquerystringnoA case-insensitive substring of the trigger id, the flow id or the namespace.
limitqueryinteger (int64)noHow many rows to return. Default 50, maximum 200; a larger value is clamped, and the clamped value comes back in the response's limit.
offsetqueryinteger (int64)noHow many rows to skip. Negative is clamped to zero.

Response 200 (application/json): TriggerPageDto

FieldTypeRequiredDescription
rowsTriggerRowDto[]yes
totalinteger (int64)yesEvery trigger that matches, across pages.
limitinteger (int64)yesThe page size served (clamped).
offsetinteger (int64)yes
unparsableinteger (int64)yesFlows in scope whose source did not parse: their triggers are unknown and not listed.
scheduler_enabledbooleanyes
worker_enabledbooleanyes
webhooks_enabledbooleanyes
can_managebooleanyesThe caller holds workflow:manage in this workspace: the switches and the bulk route are theirs to use. Per caller, not per row, so a page whose rows are all refused for another reason still says it.
StatusMeaning
200One page of the triggers of the workspace's flows not in the trash, by namespace, flow id and declaration order. Rows carry no depends_on.conditions and no webhook (read the per-flow route), and carry backfill, can_backfill and...
400namespace_prefix is not a valid namespace name, or kind/state/backfill holds an unknown value, or the query string does not decode
401Not authenticated
403Missing workflow:read permission, or the workflows module is disabled for this workspace
422More than 2000 flows match the namespace and flow filters (code: triggers_too_large); narrow by namespace
500Internal error

POST /api/ws/{workspace}/workflows/triggers/backfill/delete​

Operation id: delete_triggers_backfill. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing workflow:manage permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
workspacepathstringyes

Request body (application/json): DeleteBackfillsRequest

FieldTypeRequiredDescription
triggersBulkTriggerRef[]yesAt most 100.

Response 200 (application/json): BulkResultsDto

FieldTypeRequiredDescription
resultsBulkResultDto[]yes
StatusMeaning
200A result per entry, in the order given. Each backfill is deleted in its own transaction, as the per-trigger route does, and a refusal (ok: false with its code: no_backfill, not_found for a flow outside this workspace, never a 403)...
400More than 100 entries (code: too_many_triggers; nothing is deleted), or invalid_body
401Not authenticated
403Missing workflow:manage permission, or the workflows module is disabled for this workspace
413The body is over 64 KiB (code: body_too_large); nothing is deleted
500Internal error; entries before the failing one may be deleted

PUT /api/ws/{workspace}/workflows/triggers/backfill/paused​

Operation id: set_triggers_backfill_paused. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing workflow:manage permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
workspacepathstringyes

Request body (application/json): SetBackfillsPausedRequest

FieldTypeRequiredDescription
triggersBulkTriggerRef[]yesAt most 100.
pausedbooleanyes

Response 200 (application/json): BulkResultsDto

FieldTypeRequiredDescription
resultsBulkResultDto[]yes
StatusMeaning
200A result per entry, in the order given. Each entry is paused or resumed in its own transaction, as the per-trigger route does, and a refusal (ok: false with its code: no_backfill, not_found for a flow outside this workspace, never a...
400More than 100 entries (code: too_many_triggers; nothing is changed), or invalid_body
401Not authenticated
403Missing workflow:manage permission, or the workflows module is disabled for this workspace
413The body is over 64 KiB (code: body_too_large); nothing is changed
500Internal error; entries before the failing one may be changed

PUT /api/ws/{workspace}/workflows/triggers/disabled​

Operation id: set_triggers_disabled. Auth: Session cookie and X-Egret-CSRF header. Forbidden (403): Missing workflow:manage permission, or the workflows module is disabled for this workspace.

ParameterInTypeRequiredDescription
workspacepathstringyesWorkspace slug
workspacepathstringyes

Request body (application/json): SetTriggersDisabledRequest

FieldTypeRequiredDescription
triggersBulkTriggerRef[]yesAt most 100.
disabledbooleanyes
recover_missedbooleannoAs [SetTriggerDisabledRequest::recover_missed], for every entry.

Response 200 (application/json): BulkResultsDto

FieldTypeRequiredDescription
resultsBulkResultDto[]yes
StatusMeaning
200A result per entry, in the order given. Each entry is switched in its own transaction, as the per-trigger route does, and a refusal (ok: false with its code: a flow outside this workspace is not_found, never a 403) does not stop the...
400More than 100 entries (code: too_many_triggers; nothing is switched), or the body is not a bulk switch request: bad JSON, a missing or mistyped field, or no JSON content type (code: invalid_body)
401Not authenticated
403Missing workflow:manage permission, or the workflows module is disabled for this workspace
413The body is over 64 KiB (code: body_too_large); nothing is switched
500Internal error; entries before the failing one may be switched