Browse the docs
Documentation
Workflow API: run workflows from your own code
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 $WORFILO_API_URL/v1/workflows/WORKFLOW_ID/runs \
-H "Authorization: Bearer $WORFILO_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "input": "Summarise this ticket" }'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.
{
"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 $WORFILO_API_URL/v1/workflows/WORKFLOW_ID/runs \
-H "Authorization: Bearer $WORFILO_API_KEY" \
-F 'input={"customer": "Acme"}' \
-F invoice=@invoice.pdfUpload first: POST /v1/files returns a ref. Pass it in the input of one or more runs.
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
timeoutseconds (30 by default, at most 60). A run that is still going answers 202 with astatus_url. - Poll: send
"wait": falseto get a 202 straight away, thenGET /v1/runs/RUN_IDwith the same key untilstatusissucceeded,failedorcancelled. - Stream: send
"stream": truefor Server-Sent Events. Agent replies arrive astokenevents while they are written, steps asnode.startedandnode.succeeded, and the last event isrun.completedwith 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.
Keep reading
- Publishing and versions: draft vs publishedPublish a Worfilo workflow to freeze its draft into a numbered version. Triggers and the workflow API run that version while you keep editing the draft.
- Credentials and securityHow Worfilo protects API keys, app connections and MCP secrets: encryption at rest, redaction in run history, SSRF protection and sandboxed templates.
- Execution controls: retries, timeouts, errorsControl how Worfilo runs AI workflows: per-node retries with backoff, timeouts and error modes, and run-wide parallelism, timeouts and token caps.
Build it on the canvas
Create a free account, describe the workflow or wire it yourself, and run it in the browser.