Workflows
Saved runs, ad-hoc runs, and guards
Running workflows
Running workflows, at a glance
Saved runs, ad-hoc runs, and guards
POST /v1/workflows/{id}/runsRequest map4 boundaries
- 01Startsaved or ad-hoc definition
- 02Advancestep state machine
- 03Guardbudget + iterations
- 04Inspectevents + terminal output
Start a saved workflow with POST /v1/workflows/{id}/runs, or run a definition inline (without saving) with POST /v1/workflows/runs by adding a definition (and optional inputs_schema) to the same body. Both return a workflow.run. The body accepts inputs, a default managed-or-external machine_id for task steps, and the budget_cents, max_iterations, and deadline_seconds guards. Optional action_policy is inherited by every task step, retry, recovery, and nested delegation. An Idempotency-Key header is honoured here too, but it deduplicates workflow-run creation only; it does not make every nested machine action exactly once.
Saved and ad-hoc Workflow Runs accept a create-time
action_policy. It is atomically persisted and passed unchanged through task steps, retries, worker recovery, and nested CUA delegation. Budgets, assertions, deadlines, and approvals remain independent controls.Workflow task steps inherit the same external machine id without changing the DSL. Serialize parallel task branches that share one physical display; independent parallel control requires separately enrolled displays. Control-flow-only steps do not need the driver and remain free.
import os, requests
BASE = "https://coasty.ai/v1"
HEADERS = {"X-API-Key": os.environ["COASTY_API_KEY"]}
# POST /v1/workflows/runs runs a definition inline, without saving a workflow.
run = requests.post(
f"{BASE}/workflows/runs",
headers=HEADERS,
json={
"machine_id": "mch_test_0123456789abcdef",
"inputs": {"url": "https://status.example.com"},
"max_iterations": 5,
"definition": {
"steps": [
{
"id": "open",
"type": "task",
"save_as": "page",
"task": "Open {{inputs.url}} and report whether all systems are operational",
},
{
"id": "gate",
"type": "assert",
"condition": {"op": "truthy", "value": "{{page.passed}}"},
},
],
},
},
timeout=30,
).json()
print(run["id"], run["status"]) # object == "workflow.run"Workflow event appends, including terminal frames, and Workflow lifecycle callbacks are currently best-effort in-process notifications. They can be absent if storage or the worker fails after the durable workflow state transition. Reconcile with
GET /v1/workflows/runs/{id}instead of waiting indefinitely for an event or callback.JSON
{
"id": "wfr_5e6f7a8b",
"object": "workflow.run",
"status": "running",
"workflow_id": "wf_1a2b3c",
"workflow_version": 3,
"machine_id": "mch_test_0123456789abcdef",
"inputs": {
"order_id": "ord_4821"
},
"output": null,
"error": null,
"awaiting_human_reason": null,
"awaiting_step_id": null,
"iterations_used": 0,
"spent_cents": 0,
"budget_cents": 500,
"created_at": "2026-06-01T12:00:00Z",
"started_at": "2026-06-01T12:00:01Z",
"finished_at": null,
"request_id": "req_9c8b7a6d"
}