Skip to content

Documentation

Workflow API: run workflows from your own code

Updated September 21, 2026

Every workflow is also an API. Publish it, create an API key, and your backend can send it input and read its output in one request. Each workflow has a Playground, a chat that runs it the same way the API does, with ready-to-copy cURL and Python beside it. For complete clients that wait, poll and stream, see the examples on GitHub in TypeScript, Python and curl.

Create an API key

Open API keys in the sidebar and choose Create key. A key can run all of your workflows or only the ones you pick. It is shown once: Worfilo keeps only a hash and its first few characters, so copy it straight into an environment variable.

Call a workflow

Send the key as a bearer token and the workflow's ID in the path. Only the published version runs, so edits in the editor never reach callers until you publish. The playground shows your exact URL and ID.

cURL
curl $WORFILO_API_URL/v1/workflows/WORKFLOW_ID/runs \
  -H "Authorization: Bearer $WORFILO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "input": "Summarise this ticket" }'
Python
import os

import requests

response = requests.post(
    f"{os.environ['WORFILO_API_URL']}/v1/workflows/WORKFLOW_ID/runs",
    headers={"Authorization": f"Bearer {os.environ['WORFILO_API_KEY']}"},
    json={"input": {"ticket_id": 4812, "priority": "high"}},
    timeout=70,
)
run = response.json()
print(run["status"], run["output"])

Input and output

input becomes the run's trigger payload. An object is used as it is, so { "ticket_id": 4812 } is read as {{ trigger.ticket_id }}. Text becomes { "message": ... }, read as {{ trigger.message }}, which suits chat-style workflows.

The reply's output is the value of the workflow's Output node. With several Output nodes it is an object keyed by node ID.

Response
{
  "run_id": "495f5053-...",
  "workflow_id": "c43324cb-...",
  "status": "succeeded",
  "output": { "summary": "Customer cannot sign in since the update" },
  "error": null,
  "total_tokens": 812,
  "duration_ms": 2140,
  "status_url": null
}

Sending files

Workflows with a Parse PDF node take PDFs. There are two ways to send one. Either way, the input gets a file reference such as { "$file": "...", "filename": "invoice.pdf" }, which the node reads with {{ trigger.invoice }}.

In one request: send multipart/form-data instead of JSON. Put the input JSON in an input part. Each file part is uploaded and added to the input under its own name.

cURL, multipart
curl $WORFILO_API_URL/v1/workflows/WORKFLOW_ID/runs \
  -H "Authorization: Bearer $WORFILO_API_KEY" \
  -F 'input={"customer": "Acme"}' \
  -F invoice=@invoice.pdf

Upload first: POST /v1/files returns a ref. Pass it in the input of one or more runs.

cURL, upload then run
ref=$(curl -s $WORFILO_API_URL/v1/files \
  -H "Authorization: Bearer $WORFILO_API_KEY" \
  -F file=@invoice.pdf | jq -c .ref)

curl $WORFILO_API_URL/v1/workflows/WORKFLOW_ID/runs \
  -H "Authorization: Bearer $WORFILO_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"input\": {\"invoice\": $ref}}"

Files must be PDFs up to 25 MB, at most 5 per request. They are visible only to the key's account and are deleted after 24 hours. The multipart form takes wait, timeout and stream as fields, with the same meaning as in JSON.

Waiting, polling and streaming

  • Wait (the default): the request holds until the run ends, up to timeout seconds (30 by default, at most 60). A run that is still going answers 202 with a status_url.
  • Poll: send "wait": false to get a 202 straight away, then GET /v1/runs/RUN_ID with the same key until status is succeeded, failed or cancelled.
  • Stream: send "stream": true for Server-Sent Events. Agent replies arrive as token events while they are written, steps as node.started and node.succeeded, and the last event is run.completed with the full result.

Errors and limits

Errors come back as { "detail": "..." } with one readable sentence. A run that starts but fails is not an error: it answers 200 with "status": "failed" and the reason in error.

  • 401: the key is missing, wrong or revoked.
  • 403: the key is limited to other workflows.
  • 404: no workflow with that ID belongs to the key's account.
  • 409: the workflow has not been published.
  • 429: more than 60 runs a minute on one key. Wait for the seconds in Retry-After.

Test it in the playground

Open a workflow and choose Playground. Each message runs the workflow once, against the published version or your current draft. Send it as Text (it arrives as {{ trigger.message }}), as Inputs (a form with one row for each variable your prompts read, already filled in with their names) or as JSON. Replies show the output, the time and tokens it took, and a link to the run. The panel beside the chat holds the endpoint, the workflow ID and cURL and Python samples built from your last message. Playground runs appear in run history like any other.

Build it on the canvas

Create a free account, describe the workflow or wire it yourself, and run it in the browser.