Update a step
Changes a step's name, options, or failure behaviour.
- Method
- PATCH
- Path
https://api.returning.ai / v1/ workflow-builder/ data-workflows/ {workflowId}/ nodes/ {nodeId} - Permission
- workflowBuilder
- Retries
- A retry with the same
If-Matchis safe: if the first attempt landed, the second is refused with409 VERSION_CONFLICTand changes nothing.
Authentication#
- Header
Authorization: Bearer <API_KEY>- Permission
- workflowBuilder
Authorization: Bearer <API_KEY> with workflowBuilder, on a workflow of the key's community. If-Match is optional. Send the revision you read to avoid overwriting a concurrent change (a stale value is refused with 409 VERSION_CONFLICT); omit it and your write wins as the last one. A deployed workflow is edited with the same call: the change applies immediately.
| Failure | Meaning | Recovery |
|---|---|---|
400 VALIDATION_FAILED | The merged options do not match the step type | Read the type's schema from GET /catalog. |
Behaviour#
options is merged one level deep: a key you send replaces the stored value whole, and a key you omit is kept. A stored credential can be kept by echoing the redaction marker instead of the value.
A step's type, its position and its branch membership are not editable here. Moving a step has its own route, and changing a type is a delete plus a create.
Request#
Path parameters#
Headers#
Bearer <API_KEY>.EgBearer <API_KEY>
revision the change is based on, bare or quoted, to avoid overwriting a concurrent change: a stale value is refused with 409 VERSION_CONFLICT. Omit it for last-write-wins.Eg162af81f5de4ff2b557a4087de9a9a73a0ed4e621f737787e35a93614cb50d1c
Ruleapplication/json
Body#
Watch for
optionsmerges one level deep. A key you send replaces its stored value completely, and a key you omit stays as it was. Read the step first when you need to change part of a nested object.- A credential an import blanked stays marked as missing across a PATCH: the step keeps the list of paths it still has to fill, and a path drops off the list as soon as it holds a real value. A rename therefore cannot clear the reminder.
POST /{workflowId}/validatereports the ones still empty asMISSING_SECRETwarnings, and deploy proceeds either way. - To keep one credential while changing the rest, send
["__REDACTED__"]at that exact path. A moved path (a renamed header, a different authentication type) has no stored value and is refused. - A stored credential follows the URL, including to a different host: the marker is restored from the value stored at the same path, so an HTTP step you repoint at another host still carries the old credential there. Read the
urlin the response before the first run on the new host, and replace the credential rather than echoing the marker if the host is not one you control. typeandorderare refused with400 VALIDATION_FAILED, not ignored: the body allowsname,options,continueOnFailureandretryOnFailureonly. UsePOST /{workflowId}/nodes/{nodeId}/moveto reorder, and delete plus create to change a type.- An HTTP step's options are normalised on write: a
jsonorraw-databody is stored as one template string holding the JSON text. - A marker inside a raw body template is treated as text, not as a secret placeholder.
- A
platform-actionfield key is matched against the community's real fields when the request sendsfields: a read acceptstotal_xp,total_coins,xpandcoin, a write acceptsxpandcoin, and a custom field uses its own key. A key outside the list is stored as sent andPOST /{workflowId}/validatereportsUNKNOWN_USER_FIELDas a warning. A PATCH that does not sendfields, such as a rename, neither rewrites nor reports them. - A field written here without
logicis stored asoverwrite, which can zero a balance.POST /{workflowId}/validatereportsPOST_LOGIC_REQUIREDas a warning and the deploy still proceeds, so sendlogic(add,subtract,overwrite) on every field you write. - A label you send is kept exactly as sent; only a missing label is filled from the catalog. The label keys the step's result, so a downstream reference uses it, and validation reports
REFERENCE_UNKNOWN_FIELDwhen a reference names a label the step does not produce.
More examples and details
Replace the options while keeping a stored credential. The marker at headers.X-Api-Key and at auth.token keeps both stored values:
curl --request PATCH \
--url "https://api.returning.ai/v1/workflow-builder/data-workflows/65f1a2b3c4d5e6f708192a3b/nodes/65f1a2b3c4d5e6f708192a3d" \
--header "Authorization: Bearer <API_KEY>" \
--header "Content-Type: application/json" \
--header "If-Match: 162af81f5de4ff2b557a4087de9a9a73a0ed4e621f737787e35a93614cb50d1c" \
--data '{"options":{"method":"POST","url":["https://receiver.example.com/v2/trade-bonus"],"params":{},"headers":{"X-Api-Key":["__REDACTED__"]},"bodyType":"json","body":{"member":["{{65f1a2b3c4d5e6f708192a41.email}}"]},"auth":{"type":"bearer-token","token":["__REDACTED__"]}}}'
Make a step continue after a failure and retry once:
curl --request PATCH \
--url "https://api.returning.ai/v1/workflow-builder/data-workflows/65f1a2b3c4d5e6f708192a3b/nodes/65f1a2b3c4d5e6f708192a3c" \
--header "Authorization: Bearer <API_KEY>" \
--header "Content-Type: application/json" \
--header "If-Match: 68f78253046393414dec404e5442c140bb5db0393a7d1c389ff57bba71585501" \
--data '{"continueOnFailure":true,"retryOnFailure":true}'
{
"data": {
"node": {
"_id": "65f1a2b3c4d5e6f708192a3c",
"name": "Read member XP and coins",
"type": "platform-action",
"order": 1,
"continueOnFailure": true,
"retryOnFailure": true,
"options": {
"action": "get-user-fields",
"selectUser": { "type": "email", "value": ["{{65f1a2b3c4d5e6f708192a41.email}}"] },
"fields": [{ "label": "Total XP", "field": "total_xp" }]
}
},
"revision": "68f78253046393414dec404e5442c140bb5db0393a7d1c389ff57bba71585501",
"redactedPaths": []
}
}
curl --request PATCH \
--url 'https://api.returning.ai/v1/workflow-builder/data-workflows/<workflowId>/nodes/<nodeId>' \
--header 'Authorization: Bearer <API_KEY>' \
--header 'Content-Type: application/json' \
--data '{
"name": "Read member XP and coins"
}'
Response#
HTTP 200 with the stored step and the workflow's new revision in the body and the ETag header. The response is the readback for the fields you changed; a GET /{workflowId} is the readback that the step is in the right place with the right branch membership.
The stored options are the merged result: a top-level key you sent is replaced whole, and a top-level key you omitted is still there. The merge is one level deep only, so a nested object you send replaces the whole nested object.
Eg{ ... }
Eg{ ... }
Eg"65f1a2b3c4d5e6f708192a3c"
Eg"Read member XP and coins"
Eg"platform-action"
Eg1
Egfalse
Egfalse
["__REDACTED__"].RuleNullable
Eg{ ... }
Eg"success"
workflowNodeIds and nestedNodes.Eg"68f78253046393414dec404e5442c140bb5db0393a7d1c389ff57bba71585501"
Eg[]
{
"data": {
"node": {
"_id": "65f1a2b3c4d5e6f708192a3c",
"name": "Read member XP and coins",
"type": "platform-action",
"order": 1,
"continueOnFailure": false,
"retryOnFailure": false,
"options": {
"action": "get-user-fields",
"selectUser": {
"type": "email",
"value": ["{{65f1a2b3c4d5e6f708192a41.email}}"]
},
"fields": [
{
"label": "Total XP",
"field": "total_xp"
}
]
}
},
"revision": "68f78253046393414dec404e5442c140bb5db0393a7d1c389ff57bba71585501",
"redactedPaths": []
}
}
Errors#
Fix the request09
VALIDATION_FAILEDFix the requesttype or order, or options that do not match the type. Send at least one allowed field.REDACTED_VALUE_WITHOUT_STORED_SECRETFix the requestNODE_NOT_IN_WORKFLOWFix the requestLEADERBOARD_NOT_IN_COMMUNITYFix the requestAUTHENTICATION_REQUIREDFix the requestAPI_KEY_REQUIREDFix the requestAPI_KEY_PERMISSION_DENIEDFix the requestworkflowBuilder. Grant the permission.VALIDATION_FAILEDFix the requestUNSUPPORTED_MEDIA_TYPEFix the requestapplication/json. Send the header.Fix the data03
NODE_NOT_FOUNDFix the dataVERSION_CONFLICTFix the dataIf-Match that is not the current revision. meta.currentRevision carries the live value. Re-read, rebuild the change, resend.WORKFLOW_LOCKEDFix the dataRetry with backoff03
RATE_LIMITEDRetry with backoffINTERNAL_ERRORRetry with backoffLOCK_UNAVAILABLERetry with backoffRetries
A retry with the same If-Match is safe: if the first attempt landed, the second is refused with 409 VERSION_CONFLICT and changes nothing. A retry with the new revision is a second edit, and it applies the same body again, so only resend deliberately. Keeping a stored credential by echoing the marker means a retry can never write the marker as a value: a marker at a path with no stored value is refused.
{
"meta": {
"status": "error",
"statusCode": 400,
"code": "VALIDATION_FAILED",
"errors": [
{
"path": "node.options.url",
"message": "URL is required"
}
],
"requestId": "3f4d0e8b-7a6c-4f1e-9b2d-5a7c8e1f0a3b"
},
"message": "API request rejected error.",
"detail": "The request body is not valid.",
"solution": "Read error detail and try again."
}