> ## Documentation Index
> Fetch the complete documentation index at: https://docs.zenable.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Approval Workflows

> Configure multi-phase approval flows for requirements and guardrails

<Info>
  Approval workflows are available on **Professional** and **Enterprise** plans.
</Info>

## Overview

Approval workflows let you gate requirements or guardrail changes. Configure multi-phase flows with flexible approval criteria based on specific users, roles, or permissions.

Without an active approval flow, requirements and guardrail regenerations are auto-approved immediately. With a flow configured, submissions enter a **pending** state and require explicit approval before proceeding.

## Key Concepts

| Concept | Description |
| - | - |
| **Approval Flow** | A reusable workflow definition with one or more sequential phases |
| **Phase** | A step in the flow with its own approval expression (who must approve) |
| **Approval Expression** | A logical tree (AND/OR/NOT) of criteria that must be satisfied |
| **Approval Request** | A specific instance of a submission awaiting review |
| **Feedback** | Votes (upvote/downvote) and comments on pending requests |

## Target Types

Approval flows can be configured for these submission types. Create / update / delete are split per entity so different policies can apply to each (e.g. a flow could require approval on delete but not on create):

| Target Type | Description |
| - | - |
| `new_requirement` | New requirement proposals |
| `requirement_version` | Updates to existing requirements |
| `requirement_delete` | Deletion of a requirement family (cascades to the requirement's guardrails) |
| `requirement_override_create` | Creating a tenant override for a marketplace requirement |
| `requirement_override_update` | Modifying an existing tenant override |
| `requirement_override_delete` | Removing a tenant override |
| `guardrail_regeneration` | Guardrail code regeneration requests |
| `guardrail_custom_create` | Authoring a new tenant-owned custom guardrail |
| `guardrail_custom_update` | Modifying an existing custom guardrail |
| `guardrail_delete` | Deleting a custom guardrail |
| `guardrail_family_settings_change` | Changing a guardrail's runtime failure settings |
| `scope_create` | Authoring a new scope definition, or approving a proposed scope |
| `scope_update` | Modifying an existing scope definition |
| `scope_delete` | Deleting a scope definition |
| `target_selector_create` | Authoring a new approval-flow target selector |
| `target_selector_update` | Modifying an existing target selector |
| `target_selector_delete` | Deleting a target selector |
| `requirement_merge` | Merging multiple requirements into one |
| `requirement_split` | Splitting one requirement into several |
| `approval_policy_create` | Authoring a new [approval policy](/approval-policies) |
| `approval_policy_update` | Modifying an existing approval policy |
| `approval_policy_delete` | Deleting an approval policy |

### Pending state and final disposition

Approval-gated actions never reach their final state until the request is approved.

* **Creates and updates** stage the proposed data in the affected table itself, marked `PROPOSED` (overrides) or `PROPOSED` lifecycle (requirements). Read paths filter these out so users only see live state.
* **Deletes** carry no pending state on the row — the open approval request itself is the pending marker. On approve the row is soft-deleted via `deleted_at`; on reject the row is untouched. Soft delete keeps the audit trail intact and makes restoration trivial.
* An override **update** writes a new `PROPOSED` row whose `supersedes_id` points at the existing `ACTIVE` row. On approve, the superseded row is soft-deleted and the proposed row flips to `ACTIVE`. On reject, the proposed row is soft-deleted and the active row stays live.

### Specific-user criteria

`SPECIFIC_USER` criterion values are stored as `user_uid` (the stable 5-word identifier). The UI surfaces and accepts `login_identifier` (email / UPN / SSO sub) so authors and approvers see human-readable handles; the form picker stores the corresponding `user_uid` under the covers. Even when an approver holds `requirements:approve` or `guardrails:approve`, they can only decide on a request if they satisfy the active phase's expression — being named in a `SPECIFIC_USER` rule, for example.

## Creating an Approval Flow

Navigate to [Approval Management](https://www.zenable.app/approval-management?utm_source=docs\&utm_medium=web) and select the **Workflows** tab.

### Flow Configuration

1. **Name and description** - Give the flow a meaningful name
2. **Target types** - Select which submission types trigger this flow
3. **Phases** - Define one or more sequential approval phases
4. **Default flow** - Optionally mark as the default for its target types
5. **Auto-regenerate invalid guardrails without approval** - An optional configuration, shown only when `guardrail_regeneration` is a target type. When enabled, automatic regeneration due to a failure at runtime skips this flow and proceeds without approval. User-initiated regenerations still require approval.

### Target selectors (entity filters)

Target types decide *which kinds* of change a flow gates; an optional **target selector** narrows it to *which entities* — for example only enforced requirements, only marketplace ones, or only changes with a given lifecycle status.

Lifecycle matching is on the **resulting** status — the status the requirement will hold *after* the change (the outcome you're putting behind approval), not the status it's in now. The builder labels this rule **Resulting Status**. Match the state each change produces:

* Accepting a proposal brings it live at `beta` (the entry maturity — `stable` is a separate, later promotion), so gate go-lives with a `beta` selector.
* Declining a proposal lands it at `declined`, so gate declines with `declined`.
* Restoring a declined requirement returns it to `proposed` for re-triage, so gate restores with `proposed`.

### Approval Expressions

Each phase defines an approval expression using a logical tree:

* **Specific User** - A named user must approve (matched by user UID)
* **Role** - Any user with the specified role can approve
* **Permission** - Any user with the specified permission can approve

Combine criteria with **AND** (all must be satisfied), **OR** (any one suffices), or **NOT** (exclusion) operators. Expressions can be nested for complex approval requirements.

**Example:** "Requires approval from any Admin OR both the Security Auditor AND a Contributor"

```
OR
├── Role: Admin
└── AND
    ├── Role: Security Auditor
    └── Role: Contributor
```

### Multi-Phase Flows

Phases execute sequentially. Each phase must be fully approved before the next begins. If any phase is rejected, the entire request is rejected.

**Example:** A two-phase flow for new requirements:

1. **Technical Review** - Any contributor approves
2. **Compliance Sign-off** - Security auditor approves

## Reviewing Approval Requests

Navigate to the **Pending Reviews** tab in [Approval Management](https://www.zenable.app/approval-management?utm_source=docs\&utm_medium=web).

Each request shows:

* The submitted entity (requirement name, guardrail code snippet)
* Current phase and progress
* **Approve** / **Reject** buttons (visible only if you have the required permission)

### Decisions

* **Approve** - Records your approval for the current phase. If the phase's approval expression is now satisfied, the flow advances to the next phase (or completes).
* **Reject** - Immediately rejects the entire request regardless of phase. The submitter is notified.

### Feedback

You can provide feedback on any pending request without making an approval decision:

* **Vote** - Upvote or downvote (one vote per user per request, toggleable)
* **Comment** - Up to 280 characters. Edits are tracked; the last 12 versions are stored.

## What Happens After Approval

| Target Type | On Approval | On Rejection |
| - | - | - |
| New requirement | Transitions from PROPOSED to BETA; guardrail generation triggers | Transitions to DECLINED |
| Requirement version | Transitions from PROPOSED to BETA; guardrail update triggers | Transitions to DECLINED |
| Requirement delete | Requirement soft-deleted; cascades to its guardrails | Submitter notified; no delete |
| Requirement override create / update | New row activates (PROPOSED → ACTIVE); for updates, the superseded ACTIVE row is soft-deleted | PROPOSED row soft-deleted |
| Requirement override delete | Override row soft-deleted | Submitter notified; no delete |
| Guardrail regeneration | Regeneration proceeds with stored parameters | Submitter notified; no regeneration |
| Custom guardrail create | New row becomes is\_latest=true | PROPOSED row soft-deleted |
| Custom guardrail update | New row becomes is\_latest=true; prior version flips to is\_latest=false | PROPOSED row soft-deleted |
| Custom guardrail delete | Guardrail soft-deleted | Submitter notified; no delete |
| Scope create / update | New row activates (PROPOSED → ACTIVE); for updates, the superseded ACTIVE row is soft-deleted | PROPOSED row soft-deleted |
| Scope delete | Scope soft-deleted | Submitter notified; no delete |
| Target selector create / update | New row activates (PROPOSED → ACTIVE); for updates, the superseded ACTIVE row is soft-deleted | PROPOSED row soft-deleted |
| Target selector delete | Selector soft-deleted | Submitter notified; no delete |

## Notifications

Zenable groups notifications into two categories, both configurable under **Settings → Notifications** in your [profile](https://www.zenable.app/settings?utm_source=docs\&utm_medium=web).

### Governance Activity

Immediate notifications for approval events:

| Event | Delivery | Recipients |
| - | - | - |
| Approval requested | Immediate | Eligible approvers for phase 1 |
| Decision made | Immediate | Submitter |
| Phase completed | Immediate | Next phase's eligible approvers |
| Fully approved/rejected | Immediate | Submitter |
| Feedback received | Daily digest | Submitter |

### Report Mail

An opt-in periodic digest that combines persisted notifications with calculated activity (findings, feedback, and PR/MR reviews) for the reporting period. Choose **daily**, **weekly**, or **monthly** cadence in your profile.

## Required Permissions

Approvals are fully transparent: anyone with `approvals:read` can see every request, every decision, every comment, and who voted which way. There is no per-record permission gating beyond `approvals:read`.

| Permission | Description |
| - | - |
| `approvals:read` | View approval flows, pending requests, decisions, and the feedback thread |
| `approvals:feedback` | Submit non-binding feedback (vote + comment) on an approval request |
| `approvals:manage` | Create, edit, and archive approval flow definitions, [approval policies](/approval-policies), and target selectors |
| `requirements:approve` | Cast a binding approve/reject decision on requirement proposals |
| `guardrails:approve` | Cast a binding approve/reject decision on guardrail requests |

See [Roles and Permissions](/permissions) for which roles include these permissions.

### Who can decide what

Approving a change requires both the permission to make the change and being named by the flow's current phase.

| To approve changes to | You need |
| - | - |
| Requirements — new ones, edits, lifecycle moves, deletions, merges, splits, and marketplace overrides | `requirements:approve` |
| Guardrails — regeneration, and custom guardrails your team authors | `guardrails:approve` |
| Scopes — creating, editing, deleting, or handing over ownership | `scopes:write` |
| Groups — creating, editing, deleting, or changing who belongs to one | `groups:write` |
| Tenant configuration — guardrail runtime settings, and applying a configuration proposal | `settings:manage` |
| The approval system itself — approval policies and target selectors | `approvals:manage` |

## API Reference

### Approval Flows

| Method | Endpoint | Description | Permission |
| - | - | - | - |
| GET | `/api/data/approval-flows` | List flows (pass `?include_archived=true` to include archived) | `approvals:read` |
| POST | `/api/data/approval-flows` | Create a new flow | `approvals:manage` |
| PUT | `/api/data/approval-flows/{id}` | Update a flow | `approvals:manage` |

### Approval Requests

| Method | Endpoint | Description | Permission |
| - | - | - | - |
| GET | `/api/data/approval-requests` | List approval requests (filterable by status, target\_type, submitted\_by) | `approvals:read` |
| GET | `/api/data/approval-requests/{id}` | Get request detail with phase instances | `approvals:read` |
| POST | `/api/data/approval-requests/{id}/decide` | Submit approve/reject decision on a request | Depends on what is being changed — see [Who can decide what](#who-can-decide-what) |

Decision request body:

```json theme={null}
{
  "decision": "approve",
  "comment": "Looks good to me"
}
```

The `decision` field accepts `approve` or `reject`. The optional `comment` field (max 280 characters) is recorded with the decision.

### Approval Feedback

| Method | Endpoint | Description | Permission |
| - | - | - | - |
| GET | `/api/data/approval-requests/{id}/feedback` | List all feedback for a request | `approvals:read` |
| POST | `/api/data/approval-requests/{id}/feedback` | Submit or update your feedback | `approvals:feedback` |

Feedback request body:

```json theme={null}
{
  "vote": "upvote",
  "comment": "I agree with this change"
}
```

The `vote` field accepts `upvote` or `downvote` (mutually exclusive, toggleable). Both fields are optional; you can vote without commenting or comment without voting. Feedback is upserted per user per request — submitting again updates your existing feedback. Comment edits are versioned (last 12 versions retained).

## Audit Logging

All approval actions are recorded in the audit log:

* Flow created, updated, or archived
* Decision made (approve/reject)
* Request created or resolved
* Feedback submitted or edited

Access audit logs via the **Audit** section in the [management console](https://www.zenable.app/audit?utm_source=docs\&utm_medium=web).

<Note>
  **Need help?** Contact us at [hello@zenable.io](mailto:hello@zenable.io)
</Note>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.