The Workflow Editor can provide the JSON definition behind every workflow. That same JSON is what the Workflows API consumes for create_workflow, update_workflow, and run. Pair it with the Workflow ID and you can operate a workflow entirely from your own code — no UI required.
The Workflow Definition JSON
The JSON shown in the editor’s Workflow API Reference modal is the canonical, server-side representation of a workflow.
A workflow definition is a directed graph of blocks and edges:
{
"workflow_name": "Enrich inbound leads",
"workflow_description": "Webhook → enrich people → outgoing webhook",
"workflow_definition": {
"blocks": [
{
"block_id": "1f2c3a4d-...-source",
"sequence_number": 1,
"block_type": "io",
"block_name": "webhook",
"specs": {
"input_schema": { "email": "string", "company": "string" },
"dataframe_type": "LEAD"
}
},
{
"block_id": "2a3b4c5d-...-enrich",
"sequence_number": 2,
"block_type": "enrichment",
"block_name": "lead_enrichment",
"specs": {
"return_fields": { "title": "string", "linkedin_url": "string" }
}
},
{
"block_id": "3a4b5c6d-...-deliver",
"sequence_number": 3,
"block_type": "output",
"block_name": "outgoing_webhook",
"specs": {
"url": "https://example.com/hooks/sixtyfour",
"timeout_seconds": 10
}
}
],
"edges": [
{ "from_block_id": "1f2c3a4d-...-source", "to_block_id": "2a3b4c5d-...-enrich" },
{ "from_block_id": "2a3b4c5d-...-enrich", "to_block_id": "3a4b5c6d-...-deliver" }
]
}
}
Field reference
| Field | Type | Description |
|---|
workflow_name | string | Human-readable name shown in the editor and GET /workflows. |
workflow_description | string | Free-form description. |
workflow_definition.blocks | array | All processing steps in the graph. Order is irrelevant — execution follows edges. |
workflow_definition.edges | array | Directed connections (from_block_id → to_block_id). Defines data flow. |
id | string (optional) | Pre-generated UUID for the workflow. Omit to let the server assign one. |
Each block has the following shape:
| Field | Type | Description |
|---|
block_id | string (optional) | UUID. The server normalizes missing or non-UUID IDs and rewrites edges to match. |
sequence_number | integer | UI ordering hint. Does not affect runtime execution. |
block_type | string | Free-form category (io, transform, enrichment, signal, output). The runtime ignores this for dispatch. |
block_name | string | The executor identifier. This is what the runtime uses to resolve a block. See Workflow Blocks Reference for the full list. |
specs | object | Block-specific configuration. Schema varies per block_name. |
block_name selects the executor — renaming it will break execution with Unknown block type: .... block_type is a free-form label; renaming it is harmless. Treat block_name as immutable when hand-editing JSON.
Get the JSON for an existing workflow
Two ways to get the JSON:
- From the editor: open a workflow in app.sixtyfour.ai, click the menu next to Run, choose View Workflow Definition, and copy the JSON. The Workflow ID appears at the top of the modal.
- From the API:
GET /workflows/{workflow_id} returns the same definition under workflow_definition.
curl -X GET "https://api.sixtyfour.ai/workflows/WORKFLOW_ID" \
-H "x-api-key: YOUR_API_KEY"
The response includes id, name, description, status, and the full workflow_definition graph. The workflow_definition field can be passed directly back into create_workflow or update_workflow without modification.
Programmatic flows
The flows below all use the same JSON body shape (CreateWorkflowRequest).
Run an existing workflow
Pair a stored Workflow ID with POST /workflows/run to start a job from any client. The workflow lives server-side; your code triggers it and consumes results.
import os, requests
BASE = "https://api.sixtyfour.ai"
HEADERS = {"x-api-key": os.environ["SIXTYFOUR_API_KEY"], "Content-Type": "application/json"}
resp = requests.post(
f"{BASE}/workflows/run",
params={"workflow_id": "WORKFLOW_ID"},
headers=HEADERS,
json={"webhook_payload": [{"email": "ada@example.com", "company": "Acme"}]},
)
resp.raise_for_status()
print("job_id:", resp.json()["job_id"])
Two optional body fields parameterize each run:
| Field | Purpose |
|---|
webhook_payload | Input rows for workflows whose source block is webhook. List or single object. |
specs_override | Overrides the first block’s specs for this run only. Use when one workflow serves many parameterized inputs. |
The full request/response shape and polling pattern live in Workflow Execution.
Workflows whose source block is
read_csv cannot be triggered via API. Use a workflow that starts with
webhook — see
Incoming Webhooks.
Create a workflow from JSON
POST the definition to create_workflow to register a new workflow server-side. The response includes the assigned id, which you then pass to run.
curl -X POST "https://api.sixtyfour.ai/workflows/create_workflow" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d @workflow.json
Choose your own Workflow ID
You can pass an optional id (a valid UUID) in the request body to choose your own Workflow ID instead of letting the server assign one. The endpoint returns 409 if that ID is already taken.
Deploy + Run from CI
A typical deploy script saves the workflow definition with update_workflow, then triggers a run. update_workflow creates the workflow if workflow_id doesn’t exist and updates it otherwise, so the same script is safe to run on every deploy.
import os, json, requests
BASE = "https://api.sixtyfour.ai"
HEADERS = {"x-api-key": os.environ["SIXTYFOUR_API_KEY"], "Content-Type": "application/json"}
WORKFLOW_ID = os.environ["WORKFLOW_ID"]
with open("workflow.json") as f:
body = json.load(f)
u = requests.post(
f"{BASE}/workflows/update_workflow",
params={"workflow_id": WORKFLOW_ID},
headers=HEADERS,
json=body,
)
u.raise_for_status()
r = requests.post(
f"{BASE}/workflows/run",
params={"workflow_id": WORKFLOW_ID},
headers=HEADERS,
json={"webhook_payload": [{"email": "ada@example.com", "company": "Acme"}]},
)
r.raise_for_status()
print("running:", r.json()["job_id"])
update_workflow runs the same schema and edge checks as create_workflow and rejects invalid graphs with 400 before saving — so the save step doubles as a validation gate. To deliver completed run results to your own URL, add an outgoing_webhook block to the workflow — see Outgoing Webhooks. Polling, result download, and cancellation are documented in Workflow Execution.
Authentication
All programmatic endpoints accept either an API key or an OAuth client credential. webhook_payload and specs_override require machine authentication (API key or OAuth) — they are rejected for JWT (browser session) requests.
The credential also determines ownership: the JSON definition has no org_id field, so a workflow created with a given API key belongs to that key’s organization. To deploy the same JSON into a different organization, POST it using that organization’s API key.
| Auth method | When to use | Header |
|---|
| API key | Server-to-server scripts, CI, single-tenant deploys | x-api-key: YOUR_API_KEY |
| OAuth client credentials | Multi-tenant integrations, third-party apps acting on behalf of a user | Authorization: Bearer ACCESS_TOKEN |
See Get API Key for API keys and OAuth Clients for OAuth setup.