Returning.AIDocs
v1

API reference / Workflow Builder

.md

Rename a workflow or set its failure webhook

Changes the workflow's name and its failure webhook URL.

Last updated 28 Oct 2026API v1

Method
PATCH
Path
https://api.returning.ai/v1/workflow-builder/data-workflows/{workflowId}
Permission
workflowBuilder
Retries
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.

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.

FailureMeaningRecovery
404 WORKFLOW_NOT_FOUNDUnknown id, or another community's workflowUse 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#

workflowId#stringREQUIRED
Workflow identifier: 24 hexadecimal characters, as returned in _id.

Rule^[0-9a-fA-F]{24}$

Eg65f1a2b3c4d5e6f708192a3b

Headers#

Authorization#stringREQUIRED
Community API key: Bearer <API_KEY>.

EgBearer <API_KEY>

If-Match#stringOPTIONAL
Optional. Send the 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

Content-Type#stringREQUIRED
Request body format.

Ruleapplication/json

Body#

name#stringOPTIONAL
New workflow name.

Rule1-200 chars

Eg"VIP bonus (2026)"

outgoingWebhookUrl#stringOPTIONAL
Failure webhook URL, or null to clear it.

RuleNullable

Eg"https://hooks.example.com/returning/failures"

Watch for

  • outgoingWebhookUrl fires 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 null value 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:

BASH
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:

BASH
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:

BASH
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)"}'
JSON
{
  "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.

data#object
A workflow with its trigger, its steps in canvas order and its revision.

Eg{ ... }

_id#string
Workflow identifier.

Eg"65f1a2b3c4d5e6f708192a3b"

communityId#string
Community the workflow belongs to.

Eg"65f1a2b3c4d5e6f708192a50"

name#string
Workflow name.

Eg"VIP bonus (2026)"

status#string
draft, deployed or undeployed.

Eg"draft"

outgoingWebhookUrl#string
Failure webhook URL, when one is set.

RuleNullable

Egnull

createdAt#string
Creation time.

Eg"2026-10-24T09:15:00.000Z"

updatedAt#string
Last authored change.

Eg"2026-10-24T09:20:11.000Z"

trigger#object
The trigger, or null when the workflow has none.

RuleNullable

Eg{ ... }

_id#string
Trigger identifier. Use it as the source of a reference.

Eg"65f1a2b3c4d5e6f708192a41"

name#string
Display name.

Eg"Trade bonus trigger"

type#string
Trigger type.

Eg"webhook"

status#string
Trigger lifecycle state, for example idle.

Eg"idle"

options#object
Trigger options. A webhook key is shown only in the response that created it.

RuleNullable

Eg{ ... }

nodes#object[]
Main-line steps in canvas order, routers carrying their branches.

Eg[ ... ]

_id#string
Step identifier.

Eg"65f1a2b3c4d5e6f708192a3c"

name#string
Step name.

Eg"Read member XP"

type#string
Step type.

Eg"platform-action"

order#integer
Position on the main line, from 1.

Eg1

continueOnFailure#boolean
Whether a failure stops the run.

Egfalse

retryOnFailure#boolean
Whether the step is retried on failure.

Egfalse

options#object
Stored step options, with every credential replaced by ["__REDACTED__"].

RuleNullable

Eg{ ... }

status#string
Last run state of the step, when one exists.

Eg"success"

nestedNodes#object[]
Present on a router: each branch carries its own workflowNodeIds and nestedNodes.
revision#string
64 hexadecimal characters. Send it back as If-Match; it also arrives as the ETag header.

Eg"162af81f5de4ff2b557a4087de9a9a73a0ed4e621f737787e35a93614cb50d1c"

redactedPaths#string[]
Every location where a credential was replaced by ["__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

400VALIDATION_FAILEDFix the request
An empty body, an unknown field, a name over 200 characters, or a URL that is not a URL. Send at least one valid field.
400REDACTED_VALUE_WITHOUT_STORED_SECRETFix the request
outgoingWebhookUrl carries a redaction marker where no webhook is stored. Send the real URL.
401AUTHENTICATION_REQUIREDFix the request
No key, or an unknown key. Send a valid key.
401API_KEY_REQUIREDFix the request
A valid admin session was used, because this API accepts community API keys only. Use a community API key.
403API_KEY_PERMISSION_DENIEDFix the request
No workflowBuilder. Grant the permission.
413VALIDATION_FAILEDFix the request
The request body is too large to read. Nothing was written. Send a smaller body; a large import is better split into a create plus step writes.
415UNSUPPORTED_MEDIA_TYPEFix the request
The body was not declared application/json. Send the header.

Fix the data03

404WORKFLOW_NOT_FOUNDFix the data
Unknown id, or another community's workflow. Use an id from this community.
409VERSION_CONFLICTFix the data
You sent an If-Match that is not the current revision. meta.currentRevision carries the live value. Re-read the workflow and reapply the change.
409WORKFLOW_LOCKEDFix the data
Another write to this workflow held the lock for too long, and this write was not applied. Re-read and retry.

Retry with backoff03

429RATE_LIMITEDRetry with backoff
The community's API rate limit was reached. Wait for the window to reset, then retry.
500INTERNAL_ERRORRetry with backoff
Unexpected failure. Retry with bounded backoff.
503LOCK_UNAVAILABLERetry with backoff
The write lock store did not answer, so nothing was written. Retry shortly.

Retries

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."
}

Next step#

Delete a workflowDELETE/v1/workflow-builder/data-workflows/{workflowId}