Skip to content

Workflows

These endpoints cover the full workflow lifecycle: configure a workflow, invoke it, observe its progress, and export its durable execution history. Every endpoint requires authentication, and responses use application/json.

GET /api/workflows/workers

Returns every in-memory workflow worker with its registration status (whether a config exists in lt_config_workflows).

Example request

Terminal window
curl https://lt.acme.dev/api/workflows/workers \
-H "Authorization: Bearer $LT_TOKEN"

Response 200

{
"workers": [
{
"name": "reviewContent",
"taskQueue": "long-tail",
"registered": true
}
]
}
GET /api/workflows/discovered

Returns one list that merges active workers, historical workflow entities from the durable store, and workflow configurations. Each entry carries a registered boolean that says whether a config exists.

Example request

Terminal window
curl https://lt.acme.dev/api/workflows/discovered \
-H "Authorization: Bearer $LT_TOKEN"

Response 200

{
"workflows": [
{
"name": "reviewContent",
"taskQueue": "long-tail",
"registered": true,
"config": { "...": "..." }
}
]
}

Workflow configuration lives in Postgres (lt_config_workflows). It decides which workflows the interceptor manages, who can escalate, who can invoke, and what data flows between steps.

GET /api/workflows/config

Returns every workflow configuration.

Example request

Terminal window
curl https://lt.acme.dev/api/workflows/config \
-H "Authorization: Bearer $LT_TOKEN"

Response 200

{
"workflows": [
{
"id": "a1b2c3d4-...",
"workflow_type": "reviewContent",
"invocable": true,
"task_queue": "long-tail",
"default_role": "reviewer",
"default_modality": "default",
"description": "AI content review with human escalation",
"consumes": [],
"execute_as": null,
"tool_tags": [],
"envelope_schema": null,
"resolver_schema": null,
"cron_schedule": null,
"roles": ["reviewer"],
"invocation_roles": ["submitter"],
"created_at": "2025-01-15T10:00:00.000Z",
"updated_at": "2025-01-15T10:00:00.000Z"
}
]
}
GET /api/workflows/:type/config

Returns one workflow configuration by type name.

Path parameters

Parameter Description
type Workflow type name (for example, reviewContent)

Example request

Terminal window
curl https://lt.acme.dev/api/workflows/reviewContent/config \
-H "Authorization: Bearer $LT_TOKEN"

Response 200

A single workflow config object (same shape as the array element in List all workflow configurations).

Response 404

{ "error": "Workflow config not found" }

Create or replace a workflow configuration

Section titled “Create or replace a workflow configuration”
PUT /api/workflows/:type/config

Creates or replaces the configuration for a workflow type. The call is idempotent: it replaces the entire configuration, including roles and invocation roles (cascade delete and re-insert), and invalidates the in-memory config cache.

Auth: Requires the admin or superadmin role. When the body sets execute_as, the caller must also satisfy the act-as rule described under Invoke a workflow.

Path parameters

Parameter Description
type Workflow type name

Request body

Field Type Default Description
invocable boolean false Allow this workflow to be started via POST /api/workflows/:type/invoke
certified boolean derived Explicit HITL certification (interceptor treatment). When omitted, it is derived from whether roles or consumes are present.
task_queue string | null null Task queue name (required for invocable workflows)
default_role string "reviewer" Role assigned to escalations when the workflow does not specify one
description string | null null Human-readable description
roles string[] [] Interceptor default for who can claim interceptor-raised escalations. Escalations raised in workflow code choose their own role, whose versioned schema takes precedence.
invocation_roles string[] [] Roles allowed to invoke via the API. Empty means any authenticated user.
consumes string[] [] Workflow types whose completed data this workflow receives via envelope.lt.providers
execute_as string | null null Service account external_id to run as (overrides the invoker identity)
tool_tags string[] [] MCP tool tags for scoped tool discovery
envelope_schema object | null null Example envelope that pre-fills the legacy invoke form
input_schema object | null null x-lt-* JSON Schema for the rich invoke form. POST /:type/invoke validates data against it. See Forms.
input_lookups { domain, key, version, as? }[] | null null Versioned knowledge refs the invoke form reads as lookup.<as ?? key>. Malformed refs are refused with 400. See Lookups.
icon string | null null Curated icon name from WORKFLOW_ICONS. Unknown names are refused with 400.
resolver_schema object | null null Deprecated legacy fallback only. The escalation form is owned by the target role as a versioned form_schema.
cron_schedule string | null null Cron expression for scheduled execution (for example, "0 9 * * *")

Example request

Terminal window
curl -X PUT https://lt.acme.dev/api/workflows/reviewContent/config \
-H "Authorization: Bearer $LT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"invocable": true,
"task_queue": "long-tail",
"default_role": "reviewer",
"roles": ["reviewer", "senior-reviewer"],
"invocation_roles": ["submitter", "admin"],
"consumes": ["extractDocument"]
}'

Response 200

The created or updated config object.

GET /api/workflows/:type/input-lookups

Returns the versioned knowledge editions pinned on the config’s input_lookups, resolved server-side. The refs on the config are the grant: any caller the invoke gate admits for the workflow reads exactly the pinned editions it names.

Editions are immutable, so the response caches for the session. A ref whose snapshot does not exist answers with missing: true, and the batch still succeeds.

Path parameters

Parameter Description
type Workflow type name

Example request

Terminal window
curl https://lt.acme.dev/api/workflows/reviewContent/input-lookups \
-H "Authorization: Bearer $LT_TOKEN"

Response 200

{
"lookups": [
{ "domain": "inventory", "key": "serial-numbers", "version": 1, "as": "serials", "data": { "items": [{ "value": "sn-1", "label": "Unit 1" }] } }
]
}
Status Meaning
403 The caller may not invoke this workflow
404 No config exists for this type
DELETE /api/workflows/:type/config

Deletes the workflow config and all associated roles and invocation roles (cascade).

Auth: Requires the admin or superadmin role.

Path parameters

Parameter Description
type Workflow type name

Example request

Terminal window
curl -X DELETE https://lt.acme.dev/api/workflows/reviewContent/config \
-H "Authorization: Bearer $LT_TOKEN"

Response 200

{ "deleted": true, "workflow_type": "reviewContent" }

Response 404

{ "error": "Workflow config not found" }
POST /api/workflows/:type/invoke

Starts a workflow by its registered type. The workflow must have invocable: true in its configuration.

Path parameters

Parameter Description
type Workflow type name (for example, reviewContent)

Request body

Field Type Required Description
data object yes Business data passed to the workflow as envelope.data
metadata object no Control flow metadata passed as envelope.metadata
execute_as string no Account external_id or id to run as. Requires admin access and must satisfy the act-as rule below.

The input gate validates against the metadata in the request. The dashboard sends the config’s envelope_schema.metadata with every invoke it starts.

Example request

Terminal window
curl -X POST https://lt.acme.dev/api/workflows/reviewContent/invoke \
-H "Authorization: Bearer $LT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"data": {
"contentId": "post-456",
"content": "This article discusses the impact of...",
"contentType": "article"
}
}'

Response 202

{
"workflowId": "reviewContent-a1b2c3d4",
"message": "Workflow started"
}

The workflow starts on its configured task_queue with a generated workflow ID ({type}-{guid}). The response returns immediately, and the workflow runs durably in the background.

Error responses

Status Body Meaning
400 { "error": "Request body must include a data object" } Missing or invalid data field
400 { "error": "Workflow has no task_queue configured" } Config exists but task_queue is null
403 { "error": "Workflow is not invocable" } invocable is false
403 { "error": "User not registered" } RBAC check failed: no matching user
403 { "error": "Insufficient role for invocation" } User lacks a required invocation role
403 { "error": "execute_as may not exceed your own authority" } The caller may not act as the execute_as account
404 { "error": "execute_as principal \"...\" not found" } No account matches execute_as
404 { "error": "Workflow not found" } No config exists for this type
422 { "error": "data failed input schema validation (n violations)", "code": "schema_validation", "violations": [{ "field", "message" }], "role": null, "schemaVersion": null, "workflowType" } The config declares input_schema and data violates it. x-lt-options over pinned input_lookups constrains values to the resolved edition. See Schema enforcement.

When invocation_roles is empty, any authenticated user can invoke. When set, the user must hold at least one of the listed roles. Roles are read from the caller’s current grants in lt_user_roles, not from token claims. A superadmin grant, or the admin role held with admin type, invokes any workflow. capabilityInvoke requires a superadmin grant.

execute_as follows the act-as rule: a superadmin may act as anyone. A caller holding an admin-type grant may act as an account that holds no superadmin grant and whose every role the caller holds at the same or higher type. Nobody else may.

GET /api/workflows/invocable

Returns every workflow the calling user may invoke, decided by the same predicate the invoke gate runs. Superadmins and admin/admin callers also receive active durable workers that carry no registration row.

Example request

Terminal window
curl https://lt.acme.dev/api/workflows/invocable \
-H "Authorization: Bearer $LT_TOKEN"

Response 200

{
"workflows": [
{ "workflow_type": "reviewContent", "task_queue": "long-tail", "tier": "registered", "invocable": true, "invocation_roles": ["submitter"], "input_schema": { "...": "..." }, "envelope_schema": { "data": {}, "metadata": { "source": "dashboard" } }, "description": "..." }
]
}

Each entry is the full config row plus tier (durable, registered, certified). The dashboard Invoke Tool page and its nav entry read this list.

These endpoints check on running or completed workflows. The workflowId returned from the invoke call is all you need.

GET /api/workflows/:workflowId/status

Returns the numeric status of a workflow run.

Auth: Requires builder access (superadmin or the engineer role).

Path parameters

Parameter Description
workflowId Workflow ID returned by the invoke call

Example request

Terminal window
curl https://lt.acme.dev/api/workflows/reviewContent-a1b2c3d4/status \
-H "Authorization: Bearer $LT_TOKEN"

Response 200

{
"workflowId": "reviewContent-a1b2c3d4",
"status": 0
}
Status value Meaning
0 Complete
Positive Running
Negative Interrupted
GET /api/workflows/:workflowId/result

Returns the result when the workflow is complete, or 202 while it is still running. The call returns immediately in both cases.

Auth: Requires builder access, or being the person who started the run or the account it runs as (read from the run’s start envelope: lt.userId, or lt.initiatedBy when it runs under execute_as). Others receive 403.

Path parameters

Parameter Description
workflowId Workflow ID returned by the invoke call

Example request

Terminal window
curl https://lt.acme.dev/api/workflows/reviewContent-a1b2c3d4/result \
-H "Authorization: Bearer $LT_TOKEN"

Response 200 (complete)

{
"workflowId": "reviewContent-a1b2c3d4",
"result": {
"type": "return",
"data": {
"approved": true,
"analysis": { "confidence": 0.92 }
},
"milestones": [
{ "name": "ai_review", "value": "approved" }
]
}
}

Response 202 (still running)

{
"workflowId": "reviewContent-a1b2c3d4",
"status": "running"
}

Every /api/workflow-states endpoint requires builder access, except /:workflowId/execution, which follows the same rule as Get workflow result.

Every workflow’s full execution history exports as JSON in two formats: a raw state export (HotMesh-native) and a structured execution event history with typed events, ISO timestamps, durations and cross-references.

State is transactionally checkpointed to Postgres after every step, so the export is a complete record of the run: every activity scheduled, every result returned, every signal received and every child workflow spawned.

GET /api/workflows/:workflowId/export

Returns the raw workflow state from HotMesh. For facet filtering and execution formats, use the /api/workflow-states endpoints below.

Auth: Requires builder access.

Path parameters

Parameter Description
workflowId Workflow ID

Example request

Terminal window
curl https://lt.acme.dev/api/workflows/reviewContent-a1b2c3d4/export \
-H "Authorization: Bearer $LT_TOKEN"

Response 200

Raw workflow state object (data, state, status, timeline, transitions).

GET /api/workflow-states/:workflowId

Full state export with facet filtering. The response includes five facets: data, state, status, timeline and transitions. Use allow or block to choose which facets are returned.

Auth: Requires builder access.

Query parameters

Parameter Type Required Description
allow string no Comma-separated allowlist of facets
block string no Comma-separated blocklist of facets
values string no Set to false to omit timeline values

allow and block are mutually exclusive. When both are provided, allow takes precedence.

Example request (only data and status)

Terminal window
curl "https://lt.acme.dev/api/workflow-states/reviewContent-a1b2c3d4?allow=data,status" \
-H "Authorization: Bearer $LT_TOKEN"

Response 200

{
"workflow_id": "reviewContent-a1b2c3d4",
"data": {
"contentId": "post-456",
"approved": true,
"analysis": { "confidence": 0.92 }
},
"status": 0
}
GET /api/workflow-states/:workflowId/execution

Exports the workflow’s execution as a sequence of typed events. Each event has an eventType, an ISO timestamp and typed attributes; activity events include durations and reference their scheduling event via scheduledEventId.

The response ends with a summary holding the total event count, wall-clock duration and final status. This is the primary export format for auditing, debugging and building dashboards over durable workflow executions.

Auth: Requires builder access, or being the person who started the run or the account it runs as (same rule as Get workflow result).

Query parameters

Parameter Type Required Default Description
excludeSystem string no false true to omit LT interceptor activities (lt*)
omitResults string no false true to strip activity result payloads
mode string no sparse sparse is a flat event list, verbose nests child workflows
maxDepth integer no 5 Recursion depth limit for verbose mode
Event type Description
workflow_execution_started Workflow began; includes input arguments
activity_task_scheduled Activity dispatched to a task queue
activity_task_completed Activity returned a result; includes duration and scheduledEventId
activity_task_failed Activity threw an error
child_workflow_execution_started Orchestrator spawned a child workflow
child_workflow_execution_completed Child workflow returned
child_workflow_execution_failed Child workflow failed
timer_started Timer (sleep or delay) began
timer_fired Timer elapsed
workflow_execution_signaled External signal received (for example, escalation resolution)
workflow_execution_completed Workflow finished successfully
workflow_execution_failed Workflow failed

Example request (history without interceptor internals)

Terminal window
curl "https://lt.acme.dev/api/workflow-states/reviewContent-a1b2c3d4/execution?excludeSystem=true" \
-H "Authorization: Bearer $LT_TOKEN"

Response 200

{
"workflowId": "reviewContent-a1b2c3d4",
"workflowName": "reviewContent",
"taskQueue": "long-tail",
"events": [
{
"eventId": 1,
"eventType": "workflow_execution_started",
"timestamp": "2025-01-15T10:00:00.000Z",
"details": {
"input": {
"data": { "contentId": "post-456" },
"metadata": {}
}
}
},
{
"eventId": 2,
"eventType": "activity_task_scheduled",
"timestamp": "2025-01-15T10:00:00.050Z",
"details": {
"activityType": "analyzeContent",
"taskQueue": "long-tail"
}
},
{
"eventId": 3,
"eventType": "activity_task_completed",
"timestamp": "2025-01-15T10:00:02.300Z",
"details": {
"scheduledEventId": 2,
"duration": "2.250s",
"result": {
"confidence": 0.92,
"flags": []
}
}
},
{
"eventId": 4,
"eventType": "workflow_execution_completed",
"timestamp": "2025-01-15T10:00:02.350Z",
"details": {
"result": {
"approved": true,
"analysis": { "confidence": 0.92 }
}
}
}
],
"summary": {
"totalEvents": 4,
"duration": "2.350s",
"status": "completed"
}
}

Each event is read from the durable execution log. Activity results are checkpointed and each activity executes once, so the history reflects exactly what happened.

Verbose mode adds nested children arrays for orchestrator workflows, where each child carries its own full event sequence. Use maxDepth to limit recursion for deeply nested orchestrations.

GET /api/workflow-states/:workflowId/envelopes

Returns what went in and what came out. The input is a single field read, available for the life of the job; the output is a single state read that returns immediately. The call stays cheap on the largest jobs.

Auth: Requires builder access.

Example request

Terminal window
curl https://lt.acme.dev/api/workflow-states/reviewContent-a1b2c3d4/envelopes \
-H "Authorization: Bearer $LT_TOKEN"

Response 200 (running)

{
"workflow_id": "reviewContent-a1b2c3d4",
"status": "running",
"input": { "data": { "contentId": "c-1" }, "metadata": { "source": "dashboard" } },
"output": null
}

Response 200 (completed)

{
"workflow_id": "reviewContent-a1b2c3d4",
"status": "completed",
"input": { "data": { "contentId": "c-1" }, "metadata": { "source": "dashboard" } },
"output": { "type": "return", "data": { "approved": true } }
}
  • input: the workflow’s input envelope, exactly as invoked. A one-argument workflow (the Long Tail convention) answers the envelope itself; a multi-argument workflow answers the args array.
  • output: the workflow’s return envelope, or null while the run is in flight (status: "running"), which makes this endpoint a natural polling body. A failed run answers status: "failed", output: null, and an error message.

Response 404: the workflow does not exist or its data has expired.

GET /api/workflow-states/:workflowId/status

Returns only the numeric status, for lightweight polling.

Auth: Requires builder access.

Example request

Terminal window
curl https://lt.acme.dev/api/workflow-states/reviewContent-a1b2c3d4/status \
-H "Authorization: Bearer $LT_TOKEN"

Response 200

{ "workflow_id": "reviewContent-a1b2c3d4", "status": 0 }
Value Meaning
0 Complete
Positive Running
Negative Interrupted
GET /api/workflow-states/:workflowId/state

Returns the current internal job state: the HotMesh representation of where the workflow is in its execution graph. For completed workflows, this is the final output.

Auth: Requires builder access.

Example request

Terminal window
curl https://lt.acme.dev/api/workflow-states/reviewContent-a1b2c3d4/state \
-H "Authorization: Bearer $LT_TOKEN"

Response 200

HotMesh job state object. Its structure depends on the workflow’s current execution point.

The same export data is available directly through the Durable client, without the HTTP API:

import { Durable } from '@hotmeshio/hotmesh';
const client = new Durable.Client({ connection });
const handle = await client.workflow.getHandle(
taskQueue,
workflowName,
workflowId,
);
// Structured execution history
const execution = await handle.exportExecution({
exclude_system: true,
});
// Raw state export with facet filtering
const state = await handle.export({
allow: ['data', 'status'],
});
// Status semaphore
const status = await handle.status();
// Current state snapshot
const snapshot = await handle.state(true);
GET /api/workflows/cron/status

Lists every cron-configured workflow and whether each is actively running.

Example request

Terminal window
curl https://lt.acme.dev/api/workflows/cron/status \
-H "Authorization: Bearer $LT_TOKEN"

Response 200

{
"schedules": [
{
"workflow_type": "dailyReport",
"cron_schedule": "0 9 * * *",
"description": "Generate daily report",
"task_queue": "long-tail",
"invocable": true,
"active": true,
"envelope_schema": null
}
]
}
POST /api/workflows/:workflowId/terminate

Interrupts a running workflow. The workflow terminates immediately, and HotMesh cancels any pending escalations tied to it.

Auth: Requires builder access.

Path parameters

Parameter Description
workflowId HotMesh workflow ID

Example request

Terminal window
curl -X POST https://lt.acme.dev/api/workflows/reviewContent-a1b2c3d4/terminate \
-H "Authorization: Bearer $LT_TOKEN"

Response 200

{ "terminated": true, "workflowId": "reviewContent-a1b2c3d4" }
Method Path Auth Description
GET /workers any List active in-memory workers with registration status
GET /discovered any Unified list of workers, entities and configs
GET /cron/status any List cron-configured workflows and active status
GET /invocable any The caller’s invokable workflows with tier
GET /config any List all workflow configurations
GET /:type/config any Get a single workflow configuration
PUT /:type/config admin Create or replace a workflow configuration
DELETE /:type/config admin Delete a workflow configuration (cascade)
GET /:type/input-lookups RBAC Resolve the config’s pinned knowledge lookups (invoke predicate)
POST /:type/invoke RBAC Invoke a workflow (requires invocable: true)
GET /:workflowId/status builder Workflow status
GET /:workflowId/result builder or run owner Get workflow result (200 if complete, 202 if running)
POST /:workflowId/terminate builder Terminate a running workflow
GET /:workflowId/export builder Raw state export (convenience alias)
Method Path Auth Description
GET /:workflowId builder Raw state export with facet filtering
GET /:workflowId/execution builder or run owner Structured execution history
GET /:workflowId/envelopes builder Input and output envelopes
GET /:workflowId/status builder Status semaphore
GET /:workflowId/state builder Current workflow state snapshot