Compose many runs with a versioned JSON DSL
Workflows
Workflows, at a glance
Compose many runs with a versioned JSON DSL
POST /v1/workflows- 01DefineJSON steps + inputs
- 02Versionimmutable run snapshot
- 03Executetasks and control flow
- 04Returnstructured output
A workflow composes many runs into one versioned program, with branching, loops, and guards expressed as a JSON DSL. Each task step is itself an agent run, so a workflow is the way to chain tasks, gate them on conditions, and pass results between them. Workflows are versioned: re-creating the same slug bumps the version, and a PUT does too.
Create one with POST /v1/workflows. The slug must match [a-z0-9_-]. The response is a Workflow carrying an id, a version, and the current dsl_version (2026-06-01).
import os, requests
BASE = "https://coasty.ai/v1"
HEADERS = {"X-API-Key": os.environ["COASTY_API_KEY"]}
definition = {
"steps": [
{
"id": "fetch",
"type": "task",
"task": "Open order {{inputs.order_id}} and read the invoice total",
"save_as": "invoice",
},
{
"id": "check",
"type": "assert",
"condition": {"op": "truthy", "value": "{{invoice.passed}}"},
"message": "Agent failed to read the invoice",
},
{
"id": "branch",
"type": "if",
"condition": {"op": "contains", "left": "{{invoice.result}}", "right": "PAID"},
"then": [{"id": "ok", "type": "succeed", "output": {"state": "paid"}}],
"else": [{"id": "no", "type": "fail", "message": "Invoice not marked paid"}],
},
],
}
# 1. Create the workflow. Re-using the same slug bumps its version.
wf = requests.post(
f"{BASE}/workflows",
headers=HEADERS,
json={
"name": "Invoice reconciliation",
"slug": "invoice-reconcile",
"inputs_schema": {"type": "object", "properties": {"order_id": {"type": "string"}}},
"definition": definition,
},
timeout=30,
).json()
print(wf["id"], "v", wf["version"], wf["dsl_version"])
# 2. Start a run of the saved workflow.
run = requests.post(
f"{BASE}/workflows/{wf['id']}/runs",
headers=HEADERS,
json={"inputs": {"order_id": "ord_4821"}, "machine_id": "mch_test_0123456789abcdef", "budget_cents": 500},
timeout=30,
).json()
print(run["id"], run["status"])A concurrent update based on a stale workflow version fails with 409 CONFLICT. Fetch the workflow again, reapply the intended change to the latest state, and retry.
workflows:read and workflows:write scopes, granted to new keys by default. See the Workflow DSL for the full step and condition catalogue.