Appearance
The Run API
Every flow you build is also a live HTTP endpoint. This page is the reference for calling one: the URL shape, which HTTP methods work, how request inputs reach your Start node, authentication, how the End node shapes the response, tracing, rate limits, and status codes.
The URL
A flow is called at:
/api/run/<projectId>/<path-to-your-flow-file>[/<extra path params>]<projectId>— the ID of the project the flow lives in.<path-to-your-flow-file>— the folder-and-file path, slugified. FlowRunner lowercases each folder and file name and replaces runs of non-alphanumeric characters with a single hyphen. A file namedCreate Userinside a folderUsersresolves atusers/create-user.<extra path params>— optional positional segments consumed by the Start node's declared path inputs (see below).
bash
curl https://your-host/api/run/proj_abc/users/create-userNOTE
Folders with a blank or symbol-only name are transparent — they don't add a segment. If two Start nodes want different HTTP methods on the same file, they share one URL and are told apart by the request method.
Methods
GET, POST, PUT, PATCH, and DELETE are all handled. When a request arrives, FlowRunner looks for a Start node on that file whose configured method matches (Start nodes default to GET). If no Start node matches the method, you get a 404.
OPTIONS is answered directly with 204 and CORS headers — it never runs a flow. All responses carry permissive CORS (Access-Control-Allow-Origin: *) so a browser front-end can call a flow directly.
Inputs: four sources
A Start node declares its inputs in four buckets. The Run API fills each bucket from a different part of the request, validates it against the node's schema, then merges everything into the values your flow sees.
| Bucket | Comes from | Notes |
|---|---|---|
| path | Positional trailing URL segments | Bound in declared order. Extra segments beyond what's declared → 404. |
| query | The URL query string (?a=1&b=2) | |
| headers | Request headers | Looked up case-insensitively. |
| body | The JSON request body | Only read for non-GET/HEAD methods, and only when the Start node declares body fields. Must be application/json. |
If any bucket fails validation (a required field missing, a wrong type, or malformed JSON), the request stops before the flow runs and returns 400 with the list of problems:
json
{ "ok": false, "errors": ["body.email is required", "query.count must be a number"] }Inside the flow, merged inputs are available under the Start node's name — for a Start node named Start, a field email reads as start.email.
Authentication
Auth is checked before any input parsing. A Start node can require one of four schemes, and the expected secret is resolved from the workspace secrets vault (so you store ${secrets.API_TOKEN}, not a raw token).
| Scheme | Client sends | On failure |
|---|---|---|
none | nothing | — |
bearer | Authorization: Bearer <token> | 401 + WWW-Authenticate: Bearer |
basic | Authorization: Basic <base64 user:pass> | 401 + WWW-Authenticate: Basic |
apiKey | a header (default X-API-Key) | 401 |
Credentials are compared in constant time. Auth is fail-closed: if a scheme is configured but its expected secret is empty or unresolved, every request is rejected rather than let through.
bash
curl https://your-host/api/run/proj_abc/orders/create \
-H "Authorization: Bearer my-token" \
-H "Content-Type: application/json" \
-d '{"sku":"ABC","qty":2}'Shaping the response
What the caller gets back is decided by the End node the flow reaches:
- Status code — the End node's configured status (any value
100–599; defaults to200). - Body — the End node's response body, composed field-by-field from your flow's data. Each field can be a literal or a reference to a value produced upstream (for example the output of an HTTP or MongoDB node).
If the flow finishes without reaching an End node, you get a 200 with a diagnostic echo of the inputs instead:
json
{ "ok": true, "inputs": { "email": "a@b.com" } }Tracing with ?_trace
Add ?_trace=1 to any call to get a step-by-step execution trace. The trace lists every node that ran, in order, with timing, the outgoing port it chose, iteration counts (for ForEach), and any error. It's returned two ways:
- Inlined into the JSON body under a
_tracekey. - URL-encoded in an
X-Flow-Traceresponse header.
bash
curl "https://your-host/api/run/proj_abc/users/create-user?_trace=1"TIP
?_trace is the fastest way to see where a flow went wrong in production. The same trace is stored for every run and shown visually in run history.
Rate limits
Calls are rate-limited per client IP: 60 requests per 60 seconds. Over the limit you get a 429 with a Retry-After header (in seconds).
json
{ "ok": false, "errors": ["rate limited"] }NOTE
This is a flat per-IP ceiling today. Per-project plan quotas are planned but not yet in place.
Status codes
| Code | Meaning |
|---|---|
200 (or your End node's code) | Flow completed. Body is the End node's response, or an inputs echo if no End was reached. |
204 | Answer to a CORS OPTIONS preflight. |
400 | Input validation failed. errors lists what was wrong. |
401 | Missing or invalid credentials. |
404 | No such project, flow file, or method — or too many trailing path segments. |
429 | Rate limit exceeded. See Retry-After. |
500 | The flow ran but hit an error. Body includes node (the failing node's ID). |
A 500 body looks like this (with _trace added when requested):
json
{ "ok": false, "errors": ["http: network down"], "node": "node_7" }See also
- HTTP triggers — configuring the Start node in the editor
- OpenAPI — a generated spec for every endpoint in a project
- Run history — the stored trace of every call
- Errors & try/catch — how a node failure becomes a
500or routes to a handler branch