One permission covers everything. A community API key with workflowBuilder can read, build, test, deploy and retry. There is no separate read, write, test, deploy or live-test permission, and no per-tool split on the MCP endpoint.
A test runs for real unless you say otherwise. mode: "live" is the default, matching the canvas Test button: it writes member fields, sends mail, calls outside systems and can pay rewards. mode: "dry-run" is opt-in and side-effect free, and sideEffects in the response tells you which one you got.
Edits apply immediately, including to a deployed workflow, and revision checking is optional. Every workflow and step response carries a revision. Send it as If-Match (or as revision on an MCP tool) and a stale write is refused instead of overwriting a newer save, including a save made in the canvas; omit it and the write wins as the last one. The reverse is never protected: a canvas save does not check an API revision.
Credentials are never returned. A stored credential comes back as ["__REDACTED__"] with the location listed in redactedPaths, whatever the caller's permission.
Send it (the revision you read) and a write whose revision is no longer current is 409 VERSION_CONFLICT, with meta.currentRevision carrying the live value. Re-read, rebuild the change, resend. This is the choice for anything a person also edits, including a workflow open in the canvas.
Omit it and the write applies as the last one. Nothing is checked and nothing is refused, which is the right default for a script that owns its workflow.
A revision covers edits made in the canvas too, because it is computed from the authored fields rather than from a stored counter. An API write based on a revision read before an admin's save is refused rather than overwriting that save.
A deployed workflow accepts every edit, including a delete, and the change applies immediately. There is no draft version to promote, no live-edit header to send, and no undeploy to perform first. That is why the canvas and the API can change the same workflow: treat a live workflow as production configuration.
Tell the agent to pass mode: "dry-run". Live is the default for both test tools, and live runs really write, send and pay. The same instruction covers a retry: there is no dry retry, so dry-run the workflow before queueing one.
Tell the agent to send If-Match (or revision on a tool call). Without it a write silently wins, including over a change a person made in the canvas a moment earlier.
Tell the agent to read warnings. Validation is advisory: validate and deploy both return the findings, and neither refuses anything, so the warnings are the only thing between a misconfigured workflow and a live run.
A key outside the list is stored as sent, and POST /{workflowId}/validate reports UNKNOWN_USER_FIELD as a warning. Nothing refuses the write, so take the key from this list: a step with a key that is not a real field reads or writes nothing.
A workflow that already stores a field the backend does not compute deploys too. UNKNOWN_USER_FIELD is a warning in both cases.
A read step's result is keyed by the field's label, so a later step references that label. A label you send is kept exactly as you sent it; only a missing label is filled from the catalog. A reference that names a label the step does not produce is reported as REFERENCE_UNKNOWN_FIELD by POST /{workflowId}/validate, and resolves to nothing at run time.
A stored credential is returned as the whole array ["__REDACTED__"], even where the stored value is a plain string, and every replaced location is listed in redactedPaths. Redaction applies to the workflow read, the step read, the export, run results and dry-run output.
Redaction covers HTTP authentication values, headers, parameters and body keys whose names look like credentials, credential-named URL query parameters, JSON body keys inside a resolved payload, and the trigger's key fields.
Booleans and numbers are never redacted, so a webhook's tokenExchangeEnabled and apiKey.enabled stay readable. That is how a caller learns the authentication mode without seeing the key.
To change something else and keep a credential, send the marker back at that exact path. A marker where nothing is stored is 400 REDACTED_VALUE_WITHOUT_STORED_SECRET.
A stored credential is restored by path, so it does follow a URL to another host: repoint an HTTP step and keep the marker, and the stored credential is sent to the new host. Read the url you stored before the first run there, and replace the credential rather than echoing the marker when the host is not one you control.
A webhook trigger key is minted once, when the trigger is created, and shown once in that response. Every later read redacts it, and a PUT keeps the stored key: a value you send is ignored, so a lost key cannot be rewritten. The only way to a different key is to stop having a webhook trigger, by setting another type and then webhook again, which stores no key in between and therefore mints a new one. Treat that as replacing the trigger's authentication rather than rotating a key, and reconfigure the sender.
An import blanks the credentials it could not read (a node's, not a trigger's) and lists them in secretsToFill. Validation reports each one as MISSING_SECRET until it is supplied, as a warning: an imported workflow can be deployed with a credential still empty, and the step will run without it. Fill every path first.
Tenant scoping. The community comes from the API key. No route and no MCP tool takes a community identifier, so there is nothing to spoof, and every read and write is filtered by the key's community. Another community's workflow, step, branch or run id answers 404 exactly as an id that does not exist does, so a key cannot be used to discover one. A leaderboard or a branch member outside the community is refused with 400 LEADERBOARD_NOT_IN_COMMUNITY or 400 NODE_NOT_IN_WORKFLOW.
Secret redaction. A stored credential never leaves in a response, whoever is asking and whatever the mode. That includes the workflow read, the step read, the export, run results and dry-run output.
A key with workflowBuilder can spend money and change a live workflow. There is no narrower key to hand an agent you do not trust with that. The mode it passes and the If-Match it sends are the controls, and they live in the caller's own instructions.
Security controls that belong to the platform are not enforced here. Admin access, the sandbox a Code step executes in, and API-key permissions are the platform's own controls, closed and owned outside this API; this API neither closes them nor depends on them. What it guarantees is the two protections above.
Custom Workflows are not covered. This base path is the Data Workflows canvas. The older Custom Workflows canvas keeps its own admin-only routes.
A step cannot move between branches in one call. Moving within the main line has a route; moving into or out of a branch is a delete plus a create.
Nothing but the two tenant checks refuses a deploy. A router branch that lists a step from another workflow (400 NODE_NOT_IN_WORKFLOW) and a leaderboard from another community (400 LEADERBOARD_NOT_IN_COMMUNITY) are refused. A router that uses OR or WHERE condition groups, a template whose step id is not in the workflow, one step listed in two branch lists, a write step without logic, retryOnFailure on a router whose branches pay, an empty imported credential and a workflow with no trigger all deploy. POST /{workflowId}/validate and the deploy response both return them as warnings; the warnings are the whole safety net, so read them.
A whole workflow cannot be replaced in place. Import creates a new workflow; changing one means changing its steps.
There is no draft version of a deployed workflow. Edits apply to it immediately, including a delete. Duplicate it, edit the copy, dry-run it and deploy the copy if you want a reviewable change.
A secret an author typed inside a raw HTTP body template is not redacted, exactly as the canvas shows it today. Keep credentials in the credential fields.
A field key is matched against the community's real fields, not refused. A read action names total_xp or total_coins, a write action names xp or coin, and a custom field names its own key. A typo is stored, POST /{workflowId}/validate reports UNKNOWN_USER_FIELD as a warning, and the step reads or writes nothing at run time.
A read step's result is keyed by the field's label. Send the label you want to reference, or omit it and take the catalog's, for example Total XP. A later step references that label, and validation reports REFERENCE_UNKNOWN_FIELD when it names one the step does not produce.
{
"meta": {
"status": "error",
"statusCode": 409,
"code": "VERSION_CONFLICT",
"currentRevision": "68f78253046393414dec404e5442c140bb5db0393a7d1c389ff57bba71585501",
"requestId": "3f4d0e8b-7a6c-4f1e-9b2d-5a7c8e1f0a3b"
},
"message": "API request rejected error.",
"detail": "The workflow changed since this revision was read. Re-read it and retry.",
"solution": "Read error detail and try again."
}
The endpoint pages in this folder carry the full contract for each call.
The connection guide for AI agents covers the MCP endpoint, the client configuration and the tool list.
The API playbooks translate each operating playbook into the calls that achieve the same outcome, including the steps that still need the canvas.