← Blog

·

From bot to human on WhatsApp: when and how to hand off the conversation

Updated on October 29, 2026

To hand off a WhatsApp conversation from a bot to a human, your system changes the conversation state from “bot” to “waiting for human”, stops generating automated replies, lets the customer know, and gives the agent a summary with the data already collected. The handoff should happen when the customer asks for it, when the topic is sensitive, when the bot fails twice, or when the customer is a priority. The WhatsApp Business policy allows automation within the 24-hour window, but requires prompt, clear and direct escalation paths.

The official WhatsApp Business API has no “transfer” button: your software does the handoff. This guide covers triggers, what to pass to the agent, how to pause and resume the bot, SLA, and pseudocode.

Why handoff is mandatory, not optional

The WhatsApp Business Messaging Policy says a business can use automation when replying within the 24-hour window, as long as it keeps prompt, clear and direct escalation paths. The list of accepted options includes:

  • transfer to a human agent within the same conversation;
  • a phone number;
  • an email address;
  • support on the business’s website;
  • a visit to a store or branch;
  • a support form.

An in-chat transfer gives the best experience; the other options work as a fallback outside business hours.

AI bots have one more reason: Meta’s terms restrict general-purpose AI assistants on the platform, and a customer service bot with a narrow scope and a path to a human is clearly on the permitted side. The details are in Meta’s AI policy for chatbots.

The four handoff triggers

TriggerHow to detect itExample
Explicit requestKeywords, a “Talk to an agent” button, or the LLM classifies the intent“I want to talk to a person”
Sensitive intentA list of topics the business decides to handle only with peoplecancellation, complaint, disputed charge, health data
Repeated failureA counter of unsuccessful replies in the same conversationthe bot didn’t understand twice in a row
Priority customerA CRM lookup by WhatsApp numbercorporate contract customer, order above a certain amount

Explicit request

Three layers help:

  1. A button always at hand. Include “Talk to an agent” as an option in the bot’s interactive messages. See interactive messages.
  2. Keywords. “agent”, “human”, “person”, “manager”. Simple, fast and with no LLM cost.
  3. Intent classification. If the bot uses an LLM, ask it to flag the talk_to_human intent when the customer asks in other words.

Sensitive intent

Define the list with the customer service and legal teams, not with the tech team. Cancellation, disputed charges, formal complaints and any conversation involving sensitive data (health, for example) usually make the list. Brazil’s data protection law, the LGPD, treats health data as sensitive personal data (art. 5, II, of Law 13,709/2018); this article does not replace advice from a lawyer about your case.

Repeated failure

Count failures per conversation (“I didn’t understand”, empty search, customer repeating the question). Two in a row is a good starting point for handing off; reset the counter when the bot gets it right.

Priority customer

The webhook carries the customer’s number in messages[].from. With it, your system checks the CRM before the bot replies. If the customer has an account manager or a high-value order in progress, the conversation can go straight to the human queue, or the bot does only the triage and hands off.

Want to try it while you read? Create a Vectalk account and send your first message through the official API. Create free account →

The conversation state machine

The core of the handoff is a state field per conversation, stored in the database by the customer’s wa_id. Every event that arrives through the webhook passes through it before any reply.

                  handoff trigger
   ┌──────┐  ───────────────────────────▶  ┌────────────────────┐
   │ bot  │                                │   waiting_human    │
   └──────┘  ◀──── timeout, no agent ────── └────────────────────┘
      ▲          (bot notifies and offers           │
      │           another channel)                  │ agent takes over
      │                                             ▼
      │                                    ┌──────────────┐
      └──────── agent returns it ───────── │    human     │
               or conversation idle        └──────────────┘
StateWho repliesWhat the bot doesExits when
botBotReplies normallyA trigger fires
waiting_humanNo one automaticallyNotifies once and stays silentAn agent takes over, or the maximum wait time runs out
humanAgentNothing; only logs the messagesThe agent returns it, closes it, or the conversation goes idle

Two common mistakes:

  • The bot talking over the agent. This happens when the state lives only in process memory or when two workers process the same conversation. Store the state in the database and process each conversation’s messages in order.
  • A conversation stuck in human forever. The customer comes back a week later and nobody answers, because the bot thinks someone is handling it. Use an inactivity timeout to return it to the bot.

What to pass to the agent

The agent shouldn’t have to read 40 messages to understand the case. Along with the handoff, deliver a card with:

ItemWhere it comes from
Name and numbercontacts[].profile.name and messages[].from in the webhook
Handoff reasonThe trigger that fired (request, sensitive, failure, priority)
2 or 3 line summaryGenerated by the LLM from the history, or assembled from the flow’s answers
Data already collectedOrder number, partial CPF (Brazilian taxpayer ID), email, product
SourceAd, website, QR code; the webhook carries the referral object when the conversation starts from a Click-to-WhatsApp ad
Time of the customer’s last messagemessages[].timestamp, to know how much of the 24-hour window is left
Link to the full historyYour database or CRM

An example payload your system can publish to the support queue or the CRM:

{
  "conversation_id": "5511988887777",
  "reason": "sensitive_intent:cancellation",
  "summary": "Customer wants to cancel the annual subscription. Already provided email and order number. Asked about a prorated refund.",
  "data": { "order": "48213", "email": "customer@example.com" },
  "source": { "type": "ad", "source_id": "120226305854810726" },
  "last_customer_message": "2026-10-29T14:02:11-03:00",
  "window_expires_at": "2026-10-30T14:02:11-03:00",
  "priority": "normal"
}

The LLM summary can be wrong: show the full history right below it.

How to notify the customer

The transition message needs to say three things: that a person will take over, how long it should take, and what to do if it’s outside business hours.

  • During business hours: “I’m bringing in someone from our team. The average wait right now is a few minutes, and you don’t need to repeat anything.”
  • Outside business hours: “Our team is available Monday to Friday, 8am to 6pm. I’ve logged your case and someone will reply here first thing. If it’s urgent, call (11) 0000-0000.”

Send the notice once. If the customer writes again while waiting, the bot doesn’t reply to every message; at most, it repeats the notice after an interval. Welcome and away messages based on business hours are covered in welcome and away messages on the API.

Watch the 24-hour window

Free-form text can only be sent up to 24 hours after the customer’s last message. If the human queue is slow and the window closes, the agent can no longer reply with free-form text: they need an approved template to reopen contact. That’s why the agent’s card shows when the window expires, and the queue should be sorted with that deadline in mind. The rules are in the WhatsApp 24-hour window.

How to return to the bot

The return to the bot can happen in three ways:

  1. The agent returns it. A “Return to bot” button in the support tool changes the state to bot. The bot shouldn’t send a message at that moment; it only resumes replying on the customer’s next message.
  2. The agent closes the case. When the case is closed, the state goes back to bot and the support history is recorded for the next conversation.
  3. Inactivity. If the conversation is in human and nobody writes for a set period (for example, a few hours), the system returns it to the bot.

When it comes back, include a note in the LLM context such as “case handled by an agent on such date”, so the bot doesn’t reopen the topic.

SLA: what to measure

Measure the handoff with data your own system already records:

MetricHow to calculate it
Handoff rateHanded-off conversations ÷ conversations handled by the bot
Handoffs by triggerCount by reason (request, sensitive, failure, priority)
Time until an agent takes overTime it entered human − time it entered waiting_human
Windows lost in the queueConversations where the 24-hour window closed before the agent replied
Returns to the botConversations that went back to bot and were resolved without another handoff

Many handoffs due to “failure” mean the bot is missing content; many due to “explicit request” right on the first message suggest the bot doesn’t introduce itself well. General support metrics (first response time, average handling time, CSAT) are covered in WhatsApp customer service metrics.

Router pseudocode

The router runs for every incoming message, after deduplication by the wamid ID.

def route(msg, conversation):
    conversation.last_customer_msg = msg.timestamp
    log_to_history(conversation, msg)

    if conversation.state == "human":
        notify_agent(conversation, msg)           # the bot stays silent
        return

    if conversation.state == "waiting_human":
        if max_wait_exceeded(conversation):
            send_text(msg.from_, OTHER_CHANNEL_NOTICE)
            conversation.state = "bot"
        return                                    # don't reply to every message

    # state == "bot"
    reason = detect_trigger(msg, conversation)    # request, sensitive, failure, priority
    if reason:
        return hand_off(conversation, reason)

    reply = bot_reply(conversation)
    if reply.failed:
        conversation.failures += 1
        if conversation.failures >= 2:
            return hand_off(conversation, "repeated_failure")
    else:
        conversation.failures = 0
    send_text(msg.from_, reply.text)


def hand_off(conversation, reason):
    conversation.state = "waiting_human"
    conversation.queued_at = now()
    send_text(conversation.wa_id, handoff_notice(within_business_hours()))
    publish_to_human_queue({
        "conversation_id": conversation.wa_id,
        "reason": reason,
        "summary": summarize(conversation.history),
        "window_expires_at": conversation.last_customer_msg + hours(24),
    })


def agent_took_over(conversation, agent_id):
    conversation.state = "human"
    conversation.agent = agent_id
    record_metric("time_to_take_over", now() - conversation.queued_at)


def return_to_bot(conversation):
    conversation.state = "bot"
    conversation.failures = 0
    add_context_note(conversation, "human support completed")

send_text calls the API with Meta’s standard payload (type: "text"); the queue and notifications live in your tool (tickets, CRM, your own screen).

What if the agent replies from their phone?

With coexistence, the same number lives in the WhatsApp Business app and on the API. Messages the agent sends from the app reach your system as echo events. The router can use that echo to switch the conversation to human automatically: if a person replied from the phone, the bot steps aside. What syncs and what doesn’t is covered in coexistence: what syncs.

How to do the handoff with Vectalk

Vectalk provides the official API: you receive webhooks in Meta’s format and send through the POST https://apis.vectalk.com.br/api/messages endpoint, with the same payload. The Vectalk dashboard has no support inbox and no built-in bot. The router, the conversation state and the agent screen live in your system or in the tool you connect to the API (a CRM, a customer service platform, an n8n flow).

In practice, the setup looks like this:

  1. Register your router’s URL as the instance webhook (webhooks documentation). You can register more than one URL; all of them receive the same event.
  2. The router decides between bot and human and sends replies through the API.
  3. The support tool reads and replies through the same calls, or the team uses the app on their phone with coexistence.

If several agents will use the same number, see multiple agents on the same number. To get started, create your account at apps.vectalk.com.br/register and read the guide to the official WhatsApp Business API.

Frequently asked questions

Does the WhatsApp Business API have a native human handoff feature?

No. The Cloud API sends and receives messages; your system decides whether the reply comes from the bot or from a person. The handoff is a state change in your database, not an API call.

What happens if nobody takes over the conversation?

Set a maximum time in the queue. When it runs out, the bot tells the customer, offers another channel (phone, email, form) and logs the case for follow-up. If the 24-hour window closes, follow-up can only be done with a template.

Are the agent’s messages charged like the bot’s?

Yes. For Meta, a free-form text reply within the window is a service message, whether written by a person or by a third-party AI. Since October 1, 2026, each number gets 1,000 free service messages per month and pays from the 1,001st on; for recipients in Brazil, the rate is R$ 0.0350 (Brazilian reais) per delivered message.

Can the bot suggest replies to the agent?

Yes. In this model, the LLM generates a draft on the agent’s screen, and the agent reviews and sends it. It’s a way to keep a human in control on sensitive topics without losing speed.


Official sources consulted on October 29, 2026: WhatsApp Business Messaging Policy (updated on September 23, 2026), Meta Terms for WhatsApp Business Platform, Customer service window, Platform pricing, Text message webhook and referral object, Webhooks (Vectalk), Law 13,709/2018 (LGPD, Brazil’s data protection law).

Put your business on the official WhatsApp

Create your account, connect your number to the official API (you can keep the app with coexistence) and start serving customers and sending messages.