Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/DevMauricio03/n8n-whatsapp-ai-agent/llms.txt

Use this file to discover all available pages before exploring further.

Human Handoff is the mechanism that prevents the AI from responding while a human support agent is actively handling a conversation in Chatwoot. Without it, a human agent’s reply would be received by the customer alongside an AI-generated response to the same message — creating a confusing, potentially contradictory experience. The solution is a Redis key that acts as a per-conversation lock: when the key is present, n8n silences the AI pipeline entirely and lets the human remain in control. When the key expires or is explicitly deleted, the AI resumes handling messages normally.

How it works

The lock is implemented as a simple Redis key-value pair with a time-to-live (TTL). n8n sets the key the moment it detects an outgoing message from a human agent, and checks for it before invoking the AI on every subsequent inbound message from the customer.
Current vs. recommended key format:The workflow currently uses a key in the form:
human_mode:human_mode:<telefono>
This format uses the customer’s phone number as the identifier, which can cause collisions when the same phone number exists across multiple Chatwoot accounts or inboxes. For new implementations, use the recommended format:
human_mode:<account_id>:<conversation_id>
This ties the lock to a specific conversation rather than a phone number, eliminating ambiguity and making the key safe to use across multi-inbox deployments.
PropertyValue
Key (current)human_mode:human_mode:<telefono>
Key (recommended)human_mode:<account_id>:<conversation_id>
Valuetrue
TTL1800 seconds (30 minutes)

Activation flow

1

Human agent sends a message from Chatwoot

A support agent composes and sends a reply to the customer from within the Chatwoot inbox. This is the triggering action.
2

Chatwoot emits an outgoing webhook event

Chatwoot fires a webhook event to n8n with the message direction set to outgoing. This event carries the account ID, conversation ID, and sender phone number needed to construct the Redis key.
3

n8n detects the outgoing direction

The msg_from_client node identifies that the message direction is not incoming. Instead of entering the AI pipeline, execution is routed to the Human Handoff activation path.
4

n8n sets the Redis key with TTL

n8n writes the key to Redis with a value of true and a TTL of 1800 seconds. If a key already exists for this conversation from a previous handoff, the TTL is renewed from this moment.
5

AI stays silent for subsequent inbound messages

Every new message from the customer triggers the n8n webhook. At the Human Handoff check step, n8n finds the key in Redis, confirms the value is true, and terminates the execution without reaching the AI agent node. The human agent’s replies are the only responses the customer receives.

Deactivation

Automatic expiry

The lock expires automatically when the TTL reaches zero. After 1800 seconds (30 minutes) without a new human agent message renewing the TTL, the key is deleted by Redis and the next inbound customer message will be processed by the AI normally. The safer and more predictable deactivation method is to explicitly delete the key when the conversation is resolved or closed in Chatwoot. This prevents a situation where the AI resumes responding in the middle of an ongoing human-managed conversation simply because the agent paused for more than 30 minutes.
DEL human_mode:<account_id>:<conversation_id>
Do not delete the lock while an agent is still actively writing — wait until the conversation is marked resolved or the agent has confirmed they are done.

TTL renewal

Each new message sent by a human agent from Chatwoot should renew the TTL, resetting the 30-minute countdown from the time of the latest agent reply. This behavior prevents the AI from re-activating in the middle of a long-running support session simply because 30 minutes passed since the previous reply. If your support team routinely handles conversations that exceed 30 minutes, adjust the TTL based on actual measured conversation durations — do not increase it arbitrarily, as a longer TTL means the AI remains silenced for longer if an agent forgets to resolve the conversation.

Verification commands

Use these commands to inspect the Human Handoff state for a specific conversation directly from the Redis container. Check whether the key exists and read its value:
docker compose --env-file .env -f docker/docker-compose.yml \
  exec redis sh -lc 'redis-cli -a "$REDIS_PASSWORD" GET "human_mode:human_mode:<telefono>"'
Check the remaining TTL in seconds (-1 means no expiry, -2 means the key does not exist):
docker compose --env-file .env -f docker/docker-compose.yml \
  exec redis sh -lc 'redis-cli -a "$REDIS_PASSWORD" TTL "human_mode:human_mode:<telefono>"'
Replace <telefono> with the full phone number as it appears in Chatwoot, including the country code and any prefix used in the current key format.

Edge cases

If the Redis container is unreachable when n8n attempts to check for the Human Handoff key, the workflow must treat the state as unknown and fail closed — that is, it must not proceed to the AI agent. Auto-responding when the lock state cannot be confirmed risks the AI responding over a human agent. Configure the workflow’s Redis error handling to terminate the execution path rather than defaulting to the AI branch when a connection error occurs.
If a human agent sends a reply when the TTL has only a few seconds remaining, there is a narrow race condition where n8n processes an inbound customer message before the new agent reply arrives and renews the TTL. In this window, the AI could generate a response. To reduce this risk, TTL renewal should be applied eagerly — any outgoing message from Chatwoot, even a partial draft being sent, should reset the countdown. Monitor your Redis TTL values during high-volume periods to identify whether this race occurs in practice.
Chatwoot can emit outgoing webhook events for messages that were generated automatically — for example, system notifications, bot responses, or assignment messages. If n8n cannot distinguish between an automated outgoing event and a genuine human agent reply, it may activate the Human Handoff lock unnecessarily, silencing the AI for conversations that are not actually being handled by a human. Review your Chatwoot webhook payload structure to confirm whether automated events include distinguishing fields (such as message_type or sender.type) that can be used to filter them before the Human Handoff activation step.
The current key format uses the phone number as stored in the Chatwoot webhook payload. If a phone number is later stored or formatted differently — for example, with or without a leading +, with or without the country code, or with spaces removed — the key written at activation time may not match the key checked at inbound message time. This would cause the AI to respond even though a Human Handoff key exists under a slightly different key name. Normalizing the phone number to a canonical E.164 format before constructing any Redis key eliminates this class of bug entirely, and is another reason to prefer the human_mode:<account_id>:<conversation_id> format.

Test cases

The following test scenarios validate Human Handoff behavior end to end. Each is defined in the test suite referenced in Testing:
IDScenario
HH-01Agent sends from Chatwoot → AI is silenced for subsequent customer messages
HH-02TTL expires naturally → AI resumes on next customer message
HH-03Explicit DEL command → AI resumes immediately
HH-04Redis unavailable → execution terminates without AI response

Build docs developers (and LLMs) love