# Update a router branch

Changes a branch's name, its type, or its condition groups.

- Endpoint: `PATCH https://api.returning.ai/v1/workflow-builder/data-workflows/{workflowId}/nodes/{nodeId}/branches/{branchIndex}`
- Section: Workflow Builder / Router branches
- Authentication: `Authorization: Bearer <API_KEY>` (Community API key)
- Permission: `workflowBuilder`
- Retries: A retry with the same `If-Match` is refused with `409 VERSION_CONFLICT` once the first attempt landed, so a duplicate edit cannot apply twice.
- Guide: generated from the published specification
- Last updated: 28 Oct 2026
- Web page: https://docs.returning.ai/api-reference/workflow-builder/update-a-router-branch

## 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.

The branch index is positional, so it shifts when another branch is added or deleted. Read the router before writing to be sure which branch you are changing.

| Failure | Meaning | Recovery |
| --- | --- | --- |
| `404 BRANCH_NOT_FOUND` | No branch at that index | Read the router and use an existing index. |

## Behaviour

Fields you omit are kept, so this is a partial update of one branch rather than a replacement of the router.

The branch keeps its index and its steps. Changing a branch from `CONDITION` to `FALLBACK` does not move or delete the steps attached to it.

## Request

### Path parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `workflowId` | `string` | Yes | Workflow identifier: 24 hexadecimal characters, as returned in `_id`. (`^[0-9a-fA-F]{24}$`) |
| `nodeId` | `string` | Yes | Step identifier: 24 hexadecimal characters, as returned in the step's `_id`. (`^[0-9a-fA-F]{24}$`) |
| `branchIndex` | `integer` | Yes | Zero-based index of the branch inside the router step, in stored order. (Min 0) |

### Headers

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Authorization` | `string` | Yes | Community API key: `Bearer <API_KEY>`. |
| `If-Match` | `string` | No | 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. |
| `Content-Type` | `string` | Yes | Request body format. (`application/json`) |

### Body

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `branchName` | `string` | No | New branch name. (1-200 chars) |
| `branchType` | `string` | No | `CONDITION` or `FALLBACK`. (`CONDITION`, `FALLBACK`) |
| `conditions` | `object[]` | No | Replacement condition groups. |

### Watch for

- `conditions` is replaced, not merged. Send the complete condition tree you want.
- Conditions are `AND` inside a group. `OR` and `WHERE` groups are stored, and validation reports them as warnings rather than refusing the write or the deploy.
- Renaming a branch does not change its index or its steps.
- A branch index is not stable across adds and deletes. Never cache it across calls.
- A router with only a fallback branch is valid, deploys, and simply always takes the fallback.

### Example request

```bash
curl --request PATCH \
  --url 'https://api.returning.ai/v1/workflow-builder/data-workflows/<workflowId>/nodes/<nodeId>/branches/<branchIndex>' \
  --header 'Authorization: Bearer <API_KEY>' \
  --header 'Content-Type: application/json' \
  --data '{
    "branchName": "XP at least 100"
  }'
```

### More examples

Replace the condition groups of the first branch:

```bash
curl --request PATCH \
  --url "https://api.returning.ai/v1/workflow-builder/data-workflows/65f1a2b3c4d5e6f708192a3b/nodes/65f1a2b3c4d5e6f708192a3e/branches/0" \
  --header "Authorization: Bearer <API_KEY>" \
  --header "Content-Type: application/json" \
  --header "If-Match: 162af81f5de4ff2b557a4087de9a9a73a0ed4e621f737787e35a93614cb50d1c" \
  --data '{"conditions":[{"id":"group-1","operator":"AND","nestedGroups":[{"id":"nested-1","operator":"AND","conditions":[{"id":"condition-1","key":["{{65f1a2b3c4d5e6f708192a3c.Total XP}}"],"type":"number","operator":"greater_than_or_equal","value":["100"]}]}]}]}'
```

```json
{
  "data": {
    "node": {
      "_id": "65f1a2b3c4d5e6f708192a3e",
      "name": "XP over 100?",
      "type": "router",
      "order": 2,
      "continueOnFailure": false,
      "retryOnFailure": false,
      "options": {
        "executePaths": "first_matching",
        "branches": [
          { "branchName": "XP at least 100", "branchType": "CONDITION", "workflowNodeIds": ["65f1a2b3c4d5e6f708192a3d"] },
          { "branchName": "Otherwise", "branchType": "FALLBACK", "workflowNodeIds": [] }
        ]
      }
    },
    "revision": "68f78253046393414dec404e5442c140bb5db0393a7d1c389ff57bba71585501",
    "redactedPaths": []
  }
}
```

## Response

HTTP `200` with the router step and the workflow's new revision. The response is the readback for the branch you changed: name, type and condition groups as stored, and the same member ids as before.

Run `POST /{workflowId}/validate` after a condition change. A group that uses `OR` or `WHERE` is reported as `ROUTER_OPERATOR_UNSAFE`, as a warning: the runtime treats those groups as always true, so the branch fires more often than you meant. Deploy proceeds either way, so act on the warning.

### Response fields

| Field | Type | Presence | Description |
| --- | --- | --- | --- |
| `data` | `object` | - | One step with the workflow revision it left behind. |
| `data.node` | `object` | - | A step as returned by the API. |
| `data.node._id` | `string` | - | Step identifier. |
| `data.node.name` | `string` | - | Step name. |
| `data.node.type` | `string` | - | Step type. |
| `data.node.order` | `integer` | - | Position on the main line, from 1. |
| `data.node.continueOnFailure` | `boolean` | - | Whether a failure stops the run. |
| `data.node.retryOnFailure` | `boolean` | - | Whether the step is retried on failure. |
| `data.node.options` | `object` | - | Stored step options, with every credential replaced by `["__REDACTED__"]`. (Nullable) |
| `data.node.status` | `string` | - | Last run state of the step, when one exists. |
| `data.node.nestedNodes` | `object[]` | - | Present on a router: each branch carries its own `workflowNodeIds` and `nestedNodes`. |
| `data.revision` | `string` | - | Revision after the write. |
| `data.redactedPaths` | `string[]` | - | Credential locations replaced in this response. |

### Example response (200)

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

## Errors

### Fix the request

| Status | Code | What to do |
| --- | --- | --- |
| 400 | `VALIDATION_FAILED` | An empty body, or a field with an invalid value. Send at least one of `branchName`, `branchType`, `conditions`. |
| 401 | `AUTHENTICATION_REQUIRED` | No key, or an unknown key. Send a valid key. |
| 401 | `API_KEY_REQUIRED` | A valid admin session was used, because this API accepts community API keys only. Use a community API key. |
| 403 | `API_KEY_PERMISSION_DENIED` | No `workflowBuilder`. Grant the permission. |
| 413 | `VALIDATION_FAILED` | 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. |
| 415 | `UNSUPPORTED_MEDIA_TYPE` | The body was not declared `application/json`. Send the header. |

### Fix the data

| Status | Code | What to do |
| --- | --- | --- |
| 404 | `NODE_NOT_FOUND` | The step is not part of this workflow. Read the workflow for its step ids. |
| 404 | `BRANCH_NOT_FOUND` | No branch at that index. Read the router and use an existing index. |
| 409 | `VERSION_CONFLICT` | You sent an `If-Match` that is not the current revision. `meta.currentRevision` carries the live value. Re-read and resend. |
| 409 | `WORKFLOW_LOCKED` | Another write to this workflow held the lock for too long, and this write was not applied. Re-read and retry. |

### Retry with backoff

| Status | Code | What to do |
| --- | --- | --- |
| 429 | `RATE_LIMITED` | The community's API rate limit was reached. Wait for the window to reset, then retry. |
| 500 | `INTERNAL_ERROR` | Unexpected failure. Re-read the router before retrying. |
| 503 | `LOCK_UNAVAILABLE` | The write lock store did not answer, so nothing was written. Retry shortly. |

**Retries:** A retry with the same `If-Match` is refused with `409 VERSION_CONFLICT` once the first attempt landed, so a duplicate edit cannot apply twice. Sending the same body again against the new revision is a no-op that changes nothing.

## Next step

- [Delete a router branch](https://docs.returning.ai/api-reference/workflow-builder/delete-a-router-branch.md): `DELETE /v1/workflow-builder/data-workflows/{workflowId}/nodes/{nodeId}/branches/{branchIndex}`.
