> ## Documentation Index
> Fetch the complete documentation index at: https://phidatainc-studio-tools-doc.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Approval

> Admin-mediated HITL workflows with persistent records and audit trails.

Approval enables a "User Triggers, Admin Authorizes" workflow. When an agent (or team member) hits a protected tool during a run, the run pauses and persists a pending record to your database. Execution only resumes once an admin approves or rejects the request.

Approvals are built on HITL primitives (requires\_confirmation, requires\_user\_input, or external\_execution). Your tool must implement at least one.

<Note>
  Approvals work at both the agent and team level. When a member agent in a team calls an `@approval` tool, the team run pauses with the same flow shown below. See the [Team approval example](/examples/agents/approvals/approval-team).
</Note>

## Quick start

```python theme={null}
from agno.approval import approval
from agno.tools import tool
from agno.db.sqlite import SqliteDb
from agno.agent import Agent

@approval
@tool(requires_confirmation=True)
def delete_user_data(user_id: str) -> str:
    """Permanently delete all data for a user. Requires admin approval."""
    return f"All data for user {user_id} has been deleted."

db = SqliteDb(db_file="app.db", approvals_table="approvals")
agent = Agent(model=..., tools=[delete_user_data], db=db)
```

When the user asks for something that uses this tool, the run pauses and a **pending** approval is written to the database. An admin resolves it; then you continue the run.

## Approval Types

| Type                                          | Behavior                                                                                                        | Use Case                                                  |
| --------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- |
| `@approval(type="required") or `@approval\`\` | **Blocking:** Run pauses until an admin reviews and resolves the database record.                               | Critical actions such as deletion, payments, bulk emails. |
| `@approval(type="audit")`                     | **Non-blocking:** Run continues immediately after the HITL interaction is resolved and an audit log is created. | Compliance and activity auditing purposes.                |

### Blocking

By default, `@approval` needs HITL approval and `requires_confirmation=True` is set.

### Non-blocking

To enable an audit-style (non-blocking) Human-in-the-Loop flow for persistent audit trails, use `@approval(type="audit")`. This will create an audit log after the HITL interaction is resolved.

You can use the @tool decorator with `log_approval=True` to explicitly signal that this tool's execution should be logged in the HITL audit system.

See [User Confirmation](/hitl/user-confirmation) for details.

### Execution Flow

There are three distinct phases in the approval flow:

* **The Pause:** When a user triggers an @approval tool, the SDK automatically pauses the run and inserts a pending record into your database.
* **Admin Approval:** Admin views the list of pending requests. Then update the record status via the DB provider. Use `expected_status="pending"` to prevent race conditions.

  ```python theme={null}
  db.update_approval(
      approval_id,
      expected_status="pending",
      status="approved",   # or "rejected"
      resolved_by="admin_user_id",
      resolved_at=int(time.time()),
      # For requires_user_input or external_execution: pass resolution_data
      # (e.g. values for user input, result for external execution); SDK applies it on continue_run.
  )
  ```
* **Resuming the Run:** Continue the run using the `run_id`. The SDK verifies the resolution before proceeding. If the record is missing or still pending, continue\_run raises a RuntimeError.

  ```python theme={null}
  run = agent.continue_run(run_id=run.run_id, requirements=run.requirements)
  ```

## Examples

<CardGroup cols={2}>
  <Card title="Blocking approvals" icon="hand" href="/examples/agents/approvals/approval-basic">
    @approval + requires\_confirmation: pause, DB record, resolve, continue.
  </Card>

  <Card title="Approval list and resolve" icon="list" href="/examples/agents/approvals/approval-list-and-resolve">
    Full lifecycle: pause, list pending, resolve via DB, continue.
  </Card>

  <Card title="Approval with user input" icon="keyboard" href="/examples/agents/approvals/approval-user-input">
    @approval + requires\_user\_input.
  </Card>

  <Card title="Approval with external execution" icon="plug" href="/examples/agents/approvals/approval-external-execution">
    @approval + external\_execution.
  </Card>

  <Card title="Team approvals" icon="users" href="/examples/agents/approvals/approval-team">
    Three patterns: tool on the team, on a member agent, or on both.
  </Card>

  <Card title="Audit approval" icon="clipboard-list" href="/examples/agents/approvals/audit-approval-confirmation">
    @approval(type="audit") + requires\_confirmation; no pause, audit record only.
  </Card>
</CardGroup>

## Developer Resources

* Example code: [Approvals cookbook](https://github.com/agno-agi/agno/blob/main/cookbook/02_agents/11_approvals).
* [Approval reference](/reference-api/schema/approvals/list-approvals)
* [Tool decorator](/reference/tools/decorator)
