---
title: "Approvals"
description: "Some actions wait for a person to say yes before they run. See what is waiting, decide it from Slack or the dashboard, and keep a record of every decision."
canonical: https://firefight.app/docs/gateway/approvals
---

# Approvals

An approval is a request that is allowed in principle but held until someone with the right role says yes. The action does not fail and does not need to be repeated, it waits, and runs by itself once approved.

Go to **Gateway → Approvals**. Everyone in the workspace can see the page, and the sidebar shows how many requests are waiting.

## When an action waits for approval

Nothing waits for approval until an admin says it should. Out of the box every granted ability runs as soon as it is called. An approval rule changes that for the calls it matches: Firefight parks the call and asks for a decision instead of running it.

Rules live under **Gateway → Permissions**, in the **Approval rules** block, and need admin access. They can also be written over the API (`/approval_rules`) and with the `upsert_approval_rule` MCP tool, from an admin's personal token. Each rule answers three questions about the call and three about the decision.

| Question | Choices |
|---|---|
| Which abilities | Pick specific abilities, or leave blank for any |
| Which risk levels | Read, write, destructive, or any |
| Which environments | Pick environments, or leave blank for any |
| Who approves | Anyone with the owner role, anyone with the admin or owner role, or specific people and agents |
| Where to ask | The incidents channel, a direct message to each approver, or both |
| Requester can approve their own request | On by default, switch it off to require someone else |
| Agents may decide this rule | Appears once an agent or service key is named. Off by default, so the named machines are listed but only the people decide |

A call is held by the first rule that matches it, reading top to bottom, so put the narrow rules above the broad ones and use the arrows to reorder. Switch a rule off to keep it without enforcing it.

An ability covered by a rule shows an **approval** marker wherever it is handed out, so whoever is granting it knows it will wait.

Two things never wait, whatever the rules say: deciding an approval, and changing permissions or the rules themselves. Otherwise a rule could hold the screen you would use to remove it.

:::tip
Start with one rule for destructive abilities in production, approved by any admin, asked in the channel. That catches the calls that cannot be undone without slowing down the rest.
:::

## What the requester sees

Firefight tells the person or agent that made the request that it is waiting, and tells them again once it is decided. Nothing else is needed from them.

**In Slack**, the reply says the action needs approval, that the request has been sent, and that they will hear back either way. When it is approved, Firefight carries the action out and posts a message saying who approved it and that it went ahead. If it is denied, the message says who declined and that nothing changed.

**On the dashboard**, the page they were on shows the same message. The decision arrives as a direct message in Slack, and the change they asked for is applied without them having to redo it.

**Over the API**, the response comes back as accepted rather than completed, with the message `approval_required` and an approval id. Once approved, the caller repeats the identical request with the header `X-Approval-Id` set to that id, and it runs. See [Using the API](https://firefight.app/docs/api/using-the-api.md).

**Over MCP**, the tool result says approval is required and gives the approval id. The agent retries the same call with `approval_id` once approved. See [Connect AI agents](https://firefight.app/docs/api/mcp-server.md).

An agent connected as you can also be the one watching. With `search_approvals` it sees a request that names you, tells you, and approves it with `approve_approval` once you say so. Connected as you, it decides as you.

An agent can also decide under its own name. Give it a service key under **Developer → API Keys**, name that key as an approver on the rule, and switch on **Agents may decide this rule**. From then on the agent, connected with that key, can approve or deny what the rule holds, and every decision is recorded under the agent's name. Nothing asks the agent, it polls `search_approvals` or `GET /approvals?status=pending` and sees the requests that name it. A rule without that switch refuses a machine's click even when the machine is named, so the default stays a person saying yes.

An approval covers exactly the request that was made, with the same details. It admits that request once. Changing anything about it, or calling again after it has run, is a new request and asks again.

## Deciding

Every pending request is listed under **Gateway → Approvals**, and posted in Slack wherever the rule said to ask: the incidents channel, a direct message to each approver, or both. Every copy carries **Approve** and **Deny** buttons. Decide from any of them, the result is the same.

The Slack message names who is asking, what they want to run, the scope and details of the call, and who may decide, either the role required or the people the rule named. Once decided, every copy of the message updates in place to show the verdict and who gave it, so nobody approves the same request twice.

On the dashboard, the **Pending approvals** table shows the same information with where the request came from, and Approve and Deny buttons for anyone who may decide. Below it, **Recently resolved** lists the last decisions with their status and who made them.

If you press a button on a request you cannot decide, Firefight tells you why. Either the request is no longer pending, you are not one of its approvers, or the rule asks for someone other than the requester.

## Approving your own request

By default you can approve a request you raised yourself. That is deliberate. When your AI agent proposes an action and you approve it, you are the safety check, and asking a second person to confirm what you already read would only slow the incident down.

Switch **Requester can approve their own request** off on a rule and approval must come from someone else. The dashboard and Slack both refuse the requester's own click in that case, with a message saying so.

## Permission to decide

Approving or denying needs the `approvals` permission, held by admins and owners. It can be granted to a member like any other permission, and to an agent or service key, which then also needs to be named on the rule with **Agents may decide this rule** switched on. See [Permissions](https://firefight.app/docs/gateway/permissions.md).

Every request and its outcome is also recorded in [Activity](https://firefight.app/docs/gateway/activity.md), including the ones that are still waiting.
