Rename a workflow or set its failure webhook
Changes the workflow's name and its failure webhook URL.
- Method
- PATCH
- Path
https://api.returning.ai / v1/ workflow-builder/ data-workflows/ {workflowId} - Permission
- workflowBuilder
- Retries
- A retry with the same
If-Matchis safe only while the revision is unchanged: the second attempt then fails with409 VERSION_CONFLICTand changes nothing.
Authentication#
- Header
Authorization: Bearer <API_KEY>- Permission
- workflowBuilder
Authorization: Bearer <API_KEY> with workflowBuilder, and the workflow in the key's community.
If-Match is optional. Send the revision you last read and a stale value is refused with 409 VERSION_CONFLICT; omit it and the change applies as the last write. On a deployed workflow the same call applies immediately: there is no live-edit header and no draft to promote.
| Failure | Meaning | Recovery |
|---|---|---|
404 WORKFLOW_NOT_FOUND | Unknown id, or another community's workflow | Use an id from this community. |
Behaviour#
Those are the only two workflow-level fields a caller can change; the trigger has its own route and the steps have their own routes.
It writes only the fields you send, returns the whole workflow afterwards, and never changes the deployment state.
Request#
Path parameters#
_id.Rule^[0-9a-fA-F]{24}$
Eg65f1a2b3c4d5e6f708192a3b
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
outgoingWebhookUrlfires once for a non-test run that ends in error. It has no retry, no signature and no idempotency key, and its body can carry member rows, so point it only at an endpoint you control.- A query-parameter credential in the URL is redacted on read, and the marker is restored from the stored URL by parameter name, even when the host changes. Repointing the URL therefore keeps the old credential and sends it to the new host: check the host before the first run.
- A
nullvalue clears the webhook. Omitting the field leaves it as it is. - Editing a deployed workflow changes what the next run does, immediately; there is no separate draft version and no header to send. Copy the workflow, change the copy, dry-run it, then deploy the copy if you want a reviewable change.
- The failure webhook URL takes effect for the next failing run, whether the workflow is deployed or not. Nothing refuses a change to it, so a typo is only visible when a run fails.
- A rename does not move run history or change the trigger id, so downstream systems that reference the workflow by name will see a different name.
More examples and details
Set or clear the failure webhook:
curl --request PATCH \
--url "https://api.returning.ai/v1/workflow-builder/data-workflows/65f1a2b3c4d5e6f708192a3b" \
--header "Authorization: Bearer <API_KEY>" \
--header "Content-Type: application/json" \
--header "If-Match: 162af81f5de4ff2b557a4087de9a9a73a0ed4e621f737787e35a93614cb50d1c" \
--data '{"outgoingWebhookUrl":"https://hooks.example.com/returning/failures"}'
Clear it with an explicit null:
curl --request PATCH \
--url "https://api.returning.ai/v1/workflow-builder/data-workflows/65f1a2b3c4d5e6f708192a3b" \
--header "Authorization: Bearer <API_KEY>" \
--header "Content-Type: application/json" \
--header "If-Match: 68f78253046393414dec404e5442c140bb5db0393a7d1c389ff57bba71585501" \
--data '{"outgoingWebhookUrl":null}'
Edit a deployed workflow in place:
curl --request PATCH \
--url "https://api.returning.ai/v1/workflow-builder/data-workflows/65f1a2b3c4d5e6f708192a3b" \
--header "Authorization: Bearer <API_KEY>" \
--header "Content-Type: application/json" \
--header "If-Match: 162af81f5de4ff2b557a4087de9a9a73a0ed4e621f737787e35a93614cb50d1c" \
--data '{"name":"VIP bonus (live)"}'
{
"data": {
"_id": "65f1a2b3c4d5e6f708192a3b",
"communityId": "65f1a2b3c4d5e6f708192a50",
"name": "VIP bonus (2026)",
"status": "draft",
"outgoingWebhookUrl": null,
"createdAt": "2026-10-24T09:15:00.000Z",
"updatedAt": "2026-10-24T09:26:40.000Z",
"trigger": null,
"nodes": [],
"revision": "68f78253046393414dec404e5442c140bb5db0393a7d1c389ff57bba71585501",
"redactedPaths": []
}
}
curl --request PATCH \
--url 'https://api.returning.ai/v1/workflow-builder/data-workflows/<workflowId>' \
--header 'Authorization: Bearer <API_KEY>' \
--header 'Content-Type: application/json' \
--data '{
"name": "VIP bonus (2026)"
}'
Response#
HTTP 200 with the stored workflow and the new revision in the body and the ETag header. The response is itself the readback: name and outgoingWebhookUrl are the stored values, so no second read is needed. A read made before a concurrent canvas save would still show the newer revision, so check updatedAt when two writers are possible.
Eg{ ... }
Eg"65f1a2b3c4d5e6f708192a3b"
Eg"65f1a2b3c4d5e6f708192a50"
Eg"VIP bonus (2026)"
draft, deployed or undeployed.Eg"draft"
RuleNullable
Egnull
Eg"2026-10-24T09:15:00.000Z"
Eg"2026-10-24T09:20:11.000Z"
null when the workflow has none.RuleNullable
Eg{ ... }
Eg"65f1a2b3c4d5e6f708192a41"
Eg"Trade bonus trigger"
Eg"webhook"
idle.Eg"idle"
RuleNullable
Eg{ ... }
Eg[ ... ]
Eg"65f1a2b3c4d5e6f708192a3c"
Eg"Read member XP"
Eg"platform-action"
Eg1
Egfalse
Egfalse
["__REDACTED__"].RuleNullable
Eg{ ... }
Eg"success"
workflowNodeIds and nestedNodes.If-Match; it also arrives as the ETag header.Eg"162af81f5de4ff2b557a4087de9a9a73a0ed4e621f737787e35a93614cb50d1c"
["__REDACTED__"].Eg[]
{
"data": {
"_id": "65f1a2b3c4d5e6f708192a3b",
"communityId": "65f1a2b3c4d5e6f708192a50",
"name": "VIP bonus (2026)",
"status": "draft",
"outgoingWebhookUrl": null,
"createdAt": "2026-10-24T09:15:00.000Z",
"updatedAt": "2026-10-24T09:20:11.000Z",
"trigger": {
"_id": "65f1a2b3c4d5e6f708192a41",
"name": "Trade bonus trigger",
"type": "webhook",
"status": "idle",
"options": {
"tokenExchangeEnabled": false,
"apiKey": {
"enabled": false
},
"aesKey": {
"enabled": false
}
}
},
"nodes": [
{
"_id": "65f1a2b3c4d5e6f708192a3c",
"name": "Read member XP",
"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": "162af81f5de4ff2b557a4087de9a9a73a0ed4e621f737787e35a93614cb50d1c",
"redactedPaths": []
}
}
Errors#
Fix the request07
VALIDATION_FAILEDFix the requestREDACTED_VALUE_WITHOUT_STORED_SECRETFix the requestoutgoingWebhookUrl carries a redaction marker where no webhook is stored. Send the real URL.AUTHENTICATION_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
WORKFLOW_NOT_FOUNDFix the dataVERSION_CONFLICTFix the dataIf-Match that is not the current revision. meta.currentRevision carries the live value. Re-read the workflow and reapply the change.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 only while the revision is unchanged: the second attempt then fails with 409 VERSION_CONFLICT and changes nothing. That is the intended protection against a duplicate save, so re-read after any timeout or ambiguous result instead of resending blindly.
{
"meta": {
"status": "error",
"statusCode": 400,
"code": "VALIDATION_FAILED",
"errors": [
{
"path": "body.outgoingWebhookUrl",
"message": "Outgoing webhook URL must be a valid URL"
}
],
"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."
}