Workflow Definition
A workflow is a JSON or YAML document. It lists the HTTP steps you want run, and how they connect.
Structure
{
"name": "kebab-case-name",
"version": 1,
"schemas": {},
"triggers": [{"type": "http", "schema": "InputSchema"}],
"steps": {}
}
| Field | Required | Description |
|---|---|---|
name |
Yes | Lowercase kebab-case identifier |
version |
Yes | Positive integer |
schemas |
No | Named JSON Schema definitions |
triggers |
Yes | Array of trigger configs |
steps |
Yes | Object of step definitions |
Steps
"charge": {
"after": ["validate"],
"when": "steps.validate.response.status == 200",
"request": {
"method": "POST",
"url": "https://api.stripe.com/v1/charges",
"headers": {"authorization": "Bearer {{ secrets.STRIPE_KEY }}"},
"body": {"amount": "{{ steps.validate.response.body.total }}"}
},
"retry": {"on": [500, 502, 503], "max": 3},
"compensate": {
"method": "POST",
"url": "https://api.stripe.com/v1/refunds"
}
}
| Field | Description |
|---|---|
after |
Step IDs this step depends on |
when |
Expression that must be true to execute |
request |
HTTP request (method, url, headers, body) |
response |
Response config (timeout, schema) |
retry |
Retry on status codes with backoff |
compensate |
Rollback request if a later step fails |
wait |
Pause for an external signal |
strategy |
Fan-out, batch, race, or scatter |
Patterns
Linear chain. Steps run in sequence — chain them with after.
Parallel branches. Give two steps the same after and they’ll run concurrently.
Fan-out. Work through a list with bounded concurrency:
"strategy": {"type": "fan_out", "over": "steps.get.response.body.items", "concurrency": 5}
Wait for a signal. Pause the run until something external pings you:
"wait": {"signal": "approved", "timeout": "24h", "on_timeout": "reject"}
Conditional steps. Use when to skip a step:
"process": {
"when": "trigger.body.type == \"order\"",
"request": { ... }
}
If when evaluates to false, the step is skipped.
A bare when string dispatches by prefix:
-
Starts with
return→ Lua (use this when you need crypto, string ops, etc.) -
Anything else → path expression (
==,!=,in,and/or/not, dot-paths,null)
To pick a runtime explicitly, use the block form { "expr": "...", "lang": "lua" | "path" | "jsonpath" }.
Trigger guards. Triggers can have when too, to reject requests before a run even starts. Webhook signature checks need Lua for crypto.hmac, so prefix with return:
triggers:
- type: http
when: |
return trigger.headers['x-signature'] ==
crypto.hex(crypto.hmac('sha256', secrets.WEBHOOK_SECRET, trigger.raw_body))
Returns 403 if the condition is false. Handy for webhook signature validation.
Trigger validation. Point at a schema to validate the incoming payload:
"triggers": [{"type": "http", "schema": "OrderInput"}]
Webhook callbacks
When an external service needs to call back into your run (payment providers love this), it needs to authenticate. Every run gets its own short-lived session token, exposed in expressions as {{ run.session }}. It lasts 24 hours and carries the tenant’s encryption context.
Drop it into webhook URLs as a query parameter:
webhookUrl: "https://dispatched.work/workflows/my_webhook?dispatched_session={{ run.session }}"
The engine accepts ?dispatched_session= as an alternative to the Dispatched-Session header, so a service that can’t set custom headers can still authenticate.
Editor assistance
A JSON Schema for workflow files lives at /schemas/workflow.schema.json. Point your editor at it and you’ll get completion and validation as you write.
JSON — add $schema at the top:
{
"$schema": "https://dispatched.work/schemas/workflow.schema.json",
"name": "my-workflow",
"version": 1
}
YAML — drop a yaml-language-server modeline on the first line (you’ll need the YAML extension in VS Code, or the equivalent elsewhere):
# yaml-language-server: $schema=https://dispatched.work/schemas/workflow.schema.json
name: my-workflow
version: 1
Project-wide in VS Code — match by filename in .vscode/settings.json:
{
"json.schemas": [
{ "fileMatch": ["workflows/*.json"], "url": "https://dispatched.work/schemas/workflow.schema.json" }
],
"yaml.schemas": {
"https://dispatched.work/schemas/workflow.schema.json": ["workflows/*.yaml", "workflows/*.yml"]
}
}
The schema covers structural rules — required fields, step id patterns, HTTP methods, strategy shapes, retry/backoff, wait durations, that kind of thing. Semantic checks (DAG cycle detection, $ref resolution, Lua syntax, cron field counts) stay server-side and run at publish time.