N8n users running AI agents: where do you still keep a human approval step?

I’m trying to understand how people safely operate n8n workflows that include AI agents.

In particular, I am curious about actions such as sending external emails, updating customer records, accessing Drive/Notion, issuing refunds, or calling third-party APIs.

  • What actions do you never let an AI step perform automatically?
  • Where do you currently use Wait nodes, Slack approvals, manual checks, or custom code?
  • Have you had a workflow do something unexpected because an AI step interpreted data incorrectly?
  • Is auditing “why this action happened” difficult in your current setup?

I’m early in research and would value real examples more than general opinions.

3 Likes

Interesting timing, I’ve been stuck on this exact question for about 6 months now. Kind of backwards compared to most people here — I didn’t start with n8n, I started with “how do you let an AI agent touch real stuff without it burning you” and that rabbit hole eventually led me to n8n.

To your first question: the pattern I keep seeing (and agree with) is that nobody sane lets an agent touch money or send external emails on its own. Refunds, payments, deleting/updating records, anything going to a client — the agent can draft it or prep it, but a human fires it. Read-only stuff and internal drafts, let it run.

Wait nodes and the HITL options do work btw. The problem shows up later — the approval logic sits inside each workflow, so once you have 10, 20 of them you’re rebuilding the same gate over and over and the real risk isn’t the gated paths, it’s the one workflow where you forgot.

Your auditing question is honestly the best one in the list and the least solved. n8n’s execution log tells you what ran, but try reconstructing “why did the agent decide this and who approved it” three weeks later when a client asks. There’s basically no tamper-proof trail natively.

That last part is actually what I ended up building because of all this — a policy layer that sits in front of the workflows and checks each agent action against rules (allow / deny / needs approval) with a signed audit log. It’s working but early — there’s an n8n community node for it that I’m sure has rough edges I haven’t found yet, since so far the main tester has been me. If anyone reading this runs agents that touch anything scary and wants to hammer on it, I’d genuinely love that — free, I just want to watch someone else use it and hear where it breaks. Either way, curious what others answer to your audit question because I think it’s the most underrated one here.

The pattern @BorkoB describes - rebuilding the same gate across 10-20 workflows - is the real pain point. The fix I use: extract the entire approval gate into a shared sub-workflow (Wait node + webhook callback) and call it with Execute Workflow from every agent that needs a human check. You pass the action summary, the calling workflow ID, and a resume URL, and the sub-workflow handles the Slack/email notification and the wait. When you update the approval logic (e.g., change the approver or add a second reviewer), you do it in one place.

For the audit gap: I log $execution.id, the proposed action, and the human’s Approve/Reject response to a Postgres table before resuming. Not tamper-proof at the infra level, but enough for most client-facing accountability needs.

1 Like

@nguyenthieutoan Really solid pattern — most people never even get as far as centralizing the gate into one sub-workflow with a clean resume URL. That alone kills the “rebuild it 20 times” problem.

You named the exact thing I ended up building around: “not tamper-proof at the infra level.” That’s the part that bit me hardest — a plain table means anyone with DB access (a bug, a bad migration, a compromised agent) can quietly edit history, and there’s no way to prove after the fact that a row wasn’t touched. Hash-chaining each entry — every row’s hash includes the previous row’s hash — closes that specific hole without needing a full blockchain, and it’d bolt onto exactly the setup you described.

Genuinely curious: has tamper-evidence at that level ever actually come up for you as a real ask, or has “good enough for client accountability” held up fine so far? In my experience it stays theoretical right up until a client says “prove it” after something goes wrong.

If you’re ever curious how the hash-chain + policy layer would plug into a setup like yours, happy to show you sometime — really appreciate you engaging with this so thoughtfully, it’s the best kind of feedback I could ask for.

Disclosure: I’m Gilad, co-founder of Sequence (getsequence.io). We build an API that lets AI agents move real money between bank accounts. For us an agent misreading data doesn’t send a wrong email, it moves dollars, so humans stay in control at every layer by design. To your questions:

Actions we never let an agent do alone: an agent can only trigger money flows a human wrote and enabled in the dashboard first. It can’t create or enable a rule by itself, and manual transfers only work between account pairs the human explicitly allowed, with a per-transfer cap.

Where the control lives matters most, and it’s where I’d push back on the usual n8n pattern. If approval is a node in the workflow, the agent (or a misconfigured flow) can route around it. We enforce it below the agent, server-side: keys are scoped (which accounts, which rules, which source/target pairs, max amount) and out-of-scope calls just fail with a 403 regardless of what the agent thinks it’s doing. Money-moving calls also support dry-run simulation so the agent can preview before anything real happens. On top of that we’re rolling out per-action approval right now: the API call won’t execute, it returns an approval URL where the human sees a plain summary (“transfer $X from A to B”) plus the agent’s stated reason, then approves or denies. Unanswered requests auto-deny.

On auditing: we log every call with the key and permissions used, plus the agent’s stated reason. Real example: a user’s agent tried to edit an active payroll-split rule, got rejected, the user disabled the rule manually, and the agent retried logging “user disabled the rule in the app; now applying the approved edits.” Without the reason trail that history would be unreadable.

1 Like

@BorkoB Honestly it’s stayed at “good enough” for me so far, but only because none of my clients have hit a real dispute yet. The plain-table approach falls apart exactly the way you describe the moment someone needs to prove a row wasn’t touched after the fact, not before. Hash-chaining is the right fix and it’s cheap to bolt on: add a hash column that’s SHA256 of (row data + previous row’s hash), computed in a Code node right before the insert. Verification is just a separate scheduled workflow that walks the table and recomputes the chain, flags a break. I haven’t needed it yet, but I’d rather add it now than explain to a client later why I didn’t.

2 Likes