---
title: "Approval"
description: "Explains the configuration items, negotiation/sequential approval rules, and the meaning of branch indices for the approval node."
---

# Approval

## Node Type

`approval`

Approval node type can only be used in approval workflows, which trigger type is `approval`.

## Node Description
Initiates an approval task, waits for the approval result to continue the workflow, and can branch based on the approval outcome.

## Business Scenario Examples
An expense report goes through an approval process after submission. The branching mode is similar to if/else.

## Configuration Items
| Field | Type | Default | Required | Description |
| --- | --- | --- | --- | --- |
| branchMode | boolean | false | Yes | Passing mode: `false` for direct (termination upon rejection/return), `true` for branching mode. |
| assignees | array | [] | Yes | List of approvers, specified as an array of user IDs or user queries. User IDs could be found by query `users:list` API, or use variables of user IDs form upstream. The query object will contains a `filter` object to describe the query condition of users collection.  See [Common Conventions - filter](../conventions/index.md#the-filter-field-in-trigger-and-node-configuration). |
| negotiation | number | 0 | No | Multi-person negotiation mode: `0` means any one pass/reject takes effect; `1` means all must pass to pass; `0<value<1` is a voting threshold (e.g., 0.6 means pass rate >60% is required to pass). |
| order | boolean | false | No | Whether to approve in sequence (when sequential, subsequent approvers are initially set to `Assigned`). |
| endOnReject | boolean | false | No | In branching mode, whether to terminate the workflow immediately after the rejection branch ends. |
| title | string | Node Title | No | Task title, supports variable templates. |
| approvalUid | string | None | No | Approval interface configuration UID (new version, usually generated by UI). If no value already exists, resolve the shared UID helper path first, then run `node <resolved-path-to-uid.js>` and write the generated value into the config. |
| taskCardUid | string | None | No | "My Approvals" card configuration UID (usually generated by UI). If no value already exists, resolve the shared UID helper path first, then run `node <resolved-path-to-uid.js>` and write the generated value into the config. |
| notifications | array | [] | No | Notification configurations (approval templates/channels, etc., generated by UI). |

## UID-backed Configuration Rule

For any UID-backed config field in this node:

- Keep the current value if the source payload already has one.
- Otherwise resolve the shared helper path from [nocobase-utils UID generation](../../../nocobase-utils/references/uid/index.md) in the current workspace, then run `node <resolved-path-to-uid.js>`.
- Do not leave placeholder strings such as `uid-for-approval-interface` in the final payload.

## Branch Description
Branching is enabled when `branchMode=true`:
- `branchIndex=2`: Approved
- `branchIndex=-1`: Rejected
- `branchIndex=1`: Returned

No branches are generated when `branchMode=false`.

Only add strong related nodes in branches, for example, to update approving record status or send notifications. Other process nodes could be add after the approval node. In most case, should not use nested approval nodes (in branches), better to add approval nodes one after another (as direct downstream).

## Test Support
Not supported. This node cannot use CLI `workflow flow-nodes test` or HTTP `flow_nodes:test`, because the server-side instruction does not implement `test()`.

## Example Configuration
```json
{
  "branchMode": true,
  "assignees": ["{{ $context.data.ownerId }}", { "filter": { "$and": [{ "role.name": "manager" }]} }, 123],
  "negotiation": 1,
  "order": false,
  "endOnReject": true,
  "title": "{{ $context.data.title }} - Approval",
  "approvalUid": "<pre-generated uid if missing>",
  "taskCardUid": "<pre-generated uid if missing>"
}
```

Before finalizing a payload like the example above, generate missing UID values first:

- Locate `skills/nocobase-utils/scripts/uid.js` in the current workspace instead of assuming a document-relative path.
- Run `node <resolved-path-to-uid.js>`.

## Output Variables
The variable selector for this node is a tree array of `{ label, value, children? }`. At runtime, join the `value` segments with `.` and prepend `$jobsMapByNodeKey.<nodeKey>`.

- Exposed roots under the node: `nodeTitle`, `title`, `status`, `data`, `records`.
- `data` follows the workflow trigger collection schema; any trigger-level `appends` become nested children under `data`.
- `records` is the approval-record array, with per-item fields `id`, `userId`, `status`, `comment`, and `updatedAt`.
- Example references: `{{$jobsMapByNodeKey.approval_step.status}}`, `{{$jobsMapByNodeKey.approval_step.title}}`, `{{$jobsMapByNodeKey.approval_step.data.amount}}`.
- If you need to process individual items in `records`, usually pass `{{$jobsMapByNodeKey.<nodeKey>.records}}` into a `loop` or JSON-processing node.
