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 are available on Professional and Enterprise plans.
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 |
scope_create | Authoring a new scope definition |
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 |
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 and select the Workflows tab.
Flow Configuration
- Name and description - Give the flow a meaningful name
- Target types - Select which submission types trigger this flow
- Phases - Define one or more sequential approval phases
- Default flow - Optionally mark as the default for its target types
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:
- Technical Review - Any contributor approves
- Compliance Sign-off - Security auditor approves
Reviewing Approval Requests
Navigate to the Pending Reviews tab in Approval Management.
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
Users receive notifications for approval events based on their notification preferences:
| 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 |
All notification types can be individually enabled or disabled in user preferences.
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 |
requirements:approve | Cast a binding approve/reject decision on requirement proposals |
guardrails:approve | Cast a binding approve/reject decision on guardrail regeneration requests |
See Roles and Permissions for which roles include these permissions.
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 | requirements:approve for requirement-related target types (new_requirement, requirement_version, requirement_delete, requirement_override_create, requirement_override_update, requirement_override_delete); guardrails:approve for guardrail-related target types (guardrail_regeneration, guardrail_custom_create, guardrail_custom_update, guardrail_delete); approvals:manage for scope/selector target types (scope_create, scope_update, scope_delete, target_selector_create, target_selector_update, target_selector_delete). The phase rule may also require a specific user / role / permission. |
Decision request body:
{
"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:
{
"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.