---
title: "Approvals"
description: "An approval asks whether a tool call should happen at all. A call that needs approval waits until a person answers, for minutes or for days, without holding a Worker."
canonical_url: "https://docs.superdurable.io/agent-frameworks/approvals/"
source: "docs/content/agent-frameworks/approvals.mdx"
locale: "en"
language: "python"
---

> Index of every page for AI agents: https://docs.superdurable.io/llms.txt

# Approvals

Code on this page is in Python. Other languages: [TypeScript](https://docs.superdurable.io/agent-frameworks/approvals.typescript.md)

An approval asks whether a tool call should happen at all. A call that needs approval waits until a person answers, for minutes or for days, without holding a Worker.

<a id="approvals"></a>

## How an approval works

A tool call that needs approval waits in its own `AwaitToolApproval` Step until someone answers. The wait holds no Worker slot, and it survives Worker restarts and deploys. A person approves or rejects the call [from your application](https://docs.superdurable.io/agent-frameworks/approvals.md#approve-from-your-application) or [in Dex Web](https://docs.superdurable.io/agent-frameworks/approvals.md#approve-in-dex-web). The model sees a rejection and can react to it.

A tool's policy decides whether its calls wait for approval; [Require approval](https://docs.superdurable.io/agent-frameworks/tool-calls.md#require-approval) gives the defaults and how to change them per tool.

Approval is separate from retry: a refund with an idempotency key is still a real refund.

While an approval waits, the turn waits with it, and new user messages queue until the turn ends. If an approval must not wait forever, set an approval deadline. Dex rejects a call that is still pending at the deadline. See [Approval deadlines](https://docs.superdurable.io/reference/agents/approvals.md#approval-deadlines).

<a id="approve-from-your-application"></a>

## Approve from your application

Your application answers a pending call with the session Flow's `resolve_interrupt` RPC. It passes the interrupt ID, whether the call is approved, and an optional message for the model. In Python, `AgentSessionClient` wraps the RPC as `resolve_interrupt`. The snapshot from `get_agent_snapshot` lists pending calls under `pending_interrupts`.

The example apps expose this RPC as an HTTP route. These are excerpts: the request helpers, such as `session_request`, are in each tab's linked file. The [complete quick start app](https://docs.superdurable.io/agent-frameworks/add-to-your-agent.md#web-handler) shows the same route with nothing left out.

**Python**

```python
    @blueprint.post("/interrupts/resolve")
    async def resolve_interrupt() -> Response:
        body, session_id = await session_request()
        interrupt_id = _required_string(body, "interrupt_id")
        if not isinstance(approved := body.get("approved"), bool):
            raise BadRequest("approved must be a boolean")
        rejection_message = body.get("rejection_message")
        if rejection_message is not None and not isinstance(rejection_message, str):
            raise BadRequest("rejection_message must be a string")
        accepted = await sessions.resolve_interrupt(
            session_id, interrupt_id, approved=approved, rejection_message=rejection_message
        )
        return jsonify(accepted=accepted)
```

Example: [examples/python/agent-harnesses/agent_harness_examples/http_routes.py](https://github.com/superdurable/dex/tree/main/examples/python/agent-harnesses/agent_harness_examples/http_routes.py)

Check who may approve before you call the RPC. The example routes accept only a caller that holds the session's signed token. `resolve_interrupt` is safe to retry: a second call for the same interrupt returns **False** and changes nothing. [RPCs during a deploy](https://docs.superdurable.io/agent-frameworks/production.md#rpcs-during-a-deploy) covers what a caller sees while Workers restart.

<a id="approve-in-dex-web"></a>

## Approve in Dex Web

You can also approve a call in Dex Web. Dex Web shows the **Agent session** tab for a Flow type whose session graph the server holds.

The [Agent Quick Start](https://docs.superdurable.io/agent-frameworks/quick-start.md) program uploads that graph itself, in Python and in TypeScript: its Worker passes the graph in its Worker options (`flow_definitions` in Python, `flowDefinitions` in TypeScript) when it starts. So with plain **dexcli dev**, Dex Web already shows the tab. The upload needs recent Dex Agents and Dex Server releases; [Upload the session graph from the Worker](https://docs.superdurable.io/reference/agents/dex-web.md#upload-the-graph) has the details.

Then approve the call:

1. Open the session's run. Its Flow ID is the session ID.
2. Select the **Agent session** tab.
3. Set **Working as** to `agent-quick-start.operate`, the permission in the graph.
4. Select **Approve** or **Reject** on the `cancel_order` card. Dex Web calls `resolve_interrupt` for you.

[Show sessions in Dex Web](https://docs.superdurable.io/reference/agents/dex-web.md) covers both paths for production.

## Next

- [Tool Calls](https://docs.superdurable.io/agent-frameworks/tool-calls.md)
- [Approvals reference](https://docs.superdurable.io/reference/agents/approvals.md)
