Every node a flow can use, what expressions can read, and the limits every run works within. This page is generated from the flows engine itself (version 1.0.0), so it always describes the version that's running.
versionAlways 1.nameLower-case letters, digits and hyphens, unique in your account.descriptionOptional.entryHow the flow starts. An endpoint: { "type": "endpoint", "method": "POST", "path": "...", "public": false, "input": { JSON schema } }. An event flow: { "type": "event", "events": [...], "lists": [...], "when": "...", "ignoreUserMode": false } (see event flows). By hand: { "type": "manual" }.nodesThe nodes: each has an id (letters, digits and underscores), a type, an optional label, and the fields its type takes.edges["from", "to"], or ["from", "to", "port"] from a condition or switch. A flow can't have cycles.helpersOptional: let and function declarations every expression can use.layoutWhere the nodes sit in the editor. It never affects a run.A field of kind expression is written in the write rules language, as a string: "steps.game.data.deckId". A list is a path name or id, written plainly.
Read an item, with the list owner's privileges: guarded values included.
| Field | Kind | What it is |
|---|---|---|
list | list | The list, by id or path name. |
item | expression | The item, by id or alias. |
required | boolean | Fail the flow with 404 if there is no such item, rather than giving null. |
Find items by an index value. Only indexed fields can be searched, so it's always fast.
| Field | Kind | What it is |
|---|---|---|
list | list | The list, by id or path name. |
index | string | The index to search, by path name. It must be a filtering index. |
value | expression | Find items whose indexed value equals this. |
limit | integer | The most items to return. |
order | one of | Oldest first (asc) or newest first (desc). |
Create an item. Variables are substituted and the list's JSON schema is checked, as for any write.
| Field | Kind | What it is |
|---|---|---|
list | list | The list, by id or path name. |
data | expression | The item's data. |
identityId | expression | The identity that owns the new item, e.g. identity.id. Default: nobody. |
applyRules | boolean | Check the list's write rules, as if the caller had made the write. By default a flow's writes bypass them: the flow's require nodes are its authorisation. |
Update an item: replace its data, merge into it, or apply a JSON Patch.
| Field | Kind | What it is |
|---|---|---|
list | list | The list, by id or path name. |
item | expression | The item, by id or alias. |
data | expression | The item's new data, replacing all of it. |
merge | expression | A JSON merge patch: fields to set, and null for fields to remove. |
patch | expression | A JSON Patch: [{ op: 'remove', path: '/cards/0' }, ...] |
ifVersion | expression | Refuse the write (409) unless the item is at this version, e.g. steps.game.version. |
applyRules | boolean | Check the list's write rules, as if the caller had made the write. By default a flow's writes bypass them: the flow's require nodes are its authorisation. |
Delete an item.
| Field | Kind | What it is |
|---|---|---|
list | list | The list, by id or path name. |
item | expression | The item, by id or alias. |
applyRules | boolean | Check the list's write rules, as if the caller had made the write. By default a flow's writes bypass them: the flow's require nodes are its authorisation. |
Work out a value once, for later nodes to use as steps.<id>.
| Field | Kind | What it is |
|---|---|---|
value | expression | The value. |
Go one way or the other: the edges out of it are labelled "true" and "false".
| Field | Kind | What it is |
|---|---|---|
when | expression | Which way to go. |
Go the way of the first case that is true, or "default" if none is.
| Field | Kind | What it is |
|---|---|---|
cases | cases | The cases, in order: [{ "when": "<expression>", "port": "<name>" }]. Each port names the edges to follow. |
Stop the flow unless something is true. Everything it's written is rolled back, and an endpoint responds with the status and message.
| Field | Kind | What it is |
|---|---|---|
when | expression | What must be true for the flow to carry on. |
status | integer | The HTTP status to fail with: 403 for "not allowed", 409 for "not now", and so on. |
message | string | The error message. |
Run a small graph once for each element of an array (at most 50). Inside it, each is the element and index its position.
| Field | Kind | What it is |
|---|---|---|
items | expression | The array to go through. |
body | graph | The graph to run for each element: { "nodes": [...], "edges": [...] }. Its nodes can use each, index, and the steps before the for-each. |
result | expression | What each iteration gives, evaluated after the body with the body's steps in scope. Default: an object of the body's step outputs. |
Set the endpoint's response. It's sent once everything else has run and the writes are committed. Without one, an endpoint responds 204.
| Field | Kind | What it is |
|---|---|---|
status | integer | The HTTP status. Use a require node to fail. |
body | expression | The response body, as JSON. |
headers | headers | Extra response headers: x-* headers and cache-control. |
Send an event to webhooks you already have, signed and retried like any webhook delivery. Sent only if the run succeeds.
| Field | Kind | What it is |
|---|---|---|
webhooks | strings | The webhook ids. |
payload | expression | The event's data. |
Write a value to the run's log, for debugging.
| Field | Kind | What it is |
|---|---|---|
value | expression | The value to log. |
Besides these, expressions can use every function in the write rules language, including lookup and exists, and the flow's helpers.
inputanyWhat the flow was started with. For an endpoint, the request body (or query, for GET). For an event, the event: { type, list, item, previous, actor }, the same as a webhook body.stepsobjectThe outputs of the nodes that ran before this one, by node id: steps.game.data.status. A node that was skipped (its branch wasn't taken) is null.flowobjectAbout this run: { name, runId, eventId, depth, dryRun }. eventId is the same for every retry of an event run, so it makes a good idempotency key.identityobject | nullThe identity making the request, or null. A flow does its own authorisation with require nodes. For an event flow, the identity that made the change, if one did.tokenobject | nullThe API token making the request: { id, tags }, or null for a public flow. For an event flow, the token that made the change, if one did.nowtimestampThe time of the run. The same instant for every node, and the same as the timestamps on the items the run writes.oldanyThe item's data before the event, or null. With new, it's what changed(), unchanged() and onlyChanged() compare. Only in event flows.newanyThe item's data after the event, or null on delete. Only in event flows.eachanyInside a for-each body: the current element.indexnumberInside a for-each body: the position of the current element, from 0.The same on every plan.
100 nodesin a flow, counting each node in a for-each's body once128 KiBfor a flow document, as JSON3 for-each nodesnested inside each other4,096 charactersin one expression20 casesin a switch50 elementsper for-each, each time it runs50 reads and writesper run, lookups included25 writesper run: creates, updates and deletes25 itemsfrom one find-items10 emitsper run, each to at most 5 webhooks50 log entriesper run256 KiBfor a value a run writes, responds with, emits or logs100,000 unitsof evaluation budget per expression, and 1,000,000 for a whole run (the same units as write rules)5 secondsfor an endpoint flow, and 30 seconds for an event flow100 testsin a flow's stored tests, and 512 KiBAn endpoint flow that fails responds with a FLOW_FAILED error, whose details.code is one of these, and whose details.node is the node it failed at. The run log shows the same.
REQUIRE_FAILEDA require node's condition was false. The run fails with the node's status and message.NOT_FOUNDA get-item with required found nothing (404).EVALUATION_ERRORAn expression failed, e.g. comparing a number with a string, or a condition that wasn't true or false (400).LIMIT_EXCEEDEDThe run did too many reads, writes, iterations, emits or logs (422).BUDGET_EXCEEDEDThe expressions ran out of evaluation budget (422).TIMEOUTThe run took too long (504).LIST_NOT_FOUNDA node named a list that doesn't exist (500: the flow needs fixing, not the request).ITEM_NOT_FOUNDAn item a write needed isn't there (404).ITEM_CONFLICTAn update-item's ifVersion didn't match the item's version (409).VALIDATION_ERRORA write didn't match its list's JSON schema (400).A write can also fail the way the same API request would, e.g. MAX_ITEMS_EXCEEDED or ALIAS_IN_USE, or with your list's write rules on a node with applyRules.