Skip to main content
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.
To build workflows in the UI, see Building Workflows.

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

FieldTypeDescription
workflow_namestringHuman-readable name shown in the editor and GET /workflows.
workflow_descriptionstringFree-form description.
workflow_definition.blocksarrayAll processing steps in the graph. Order is irrelevant — execution follows edges.
workflow_definition.edgesarrayDirected connections (from_block_idto_block_id). Defines data flow.
idstring (optional)Pre-generated UUID for the workflow. Omit to let the server assign one.
Each block has the following shape:
FieldTypeDescription
block_idstring (optional)UUID. The server normalizes missing or non-UUID IDs and rewrites edges to match.
sequence_numberintegerUI ordering hint. Does not affect runtime execution.
block_typestringFree-form category (io, transform, enrichment, signal, output). The runtime ignores this for dispatch.
block_namestringThe executor identifier. This is what the runtime uses to resolve a block. See Workflow Blocks Reference for the full list.
specsobjectBlock-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
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:
FieldPurpose
webhook_payloadInput rows for workflows whose source block is webhook. List or single object.
specs_overrideOverrides 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.
Python
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 methodWhen to useHeader
API keyServer-to-server scripts, CI, single-tenant deploysx-api-key: YOUR_API_KEY
OAuth client credentialsMulti-tenant integrations, third-party apps acting on behalf of a userAuthorization: Bearer ACCESS_TOKEN
See Get API Key for API keys and OAuth Clients for OAuth setup.