n8n Approval Workflows: Human Review for AI Agents in Slack
How to add human approval steps to n8n workflows and AI agents: Slack interactive approvals, Wait nodes, signature verification, timeouts, escalation, and audit trails, based on the official docs.

An AI agent that can send client emails, post payments, or delete records is one bad tool call away from doing real damage. The practical fix is not to abandon agents; it is to put a human decision in front of the actions that matter. This guide shows how to build that approval step in n8n three ways, with the security checks, timeouts, and audit trail that make it safe to run in a business.
Everything below is based on the official n8n and Slack documentation linked throughout, and it applies whether you self-host n8n or run on n8n Cloud.
What human in the loop means in n8n
n8n gives you two distinct approval mechanisms, and they solve different problems.
The first is tool-level human review on the AI Agent node. When enabled, the workflow pauses each time the agent wants to call a tool you flagged for review. A human sees what the agent intends to do, then picks Approve or Deny. On approval the tool runs with the input the AI specified; on denial the action is cancelled and the AI is told its action was rejected, so it can adjust or stop.
The second is an approval step inside a regular workflow. The Slack, Gmail, Discord, Telegram, Microsoft Teams, WhatsApp Business Cloud, Google Chat, and Microsoft Outlook nodes all support a Send and Wait for Response operation, which halts the workflow until a person responds. For anything more custom, the Wait node pauses a workflow until a webhook call, a form submission, or a timer.
A note on versions: n8n simplified the AI Agent node starting at version 1.82.0. The agent-type setting is deprecated, every AI Agent node now behaves as a Tools Agent, and the v1 node was removed in n8n 3.0. If you follow an older tutorial and cannot find the agent-type dropdown, that is why (see the AI Agent node docs).
Decide which actions need approval
Not every tool call deserves a human gate. Approval steps add latency and demand someone's attention, so spend them where mistakes are expensive. A simple checklist:
- Irreversibility. Sending an external email, posting a payment, deleting a record, or changing a production setting cannot be undone cleanly. Approve these.
- External audience. Anything a client, supplier, regulator, or court will see deserves review until the agent has a long clean track record.
- Money movement. Payment runs, refunds, invoice write-offs, and payroll changes should never fire unattended at first.
- Regulated records. In legal, financial services, and insurance work, an audit trail of who approved what is often a compliance requirement, not a nice-to-have.
- Volume and latency. If the action happens hundreds of times a day or must complete in under a second, a human gate will not hold. Use sampling or tighter guardrails instead.
The n8n documentation's own advice is to enable review on the risky tools first, run with oversight while you build confidence in the agent's behavior, then reduce review coverage deliberately rather than by accident.
If you operate in or sell into the EU, note that Article 14 of the EU AI Act requires high-risk AI systems to be designed so natural persons can effectively oversee them while in use. The article spells out what oversight means in practice: overseers must be able to understand the system's capacities and limits, monitor its operation, stay alert to automation bias, interpret its output, disregard or reverse that output, and interrupt the system through a stop mechanism. An approval workflow with named approvers, visible context, and a recorded decision maps directly onto several of those duties. The high-risk obligations phase in from December 2027 for Annex III systems, so building the pattern now is cheaper than retrofitting it.
Pattern 1: human review for AI agent tool calls
This is the fastest path when your workflow uses the AI Agent node and you want review on specific tools, not on the whole agent. The n8n human-in-the-loop guide describes four steps:
- Add the AI Agent node and connect a chat trigger so you can interact with the agent.
- Add the tools the agent needs. A Gmail tool to send mail, a Postgres tool to query records, an HTTP Request tool to call an internal API, and so on.
- Turn on human review for the risky tools. Open the tool's settings and enable the human review option. You can do this per tool, so the agent can search a knowledge base freely but must ask before it sends email.
- Tell the agent about the setup in the system prompt. State which tools require approval and what the agent should do when a request is denied. Without this, a denial confuses the agent and it may retry the same action.
Two details make the review useful rather than ceremonial. First, the approval message should show what the agent intends to do. n8n exposes $tool.name and $tool.parameters inside the tool configuration, and any values the agent generated with $fromAI() are exactly what the reviewer will see, so the approver is judging real inputs, not a vague summary. Second, human review still works when you nest agents: if a sub-agent's tool is flagged for review, the approval request surfaces correctly through the parent.
Pattern 2: Slack approvals with Send and Wait for Response
For approval steps that are not tied to an AI Agent node, or when the approver should not be inside n8n at all, the Slack node's Send and Wait for Response operation is the workhorse. Set the Response Type to Approval and the decision happens inside Slack, with no browser page to open.
Why Slack approvals instead of link buttons
The same operation can send simple approve or decline links. Those are fine for low-stakes confirmations, but the n8n Slack approvals documentation is blunt about the limit: anyone holding the link can click it, and n8n cannot tell who did. Slack's interactive approval buttons are different. n8n verifies every button callback using Slack's request signing, checks the responder against an approver list you define, and records who responded. For anything involving money or client communication, use the Slack-native approval, not links.
Setup checklist
- A public HTTPS instance. Slack must be able to reach your n8n server. Approval from Slack does not work against localhost; use a tunnel for testing.
- A Slack credential with the signing secret. Create the credential with a bot token and access token, then paste your app's signing secret into the Signature Secret field. Without it, n8n cannot verify interactive callbacks and approvals silently never arrive.
- The right scopes. Add
users:readandusers:read.emailto the Slack app, or the responder's email will be missing from the output. If your credential is an older OAuth2 connection, reconnect it so the new scopes are granted. - The interactivity Request URL. In the Slack app settings under Interactivity and Shortcuts, set the Request URL to
https://your-n8n-instance/webhook-waiting-slack(adjust the path if you changedN8N_ENDPOINT_WEBHOOK_WAIT). Slack allows one Request URL per app, and that URL is also where modal submissions go, so one Slack app effectively belongs to one n8n instance. Do not point two environments at the same app. - A channel your approvers can see. The approver list controls who can respond, not who can read the message. For sensitive approvals, post to a private channel.
Configuring the node
On the Slack node, choose the Message resource and the Send and Wait for Response operation, set Response Type to Approval, then decide:
- Capture Who Responded. Turn this on. It switches the approval to interactive buttons and records the responder's identity.
- Restrict Who Can Approve. List the Slack users allowed to decide, by hand or with an expression. Anyone else who clicks gets an ephemeral notice and the workflow keeps waiting. Leave the list empty and any person who can see the message can approve, which is rarely what you want.
- Unauthorized Reply. The message shown to non-approvers who click.
- After Decision. The default, Show Outcome and Remove Buttons, updates the Slack message with the decision and strips the buttons, so the first decision stands and the channel shows the result. Remove Buttons Only keeps the original text untouched, and Keep Message Unchanged leaves everything as it was.
The node's output gives you everything an audit trail needs:
{
"approved": true,
"respondedAt": "2026-10-29T06:12:10.000Z",
"data": {
"channel": "C123456",
"messageId": "1761746730.123456",
"responder": {
"id": "U123456",
"name": "j.otieno",
"username": "j.otieno",
"email": "j.otieno@example.com"
}
}
}
Branch on approved for the downstream action, and write the whole object to your audit store before you act on it.
A worked example: payment run approval
Take a finance operations workflow that assembles a supplier payment batch. The agent drafts the batch: 14 payments totalling KES 2.3 million, with payee names and bank details pulled from the accounting system. Before anything is sent to the bank API, the workflow posts to a private #payment-approvals Slack channel showing the batch total, the three largest payments, and a link to the full batch. Two named finance leads are on the approver list.
The human cost is about two minutes per batch: open the message, scan the totals, click Approve or Reject. At 30 batches a month that is roughly one hour of approver time, against the alternative of either skipping review entirely or having someone manually assemble every batch. The workflow waits up to four business hours; if nobody responds, it posts a follow-up tagging the second approver, and at 24 hours it auto-cancels the batch and notifies the requester. Every decision, with responder identity and timestamp, lands in a Postgres table the same day. That is the entire control: cheap to run, legible to an auditor, and impossible to bypass quietly because the channel shows the outcome on the original message.
Pattern 3: your own approval gate with the Wait node
Sometimes neither built-in pattern fits: the approvers are in a system n8n has no node for, you need a custom approval page, or you want the signed audit record in your own database from the start. Then you build the gate from the Wait node.
The Wait node pauses a workflow and resumes on one of four conditions: after a time interval, at a specific time, on a webhook call, or on a form submission. The webhook option is the interesting one. When the Wait node executes, n8n generates a unique resume URL for that specific execution, exposed as $execution.resumeUrl. Your workflow sends that URL to wherever the human will decide, and the decision system calls it back. You can require Basic, Header, or JWT auth on the resume webhook, and restrict it to an IP whitelist.
The mechanics matter for long waits. When a wait runs longer than about 65 seconds, n8n offloads the execution data to the database and the worker moves on; when the resume call arrives, the data is reloaded and the workflow continues. A waiting approval is therefore cheap: it does not hold a worker or count against your concurrent execution capacity. One caveat from the docs: wait timing always uses the n8n server's clock, so do not expect workflow timezone settings to shift your intervals.
The n8n team publishes a complete reference implementation of this pattern, template 16663, which routes approval requests through Slack and Postgres. It is worth studying because it gets the hard parts right: a single webhook endpoint serves both as the intake API and as Slack's interactivity callback; every Slack callback is verified against the app's signing secret and timestamp before it is trusted; the request context, channel ID, and message timestamp are stored in a Postgres approval_requests table; and when a decision arrives, the workflow returns HTTP 200 to Slack immediately, updates the original message to replace the buttons with the recorded decision, and writes the outcome back to the database. Even if you never import the template, copy its structure.
Verifying Slack signatures yourself
If you build a custom intake webhook, you must verify that requests actually come from Slack before trusting an Approve click. Slack signs every request with your app's signing secret, and the recipe from Slack's request-verification documentation is:
- Read the
X-Slack-Request-Timestampheader and reject the request if it is more than five minutes from your server's clock. This kills replayed requests. - Build the basestring
v0:timestamp:raw_bodyusing the raw, unparsed request body. Parsing and re-serializing the JSON breaks the signature. - Compute HMAC SHA-256 of that basestring, keyed with your signing secret, hex-encoded, prefixed with
v0=. - Compare it to the
X-Slack-Signatureheader with a constant-time comparison function, never a plain string equality check.
The signing secret lives in your Slack app's Basic Information page. If a request fails verification, treat it as hostile and drop it.
Timeouts, escalation, and stuck approvals
An approval that nobody answers is a stalled process, and silent stalls are how operations teams lose trust in automation. Three controls keep this from happening:
- Always set a wait limit. The Wait node's Limit Wait Time option resumes the workflow automatically after an interval or at a fixed time, even if nobody responded. Build every approval with a defined maximum wait, not an open-ended one.
- Branch on the timeout. When the limit fires, route the request somewhere useful: re-notify the channel, escalate to a second approver, or auto-deny and tell the requester. Auto-deny is the right default for anything risky, because absence of approval should never equal approval.
- Alert on aging approvals. A scheduled workflow that queries your approvals table for requests older than your SLA and posts a summary to the ops channel costs an afternoon to build and pays for itself the first time a payment run sits untouched for two days.
There is no strict documented limit on how long an n8n execution can wait, and the old five-minute cloud execution limit no longer applies, because long waits live in the database rather than in a running process. Self-hosted instances have an EXECUTIONS_TIMEOUT environment variable if you want to cap total execution time yourself. The practical constraints are your plan's execution-data retention and your own escalation design, not the platform.
Security and audit trail basics
An approval step is a security control, so it has to be built like one:
- Verify every callback. n8n does this for you on the Slack approval operation, using the signing secret in your credential. If you build a custom webhook, do it yourself as described above.
- Name your approvers. A restricted approver list plus a private channel means a leaked message or a curious colleague cannot approve their own request.
- Give approvers enough context to actually decide. An Approve button under a message that says "agent wants to call send_email" is approval theater. Show amounts, counterparties, recipients, and the exact text or parameters the agent generated, using
$tool.nameand$tool.parametersor your own message fields. - Record the decision before acting on it. The Slack approval output already includes who responded and when; persist it, along with the request payload, to a table you control. Template 16663's
approval_requeststable is a solid minimal schema. - Treat denials as data. A tool that gets denied repeatedly is telling you the agent's prompt or permissions are wrong. Review denial patterns monthly.
Common mistakes
- Missing or wrong signing secret. The approval message renders, buttons appear, and clicking them does nothing from the workflow's point of view, because n8n rejects the unsigned callbacks. The n8n troubleshooting notes call out exactly this symptom. If approvals never resume, check the Signature Secret field first.
- Testing against localhost. Slack cannot deliver interactive callbacks to a machine it cannot reach. Use a tunnel or a staging instance with a public HTTPS URL.
- Empty approver list on a public channel. Anyone who can see the message can approve. Combine a restricted list with a private channel for anything sensitive.
- Sharing one Slack app across two n8n instances. Slack allows one interactivity Request URL per app, so the second instance you connect silently steals the callbacks from the first.
- No timeout. An approval with no wait limit stalls forever, and you find out when a user asks why nothing happened.
- Old Slack credentials. If the responder's email is missing from the output, your credential predates the
users:read.emailscope. Reconnect it.
When n8n approvals are the wrong choice
Be honest about the limits before you build:
- Sub-second latency requirements. A human cannot approve inside a real-time decision path. Use deterministic guardrails instead: allow-lists, amount caps, and model-level constraints.
- Very high volume, low risk. If an action runs thousands of times a day and a mistake costs little, full review does not scale. Approve a random sample and review failures.
- Complex multi-level chains. If your approval policy has delegation rules, amount-based routing tiers, and mobile push with SLA timers, you are describing an approval management product, not a workflow node. Buy one, or commission a custom build.
- Formal signature requirements. Clicking a Slack button is not an e-signature. Where law or contract requires one, route to a signing provider instead.
Frequently asked questions
Does n8n support human-in-the-loop for AI agents natively? Yes. The AI Agent node has a per-tool human review option: the workflow pauses before the flagged tool executes and resumes on Approve, or cancels the action and informs the agent on Deny. Review requests can arrive over Slack, email, Telegram, Teams, and several other channels.
Can approvers respond inside Slack without opening a browser? Yes. The Slack node's Send and Wait for Response operation with Response Type set to Approval posts interactive buttons in the channel. Clicks are verified via Slack request signing, checked against your approver list, and the responder's identity is recorded in the node output.
How long can an n8n workflow wait for an approval? There is no strict documented limit. Waits longer than about 65 seconds are offloaded to the database, so a waiting approval consumes essentially no resources and does not count toward concurrency. Always configure the Wait node's limit anyway, so an unanswered request escalates or auto-denies instead of stalling.
How do I know who approved a request?
Enable Capture Who Responded on the Slack approval operation. The output includes the responder's Slack ID, name, username, and email, plus the channel and message ID. The email requires the users:read.email scope on your Slack app.
What happens if nobody responds? Without a wait limit, the workflow waits indefinitely. Set Limit Wait Time on the Wait node, then branch on the timeout: escalate to a backup approver, re-notify the channel, or auto-deny and inform the requester.
Can I collect approvals by email instead of Slack? Yes. Gmail and Microsoft Outlook nodes support Send and Wait for Response, and the AI Agent's human review can deliver approval requests over email channels too. The trade-off is weaker identity proof than signed Slack callbacks, so prefer Slack or a custom signed webhook for high-stakes decisions.
Where to go from here
If you are already running agents or automated workflows, pick the one action this week that would hurt most if it fired wrongly, and put one of these three patterns in front of it. Start with the Slack approval operation; it takes an afternoon and the audit record comes free. If you would rather have this designed and run for you, approvals, escalation rules, and audit trails included, that is exactly what our business automation service builds on n8n, and the same oversight pattern ships inside our AI Employees. If you are still weighing platforms, our n8n vs Zapier vs Make comparison covers the trade-offs, and the Zapier to n8n migration playbook shows how to move without breaking live workflows. For a concrete finance example, see how we structure M-Pesa reconciliation with n8n and Daraja.
About AI Agents Plus Editorial
AI automation expert and thought leader in business transformation through artificial intelligence.



