Returning.AIDocs
v1

API reference / Workflow Builder

.md

Add a router branch

Appends one branch to a router step.

Last updated 28 Oct 2026API v1

Method
POST
Path
https://api.returning.ai/v1/workflow-builder/data-workflows/{workflowId}/nodes/{nodeId}/branches
Permission
workflowBuilder
Retries
Not idempotent: two accepted calls create two branches with the same name.

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.

FailureMeaningRecovery
400 VALIDATION_FAILEDThe step is not a router, branchName is empty, or branchType is neither CONDITION nor FALLBACKSend a branch for a router step, with both required fields.

Behaviour#

A branch is a condition group plus the steps that run when it matches, or a fallback that runs when nothing else did.

The new branch is appended at the end of the router's branch list, and its step list starts empty. Steps are added to it with POST /{workflowId}/nodes and position: {routerNodeId, branchIndex}.

Request#

Path parameters#

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

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

Eg65f1a2b3c4d5e6f708192a3b

nodeId#stringREQUIRED
Step identifier: 24 hexadecimal characters, as returned in the step's _id.

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

Eg65f1a2b3c4d5e6f708192a3c

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#

branchName#stringREQUIRED
Branch name shown on the canvas.

Rule1-200 chars

Eg"Coins > 500"

branchType#stringREQUIRED
CONDITION for a rule, FALLBACK for the default path.

RuleCONDITION, FALLBACK

Eg"CONDITION"

conditions#object[]OPTIONAL
Condition groups. Prefer AND: the runtime treats OR and WHERE groups as always true, and validate reports ROUTER_OPERATOR_UNSAFE as a warning. Send [] for a fallback.

Eg[ ... ]

Watch for

  • Conditions use AND groups. A group with OR or WHERE is stored, and POST /{workflowId}/validate reports ROUTER_OPERATOR_UNSAFE as a warning: the runtime treats those groups as always true, so the branch fires more often than you meant. Deploy still proceeds, so use AND groups and read the warnings.
  • Each condition needs an id, a key, a type, an operator and a value, all as non-empty arrays for key and value.
  • A branch's steps are named in workflowNodeIds. A branch that names a step of another workflow is 400 NODE_NOT_IN_WORKFLOW: that is a tenant check, not a validation warning.
  • A router needs at least one branch to be runnable; POST /{workflowId}/validate reports BRANCH_REQUIRED as a warning when it has none, and deploy still proceeds. executePaths decides whether the first match wins or every match runs; a fallback only runs when no condition matched.
  • Deleting the last branch is refused, so build the replacement before removing the old one.
More examples and details

A condition branch:

BASH
curl --request POST \
  --url "https://api.returning.ai/v1/workflow-builder/data-workflows/65f1a2b3c4d5e6f708192a3b/nodes/65f1a2b3c4d5e6f708192a3e/branches" \
  --header "Authorization: Bearer <API_KEY>" \
  --header "Content-Type: application/json" \
  --header "If-Match: 162af81f5de4ff2b557a4087de9a9a73a0ed4e621f737787e35a93614cb50d1c" \
  --data '{"branchName":"Coins > 500","branchType":"CONDITION","conditions":[{"id":"group-2","operator":"AND","nestedGroups":[{"id":"nested-2","operator":"AND","conditions":[{"id":"condition-2","key":["{{65f1a2b3c4d5e6f708192a3c.Total Coins}}"],"type":"number","operator":"greater_than","value":["500"]}]}]}]}'

A fallback branch, with an empty conditions array:

BASH
curl --request POST \
  --url "https://api.returning.ai/v1/workflow-builder/data-workflows/65f1a2b3c4d5e6f708192a3b/nodes/65f1a2b3c4d5e6f708192a3e/branches" \
  --header "Authorization: Bearer <API_KEY>" \
  --header "Content-Type: application/json" \
  --header "If-Match: 68f78253046393414dec404e5442c140bb5db0393a7d1c389ff57bba71585501" \
  --data '{"branchName":"Otherwise","branchType":"FALLBACK","conditions":[]}'
JSON
{
  "data": {
    "node": {
      "_id": "65f1a2b3c4d5e6f708192a3e",
      "name": "XP over 100?",
      "type": "router",
      "order": 2,
      "continueOnFailure": false,
      "retryOnFailure": false,
      "options": {
        "executePaths": "first_matching",
        "branches": [
          { "branchName": "XP > 100", "branchType": "CONDITION", "workflowNodeIds": ["65f1a2b3c4d5e6f708192a3d"] },
          { "branchName": "Otherwise", "branchType": "FALLBACK", "workflowNodeIds": [] }
        ]
      }
    },
    "revision": "68f78253046393414dec404e5442c140bb5db0393a7d1c389ff57bba71585501",
    "redactedPaths": []
  }
}
curl --request POST \
  --url 'https://api.returning.ai/v1/workflow-builder/data-workflows/<workflowId>/nodes/<nodeId>/branches' \
  --header 'Authorization: Bearer <API_KEY>' \
  --header 'Content-Type: application/json' \
  --data '{
    "branchName": "Coins > 500",
    "branchType": "CONDITION",
    "conditions": [
      {
        "id": "group-2",
        "operator": "AND",
        "nestedGroups": [
          {
            "id": "nested-2",
            "operator": "AND",
            "conditions": [
              {
                "id": "condition-2",
                "key": ["{{65f1a2b3c4d5e6f708192a3c.Total Coins}}"],
                "type": "number",
                "operator": "greater_than",
                "value": ["500"]
              }
            ]
          }
        ]
      }
    ]
  }'

Response#

HTTP 201 with the router step in { node, revision, redactedPaths }, and the revision in the ETag header. The response is the readback: options.branches shows the new branch at the index you will use to add steps to it.

The branch index is its position in options.branches, counted from 0.

data#object
One step with the workflow revision it left behind.

Eg{ ... }

node#object
A step as returned by the API.

Eg{ ... }

_id#string
Step identifier.

Eg"65f1a2b3c4d5e6f708192a3c"

name#string
Step name.

Eg"XP over 100?"

type#string
Step type.

Eg"router"

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
Revision after the write.

Eg"68f78253046393414dec404e5442c140bb5db0393a7d1c389ff57bba71585501"

redactedPaths#string[]
Credential locations replaced in this response.

Eg[]

{
  "data": {
    "node": {
      "_id": "65f1a2b3c4d5e6f708192a3c",
      "name": "XP over 100?",
      "type": "router",
      "order": 1,
      "continueOnFailure": false,
      "retryOnFailure": false,
      "options": {
        "executePaths": "first_matching",
        "branches": [
          {
            "branchName": "XP > 100",
            "branchType": "CONDITION",
            "workflowNodeIds": []
          }
        ]
      }
    },
    "revision": "68f78253046393414dec404e5442c140bb5db0393a7d1c389ff57bba71585501",
    "redactedPaths": []
  }
}

Errors#

Fix the request06

400VALIDATION_FAILEDFix the request
The step is not a router, or a required field is missing or invalid. Send branchName and branchType, and conditions for a condition branch.
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 data04

404NODE_NOT_FOUNDFix the data
The step is not part of this workflow. Read the workflow for its step ids.
404BRANCH_NOT_FOUNDFix the data
No branch at that index on this router.
409VERSION_CONFLICTFix the data
You sent an If-Match that is not the current revision. meta.currentRevision carries the live value. Re-read and resend.
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. Re-read the router before retrying.
503LOCK_UNAVAILABLERetry with backoff
The write lock store did not answer, so nothing was written. Retry shortly.

Retries

Not idempotent: two accepted calls create two branches with the same name. A retry after a timeout can leave a duplicate branch, so read the router before resending.

{
  "meta": {
    "status": "error",
    "statusCode": 400,
    "code": "VALIDATION_FAILED",
    "errors": [
      {
        "path": "params.workflowId",
        "message": "Id must be a 24 character hex string"
      }
    ],
    "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#

Update a router branchPATCH/v1/workflow-builder/data-workflows/{workflowId}/nodes/{nodeId}/branches/{branchIndex}