Skip to content
Talk to our solutions team

Workflows API

Starting, signalling, suspending and resuming long-running processes, plus the admin surface.

For concepts and configuration see the block documentation.

EndpointPurpose
POST /workflow/startBegin an instance
GET /workflow/statusWhere an instance has reached
POST /workflow/signalDeliver a signal — addressed to one instance
POST /workflow/eventDeliver an event — broadcast to instances waiting on it
POST /workflow/resumeResume a suspended instance
POST /workflow/cancelStop an instance
GET /workflow/logsExecution history for an instance
GET /workflow/configDefinitions loaded for this tenant
GET /workflow/queueQueued work

Signal or event? A signal is addressed to one instance and usually carries a human decision — you send it because you know which instance you are answering. An event is broadcast and wakes whichever instances are waiting on it — you send it because a fact changed. Choosing wrong is the usual cause of an instance that hangs forever.

GET /workflow/config is worth checking after a deploy: a definition that failed to load produces no error until something tries to use it.

EndpointPurpose
GET /admin/agentsConnected workers
GET /admin/agents/{id}One worker
GET /admin/instancesRunning instances
GET /admin/queueThe work queue
GET /admin/queue/{id}One queued item

/admin/instances is the first place to look when a process appears stuck. An instance in a wait state is usually correct — waiting for a signal nobody sent — and telling that apart from a wedged instance is what the endpoint is for.

Every route requires a bearer token. One route also accepts an API key:

RouteAccepts
GET /workflow/configAn API key or a bearer token
Everything elseA bearer token only

A missing or invalid token is 401 with a plain-text body (Unauthorized), not the JSON error envelope — branch on the status before parsing.

Authentication only proves who you are. Each /workflow/* route is additionally gated by a per-tenant access rule, evaluated as JavaScript, and each route has its own rule name:

RouteRule name
POST /workflow/startworkflow.start
POST /workflow/resumeworkflow.resume
POST /workflow/eventworkflow.resume
POST /workflow/signalworkflow.signal
POST /workflow/cancelworkflow.cancel
GET /workflow/statusworkflow.status
GET /workflow/logsworkflow.logs
GET /workflow/configworkflow.config
GET /agentsagents.list
GET /workflow/queuequeue.status
DELETE /workflow/queue/{id}queue.cancel

Lookup falls back: the named rule, then authorization.admin, then the service default. Rule code receives user.id, user.email, user.roles, user.is_superadmin, tenant and action, and returning a truthy value allows the request.

A denial is 403 with {"message": "access denied"} — also not the standard envelope.

The /admin/* routes do not use the rule engine. They require a superadmin token and are checked separately, so a tenant access rule can neither grant nor revoke them.

Every request carries the four platform tenancy headers — X-Customer, X-Product, X-Env and X-Tenant. They are the partition key for storage, quotas and audit, and they also select which tenant’s access rules apply, so a request without them is rejected rather than served against a default tenant.

StatusBodyRaised by
400JSON error envelopeRequest parse and validation — the most common failure by far
401Plain text UnauthorizedMissing or invalid token
403{"message": "access denied"}An access rule denied the request, or no rules exist in deny-by-default mode
500JSON error envelopeUnexpected server error

Three shapes across four statuses. A client must branch on the status code first — only 400 and 500 carry the standard envelope.