Skip to content

n8n Human in the Loop: Native Review or ActionBox?

Compare n8n's built-in human review with ActionBox, then build an approval workflow using the community node or the API. Includes a safe first test.

Actual n8n canvas showing a sample customer reply, ActionBox approval, and separate approved and revision branches

Select the screenshot to inspect the workflow at full size.

An n8n human-in-the-loop workflow pauses before a consequential operation and continues only after a person answers. You can do this with n8n's built-in review tools. The ActionBox community node is another option when the decision needs to be available beyond one n8n workflow. The direct API gives you more control over the request and recovery logic.

n8n's Gmail node documentation covers approval messages and human review for AI Agent tool calls. Its Wait node can also pause an ordinary workflow. Start there when the decision only matters inside n8n and the built-in delivery path suits your reviewers.

Use ActionBox when the decision needs to sit in the same shared inbox as requests from other systems, or when another application must be able to read the decision after an n8n execution ends.

Your workflow needsStart with
Approve an AI Agent tool call in a supported n8n channelNative n8n review
Pause one ordinary n8n workflow and resume it from a form or authenticated webhookn8n Wait node
Give reviewers one inbox for n8n and requests from other applicationsActionBox
Let another service read the decision later using a saved Action IDActionBox

The workflow pictured above is a local demo. It prepares a sample customer reply, waits at Request Approval, then separates the approved path from Hold draft for revision. The approved path records a demo outcome; it does not send an email.

Run the importable workflow template with its harmless demo operation first. Once both branches work, try a representative case: a workflow drafts a reply about a delayed order. Put the recipient, subject, and full draft in the review request, but keep the demo operation while testing. Only after approval, rejection, and timeout behave as expected should you replace it with an email-sending node. The manual API example later in this guide uses a refund to show the additional checks needed before money moves.

ActionBox stores the review request and answer. n8n still owns the workflow and executes the approved operation. If the draft or recipient changes after approval, request a new decision for the changed version.

Fastest path: install the ActionBox community node

Install n8n-nodes-actionbox on an n8n instance you administer. In Settings → Community Nodes → Install, enter the package name, review n8n's notice, and add an ActionBox node to your workflow. The tested compatibility target is n8n 2.38.7. The connector has not been verified for n8n Cloud.

The Request Approval and Wait operation creates the request and pauses the execution. After the decision, branch only when actionbox.approved is true. Rejection, expiry, cancellation, timeout, a changed review snapshot, and an invalid response all return false.

The Request Approval and Wait operation configured in a local n8n workflow
The real node settings for the customer-reply demo. The selected credential's name is visible, but its key is not. No email is sent by this workflow.

Use the importable n8n workflow template for the shortest setup. It includes a harmless demo operation and reports success after the approved branch runs. The complete credential, callback, and recovery contract is in the n8n integration guide.

Before a live test, give your n8n instance a reachable HTTPS callback address and keep its execution data for the duration of the wait. Create a dedicated ActionBox Source, then put its Source key and webhook signing secret in n8n credentials. The integration guide walks through these requirements and the credential test.

The rest of this article shows the direct HTTP integration. Keep it when you need custom request fields or already own the surrounding wait and recovery logic.

Build the first approval on the n8n canvas

The downloadable template has six nodes, so you can see the decision path before connecting another service. The pictured customer-reply demo has one extra input node and uses different names for the two exits; it follows the same approval branch:

  1. Start triggers a manual test.
  2. Request Approval creates the ActionBox request and waits for a reviewer.
  3. Approved checks {{ $json.actionbox.approved }}. Only true goes to the operation branch.
  4. Demo Operation does nothing outside n8n. Report Success records that this demo branch completed.
  5. Not Approved is the separate exit for rejection, expiry, cancellation, timeout, or an invalid decision.

Run it once with Approve and once with Reject. Inspect the two executions before editing the demo node. The template walkthrough covers import, credentials, and the callback setup step by step.

The manual API workflow

This example puts a refund approval between an automated check and the refund API without relying on the community node:

Architecture Flow
1 Create Action with request_id 2 Show amount and reason 3 Wait for up to 30 seconds 4 Current authoritative state 5 Issue refund with request_id 6 Report success or failure Stop without refunding n8n workflow Actionbox Reviewer Refund API API- n8n workflow Actionbox Reviewer Refund API API-

The Actionbox Source key can create, read, cancel, and report outcomes for its own Actions. Keep it in an n8n credential. Do not paste it into a Code node, workflow export, URL, or expression.

1. Start with a stable input

The workflow needs an identifier that means "this exact refund request," even after a retry. A database row ID, payment ID, or job ID works. An n8n execution ID alone is weaker because a manual restart can produce a new execution for the same business operation.

Use an input shaped like this:

json
{
  "request_id": "refund_8472",
  "customer": "Acme Corp",
  "amount": "425.00 USD",
  "reason": "Duplicate invoice",
  "approval_expires_at": "2026-10-01T22:00:00Z"
}

Replace the sample deadline with a future time appropriate for your request. Persist that time with the original input; recomputing it during a retry changes the request payload.

Pass only the context a reviewer needs. Payment credentials, full customer records, access tokens, and hidden model prompts do not belong in an approval request.

2. Create the Action with an HTTP Request node

Configure an n8n HTTP Request node named Create approval:

SettingValue
MethodPOST
URLhttps://api.actionbox.cloud/v1/actions
AuthenticationHeader credential containing Authorization: Bearer <Source key>
HeaderIdempotency-Key: n8n:refund:{{$json.request_id}}
Body content typeJSON

Use this request body:

json
{
  "title": "Approve refund {{$json.request_id}}?",
  "description": "Review this refund before n8n calls the payment provider.",
  "priority": "high",
  "expires_at": "{{$json.approval_expires_at}}",
  "interaction": {
    "type": "boolean",
    "label": "Issue this refund?",
    "true_label": "Approve refund",
    "false_label": "Reject"
  },
  "context": [
    {
      "type": "key_value",
      "title": "Refund request",
      "items": {
        "Request": "{{$json.request_id}}",
        "Customer": "{{$json.customer}}",
        "Amount": "{{$json.amount}}",
        "Reason": "{{$json.reason}}"
      }
    }
  ],
  "metadata": {
    "origin": {
      "provider": "automation",
      "ref": "n8n refund {{$json.request_id}}"
    },
    "request_id": "{{$json.request_id}}"
  }
}

Actionbox returns the Action in data. Keep data.id, data.action_version, and data.fingerprint available to later nodes. Within the documented idempotency retention window, retrying the same payload and key returns the same logical Action if n8n is unsure whether the first request succeeded. Persist the returned Action ID with the business request so later recovery can read it directly.

Do not reuse the key for a later, genuinely different refund. Idempotency prevents duplicate requests; it is not a general cache key.

3. Wait without holding one connection forever

Add another HTTP Request node named Read approval:

plaintext
GET https://api.actionbox.cloud/v1/source/actions/{data.id}?wait_seconds=30

Use the same Source credential. The request waits for a state change for up to 30 seconds, then returns the current Action. This is a bounded long poll, not an hour-long HTTP request.

After the read, use a Switch node:

Action stateNext step
openLoop back to Read approval
resolved by a user, matching the saved version and fingerprint, with response.type = boolean and response.value = trueContinue to the refund node
resolved with any other responseStop as rejected
expired or cancelledStop without changing money

The expires_at value prevents the loop from waiting forever. Actionbox makes an expired Action terminal. Your workflow should not invent an approval because a timer, network request, or credential check failed.

n8n's Wait node is still useful for longer backoff intervals or a separate webhook design. The source read above already provides a bounded wait, so an extra Wait node is optional here.

4. Put the side effect after the decision

Only the approved Switch branch should reach the refund API. Give that API the same request_id as its idempotency key if the provider supports one.

This protects two different boundaries:

  • The Actionbox key prevents duplicate human requests.
  • The refund provider key prevents duplicate money movement after retries.

An approval says the operation may run. It does not prove that the operation ran once, or that it succeeded.

5. Report the execution outcome

After the refund node, call:

plaintext
POST https://api.actionbox.cloud/v1/actions/{data.id}/outcome

For a successful refund, send:

json
{
  "status": "success",
  "duration_ms": 1840,
  "rollback": false,
  "reason_code": null,
  "action_version": 1,
  "fingerprint": "the fingerprint returned by Actionbox"
}

Connect the refund node's error output to a second outcome request with status: "failed" and a bounded reason_code, such as provider_rejected. Do not put raw provider errors or customer data in the reason code.

Use the Action's actual action_version and fingerprint, not the sample values above. They bind the outcome to the exact decision the reviewer saw.

What happens when something goes wrong?

FailureSafe behavior
Create request times outRetry with the same idempotency key
Actionbox cannot be reachedStop before the refund node
Reviewer rejectsEnd the workflow without refunding
Approval expiresEnd the workflow without refunding
n8n restarts while waitingRecover the saved Action ID and re-read it; retry create only with the original payload and key within its retention window
Refund API fails after approvalReport a failed outcome; do not rewrite the decision
Outcome report failsRetry the same outcome request

If an operator manually stops the workflow while its Action is still open, call POST /v1/actions/{id}/cancel from your n8n error workflow when possible. That keeps an abandoned request from looking actionable.

Polling or a callback-based n8n workflow?

The example uses polling so the workflow reads the current Action before deciding what to do. Preserve the business request and Action ID outside transient node output if recovery must survive a new execution.

A callback receiver is another option when the waiting period is long. It must verify the Actionbox signature, deduplicate the event, and correlate it with the saved request before resuming work. A received HTTP request alone is not approval. Follow the webhook approval integration guide for that receiver contract instead of sending an unchecked callback directly to the refund node.

Check the workflow with a simulated refund

Run the workflow against a test receiver before using a payment credential. Approve one request, reject another, and let a third expire. Only the approved request should reach the simulated refund step.

Then retry the create request with the same input and restart a waiting execution. Check that each business request still maps to one Action. Finally, simulate a downstream timeout and confirm that recovery checks the payment result before trying again. Duplicate approval requests and duplicate refunds are separate problems.

For reviewer selection, deadlines, and the information to include in a request, use the human-in-the-loop automation design guide.

Ship the first workflow

Create a Source, store its one-time key in n8n credentials, and test the approve, reject, expiry, restart, and downstream failure paths before connecting a real payment provider.

Create a free Source · Read the n8n integration guide · See the human approval API

About the author

Suson Sapkota

Suson founded ActionBox and works in software and data engineering. He writes about approval workflows, background jobs, and how to verify what happened after a human decision.

Turn the next risky operation into a reviewable decision.

Create a free Source, run the example from this guide, and keep the decision and execution outcome connected.