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

# Approvals

> Require structured approval on tickets before work proceeds, with flexible policies, multi-stage rounds, and notifications across web and Slack.

Approvals let you gate ticket progress behind one or more approval decisions. Add approvers to a ticket, choose a policy that determines when the approval is satisfied, and track the outcome across web and Slack.

Approvals use a rounds-based system where each round has its own approvers and policy. Rounds run in sequence, so the next round only activates after the previous one completes. A single round covers simple use cases, while multiple rounds support multi-stage workflows like manager approval followed by security review.

## Mental model

Approvals are a structured gate on ticket progress. A ticket can have zero or more approval rounds, each with its own policy and set of approvers. Rounds execute sequentially in a linked-list order. The ticket tracks an overall approval status derived from the state of its rounds.

Key entities:

| Entity                     | Purpose                                                                       | Cardinality               |
| -------------------------- | ----------------------------------------------------------------------------- | ------------------------- |
| **Ticket approval status** | Overall ticket-level status (In Progress, Approved, Declined, Force Approved) | One per ticket (nullable) |
| **Approval round**         | A single stage with a policy and approvers                                    | Zero or many per ticket   |
| **Round approver**         | A user assigned to approve within a round                                     | One or many per round     |

***

## Approval policies

| Policy        | Approved when                      | Declined when                   |
| ------------- | ---------------------------------- | ------------------------------- |
| **ANY**       | Any single approver approves       | Any approver declines           |
| **ALL**       | Every approver approves            | Any approver declines           |
| **THRESHOLD** | N approvers approve (configurable) | Impossible to reach N approvals |

***

## Round status flow

```text theme={"system"}
PENDING → ACTIVE → APPROVED → (next round activates or ticket approved)
                 → DECLINED → (ticket declined)
                 → RESET    → (new replacement round created)
```

* **PENDING**: Waiting for a previous round to complete
* **ACTIVE**: Awaiting approver decisions
* **APPROVED**: Policy satisfied
* **DECLINED**: Approver declined
* **RESET**: Admin reset the round (archived, replaced by a new round)
* **SKIPPED**: Round was bypassed

***

## Ticket approval status

| Status              | Meaning                        |
| ------------------- | ------------------------------ |
| **IN\_PROGRESS**    | Active or pending rounds exist |
| **APPROVED**        | All rounds approved            |
| **DECLINED**        | A round was declined           |
| **FORCE\_APPROVED** | Admin bypassed all rounds      |

***

## Round sequencing

Rounds form a singly-linked list via `nextRoundId`. The first round (head of list) has no previous round. When a round is approved, the system activates `nextRound` automatically. When the final round is approved, the ticket's `approvalStatus` is set to APPROVED.

***

## Adding approvers

Approvers can be added through:

* Ticket sidebar (creates/updates the focused round)
* Approval rounds UI (explicit round management)
* Workflow "Add Approvers" action (creates round at head of chain)
* Approval templates (creates full round chain from template)
* Forms (adds approvers to active round or creates new one)

When user groups are selected, they are expanded to individual users server-side. Only concrete users are stored as round approvers.

***

## Admin operations

* **Force approve**: Sets all non-approved rounds to APPROVED, sets ticket status to FORCE\_APPROVED. Requires workspace admin.
* **Reset round**: Archives the round (status = RESET), creates a new replacement round with `resetFromRoundId` link. Can change policy and approvers.
* **Reset approval**: Resets all rounds, restarts the process from the beginning.

***

## Notifications

Approvers are notified through:

* **Slack DM**: Always sent, bypasses notification preferences. Includes approval action buttons.
* **Microsoft Teams Adaptive Card**: Always delivered to the approver's chat, bypasses notification preferences. Includes **Approve** and **Decline** actions.
* **Slack thread**: Batched @mentions posted to the ticket thread (5-second batching window).
* **Microsoft Teams channel thread**: Approval updates posted into the ticket's connected Teams channel.
* **Email**: Configurable notification for pending approvals.

Events dispatched: `APPROVAL_ROUND_APPROVER_ADDED`, `APPROVAL_ROUND_APPROVER_REMOVED`, `APPROVAL_ROUND_APPROVER_APPROVED`, `APPROVAL_ROUND_APPROVER_DECLINED`, `TICKET_APPROVAL_COMPLETED`, `TICKET_APPROVAL_RESET`, `APPROVAL_ROUND_STARTED`.

***

## Constraints and gotchas

* A ticket can have multiple rounds, but only one round is ACTIVE at a time.
* Removing approvers from an active round triggers immediate policy re-evaluation. If remaining approvers already satisfy the policy, the round auto-completes.
* User groups are expanded to individual users at save time, not at evaluation time.
* Force approve requires workspace admin privileges.
* Reset preserves history by archiving the old round (RESET status) rather than deleting it.
* Biometric verification (when enabled) forces Slack approval buttons to redirect to the Admin.
* Approval DMs in Slack always send regardless of user notification preferences.
