Start a run of this workflow
workflow:runCreates a run and hands it to a worker. This returns 202 Accepted — the run has been ACCEPTED, not finished. Nothing has executed when you get the response: the run comes back with status: "pending" and no finishedAt, no durationMs, no steps. Take data.id — that is the run id — and then either poll GET /api/runs/{id} or subscribe to GET /api/runs/{id}/stream (SSE) for progress. Step output lands at steps[].outputData, keyed by steps[].nodeId (the step's stable name), on the run detail.
The request BODY is the trigger payload. Whatever JSON object you POST is handed to the flow as its trigger data and reshaped to look like a real delivery from that trigger's kind, so a webhook flow reads it as {{trigger.body.…}}, gains {{trigger.headers}}/{{trigger.query}}/{{trigger.method}}, and a schedule flow gets a schedule-shaped payload. The body is optional; an empty/absent body runs with an empty payload. To bypass reshaping and supply trigger data ALREADY in delivery shape (replaying a past run's exact triggerData, or a saved test payload), include "__shaped": true at the top level — that key is stripped and the rest is passed through verbatim.
That is exactly why environment is a QUERY parameter and not a body field. The body belongs to the caller; a top-level environment key in it would collide with the caller's own payload, and a __shaped replay carrying that key would both lose the key and silently flip the run's environment.
environment
production— executes the PUBLISHED snapshot (latestVersionId), recordstriggerType: "api", obeys the workflow'sconcurrencyLimit, and appears inGET /api/runsby default. Publishing is required first: if the workflow is notactive, or has no published version, the call is 409CONFLICTwith the message "Publish this workflow before running it in production". If the published version exists but cannot be loaded, it is also 409 ("…could not be loaded — republish it") rather than silently falling back to the draft.test— executes the live DRAFT, recordstriggerType: "manual", ignores the concurrency limit (so the editor stays responsive), and is filtered out of the defaultGET /api/runs.- Omitted — resolves to
productionwhen the workflow isactiveAND has no unpublished changes; otherwisetest. PassingfromNodeorversionIdforces the default totest, because both are rehearsals by construction. - Any other value is a 400.
fromNode / versionId / retryOf
fromNode— a PARTIAL run: execution starts at that step, with upstream values seeded from earlier test data rather than executed. It must name a step on the TOP-LEVEL chain (not inside a branch arm or loop body) — an interior or unknown name is 422. It is test-only: combined withenvironment=productionit is a 400. The run records it asstartedFromStep.versionId— replays a specific published snapshot instead of the draft ("retry as it ran"). The version must belong to THIS workflow or it is 404. Underenvironment=productionit must be omitted or equallatestVersionId; anything else is 400, because a production run always executes the published version.retryOf— records lineage: this run is a retry of that run. The referenced run must belong to THIS workflow or it is 404. It changes nothing about what executes — passversionId,fromNodeand the originaltriggerDatayourself to actually reproduce a run.
The definition is parsed and every piece it names is checked against what the live worker fleet can run BEFORE a run row is created, so an unrunnable flow is 422 and leaves no pending run behind.
Pass ?wait= to receive the finished run in this same call rather than a run id to poll.
Authorization
bearerAuth An API token: Authorization: Bearer grt_…. Mint one in the app under Settings → Workspace → API tokens; the raw value is shown once. Scopes confine the token — see x-permission on each operation.
In: header
Path Parameters
Workflow id (UUID).
uuidQuery Parameters
Which definition executes and how the run is labelled. Omit to let the server choose (production for a clean published workflow, test otherwise). It is a query parameter because the request body is the trigger payload and a body field would collide with it.
Value in
- "test"
- "production"
Start a PARTIAL run at this step instead of the trigger. Must be a top-level step name (nextAction chain of the trigger), not a step inside a branch arm or loop body. Test-only — rejected with environment=production.
Execute this published version's snapshot instead of the draft. Must be a version of this workflow. Under environment=production it must be omitted or equal the workflow's latestVersionId.
uuidRecord this run as a retry of that run id (lineage only — it does not copy the original's payload, version or start step). Must be a run of this workflow.
uuidHold the connection for up to this many seconds (0-30) and answer with the FINISHED run instead of a 202. Omit it, or send 0, for the historical behaviour.
200 means the run reached a terminal state inside the budget — the body is the run with every step's output, so a failure needs no separate shape: read status and the failing step. 202 means it is still going, including when it PAUSED on a delay or an approval; poll GET /api/runs/{id}. The run itself is never bounded by this — it keeps executing past the budget.
0 <= value <= 30Header Parameters
Opt-in replay protection, ≤255 characters. A retry carrying the same key and the same method+path+query+body replays the original 202 (same run id) with Idempotency-Replayed: true instead of starting a second run. The QUERY STRING is part of the fingerprint, so the same key with ?environment=production and ?environment=test is a different request and is refused with 422 rather than replayed. Records live 24h.
length <= 255Request Body
application/json
The trigger payload. Any JSON object; it is reshaped into the delivery shape of this workflow's trigger kind unless __shaped is true.
TypeScript Definitions
Use the request body type in TypeScript.
The trigger payload for a run. Any JSON object; it is reshaped to the trigger's delivery shape unless __shaped is true. There is NO environment field here — that is a query parameter precisely so it cannot collide with your payload.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/api/workflows/497f6eca-6276-4993-bfeb-53cbbbba6f08/run" \ -H "Content-Type: application/json" \ -d '{ "orderId": "A-1001", "amount": 42.5 }'{ "data": { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "workflowId": "43c4fa9b-0cbc-4b57-a121-9d7d46a3eaa4", "workspaceId": "ef0efa32-d1c1-43d4-a5e2-fe7b4f00403c", "orgId": "25b2c2d5-a7fc-47d0-89e4-8709a1560bfa", "status": "pending", "triggerType": "api", "triggerData": null, "startedAt": "2019-08-24T14:15:22Z", "finishedAt": "2019-08-24T14:15:22Z", "durationMs": 0, "errorMessage": "string", "tags": [ "string" ], "environment": "test", "versionId": "14707576-2549-4848-82ed-f68f8a1b47c7", "versionNumber": 0, "executedVersionId": "4d3e9121-6455-4ca4-b3e7-67df52d19c9f", "executedVersionNumber": 0, "startedFromStep": "string", "retryOfRunId": "d0a9e625-c445-46be-b052-60aba1a6d053", "steps": [ {} ] }}