Content

Human-in-the-Loop Approval for AI Agent Tool Calls: A Production Guide

How to make an AI agent pause a risky tool call until a person approves it: which actions need approval, four ways to build it, what the request should contain, and how to run it in Slack or Telegram.

AI AgentOct 5, 2026

Key takeaways

  • -Human-in-the-loop approval pauses one risky tool call until a person approves or denies it, while the agent keeps working on everything else.
  • -Use approval for actions that are allowed in principle but costly to get wrong: large payments, refunds, deletes, customer-facing messages, and permission changes.
  • -Use a hard block for actions that should never run in an environment, such as deletes in production, and save approval for actions that are fine after a check.
  • -A safe approval flow fails closed: no channel, no plan, or no answer means the call does not run.
  • -The agent must be able to tell waiting apart from failed, or it will retry and send duplicate requests.
  • -Swytchcode holds matching calls in Slack or Telegram, exits with code 7 while waiting, runs the call once on approval, and expires requests after 48 hours (Business and Enterprise).

Human-in-the-loop (HITL) approval for AI agents means the agent pauses one sensitive tool call, sends a person the exact action and its arguments, and runs the call only if that person approves. Everything else in the workflow keeps moving. Add it to payments, refunds, deletes, and customer-facing messages, where a wrong call is expensive and hard to undo.

This guide covers which actions need approval, the four common ways teams build it, what a good approval request contains, and the design rules that keep it safe in production. The last section shows how Swytchcode runs approvals for every agent framework from one policy file.

What does human-in-the-loop approval mean for tool calls?

An agent decides to call a tool, for example to issue a refund. Before the request reaches the API, an approval rule checks the call. If the rule matches, the call is held, a person gets a message with Approve and Deny, and the agent is told the call is pending. Approve runs the call once. Deny cancels it. No answer means it never runs.

The important part is where the check lives. A rule written into the prompt can be argued with or ignored by the model. A rule enforced outside the model, in code or in a policy layer, cannot.

Which agent actions should wait for a person?

Approval fits actions that are allowed in principle but costly to get wrong. Common candidates:

  • Money movement above a threshold: payments, refunds, payouts, credits
  • Irreversible changes: deleting records, canceling subscriptions, closing accounts
  • Messages that reach customers: bulk email, SMS, public posts
  • Access and permission changes: adding users, granting roles, rotating keys
  • Deployments and infrastructure changes

Approval is one of three outcomes a policy can give a call. Pick the lightest control that keeps the risk acceptable:

OutcomeUse it whenExample
AllowThe action is low risk and easy to reverseReading a customer record
Require approvalThe action is allowed, but a mistake is costlyA refund over 500.00
BlockThe action should never run in this environmentAny DELETE call in production

Requiring approval for everything trains reviewers to click Approve without reading. Keep approvals for the calls that deserve a second look.

Four ways to add human approval to an AI agent

1. In-framework interrupts

Some agent SDKs pause a run when a tool needs approval. The OpenAI Agents SDK documentation describes a needsApproval rule on a tool: the run stops, returns the pending calls as interruptions, and resumes from the saved run state after you approve or reject each one. This works well when a person is already in the session. It is tied to one framework, and each team that uses a different framework rebuilds it.

2. Workflow tools with a review step

Workflow platforms add a human review step to selected tools. The n8n documentation lists review channels including its own chat, Slack, Discord, Telegram, Microsoft Teams, Gmail, Outlook, WhatsApp, and Google Chat. This suits agents that already live inside that platform.

3. A custom Slack approval gate

Headless agents running on a schedule or a webhook have no one watching a terminal, so the request has to go to a channel people already watch. The usual build: store a pending record with an approval ID, post a message with buttons, verify Slack's request signature when someone clicks, flip the record, and let the parked run read the decision. It works, but you own the storage, the signature checks, the expiry, and the audit trail.

4. A policy layer between the agent and the API

The approval rule lives in a policy file that every call passes through, whichever framework or editor made it. One rule covers every agent, and the rule is reviewed in Git like any other code. This is the model Swytchcode uses.

What should an approval request contain?

A reviewer should be able to decide from the message alone. Include:

  • What the call does, in plain language, and why it was flagged
  • The key arguments, such as the amount and the customer
  • Who or what asked for it: the account, the workspace, and the end user if the call is made on someone's behalf
  • When the request expires

Design rules for production approval flows

Fail closed
If the request cannot be sent, because no channel is configured or the approval service is down, the call must not run. A gate that opens when it breaks is no gate.

Expire every request
A refund approved three days late may no longer be correct. Set a deadline, and treat a late approval as a denial.

Approve once, run once
An approval should cover one call. If you allow reuse, scope it tightly, for example the same customer for 24 hours.

Tell waiting apart from failed
If a held call looks like an error, the agent retries it and floods reviewers with duplicate requests. Return a distinct status for pending, and do not send a second request for the same call.

Record every decision
Log who approved or denied, when, and what ran afterwards. Auditors ask for this, and so does the engineer debugging an incident.

How Swytchcode handles human approval

Swytchcode is an execution kernel that sits between your agents and the APIs they call. Approval is a policy action. When a call matches a REQUIRES_APPROVAL rule:

  1. Swytchcode sends a request to the workspace's Slack or Telegram channel with the policy's message, who asked, the workspace, and the end user when the call is made for one of your app's users.
  2. swy exec exits with code 7, so the agent or script knows the call is waiting. Running the same command again does not send a second message.
  3. Approve runs the command once. Deny stops it. Swytchcode checks for a decision every 2 minutes for the first hour, then every 30 minutes.
  4. If nobody responds within 48 hours, the request expires and the command never runs. If the request cannot be created, the command does not run and the terminal says why.

Add a rule from the CLI. Find the method's canonical ID with swy discover first, since IDs change as the catalog is updated:

swy discover "create a refund" --project stripe --json

swy policy add --name "Large refunds" --target <canonical_id> \
  --field amount --operator ">" --value 50000 \
  --action REQUIRES_APPROVAL --message "Refunds over 500.00 need approval"

swy policy list

In a version 2 policies.json, an approval rule can also reuse one approval for a while and set a shorter deadline:

{
  "id": "big-refunds",
  "target": ["<canonical_id>"],
  "when": { "field": "amount", "operator": ">", "value": 50000 },
  "action": { "type": "REQUIRES_APPROVAL", "message": "Refunds over 500.00 need approval" },
  "reuse": { "for": "24h", "same": ["customer"] },
  "approval_timeout": "2h"
}

With that rule, one approved refund to a customer covers more refunds to the same customer for 24 hours, and any request still waiting after 2 hours can no longer run. Held, denied, and blocked calls show up in swy audit policy. Approvals are configured per workspace in app.swytchcode.com, using Swytchcode's shared Slack bot or your own bot in a channel you control.

Approval workflows are included on the Business and Enterprise plans. To test the flow without a connected provider account, run the matching command with --demo.

Why run approvals in the execution kernel

  • One rule for every framework. LangGraph, CrewAI, the OpenAI Agents SDK, the Anthropic SDK, the Vercel AI SDK, and coding agents such as Cursor and Claude Code all pass through the same policy.
  • Fail-closed by design. No channel, no plan, or no answer in 48 hours means the call does not run.
  • Reviewable. policies.json is version-controlled, so a new approval rule goes through code review.
  • Auditable. Every outbound call and policy decision is recorded locally for 90 days, with sensitive values redacted.
  • Built for legacy and internal APIs. Bring your own OpenAPI spec and the same approval rules apply.

FAQ

What is the difference between human approval and a deny rule?
A deny rule stops a call immediately and permanently. An approval rule holds the call until a person decides. Use deny for actions that should never run in an environment and approval for actions that are fine after a check.

Does the agent stop working while it waits?
It should not. Only the held call waits. With Swytchcode the command exits with code 7, so the agent can continue other steps and check back later.

Where do approval requests go?
In Swytchcode, to the Slack or Telegram channel configured for the workspace. Each workspace can use its own channel.

What happens if nobody answers?
The request expires. In Swytchcode, requests always expire after 48 hours, or sooner if the rule sets approval_timeout, and an expired request never runs.

Swytchcode resources

More content