How to Set Up Headless Human Handoff (API-Only Agent Inbox)

Headless human handoff lets your own application act as the WhatsApp gateway. You implement the Meta webhook handler and chatbot orchestration (e.g. Voiceflow or Botpress), while using HitlChat purely as the live-agent inbox. You push inbound messages to the HitlChat API; your agents reply in HitlChat; we send those replies (and a “resolved” event) back to your webhook endpoint, and your gateway handles the actual message sending via Meta.

What is headless human handoff?

In a normal HitlChat setup, HitlChat connects to WhatsApp for you and receives the messages. In headless mode, your own system stays in charge of WhatsApp — HitlChat never becomes the webhook receiver for your number and never sends messages on its own. Instead:

  • Inbound: your gateway forwards the WhatsApp message to our API, and it appears in the agent inbox.
  • Outbound: when an agent replies, HitlChat sends the message to your webhook as a ready-to-send Meta payload — your gateway forwards it to WhatsApp.
  • Resolved: when an agent closes the chat, HitlChat fires a conversation_resolved event to your webhook so you can clean up state.
Think of it as “bring your own transport”: you keep your WhatsApp pipeline; HitlChat is just the human inbox bolted on via API.

Who it’s for

Use this mode when you already run your own WhatsApp gateway and just want a human agent inbox — for example:

  • You receive WhatsApp via the Meta Cloud API into your own webhook (a custom backend, automation tool, etc.).
  • Your bot logic (Voiceflow, Botpress, or a custom flow) lives outside HitlChat and you only want HitlChat for the live-agent step.
  • You need your gateway to remain the single point that talks to Meta for sending and receiving.

If you’d rather HitlChat manage the WhatsApp connection for you, use one of the standard methods instead — see Connect to WhatsApp.

What you need

  • A HitlChat account.
  • Your own WhatsApp gateway already receiving Meta webhooks for your number.
  • From Meta: your WhatsApp Business Account ID, Phone Number ID, and a permanent (system-user) access token.
  • A webhook URL on your gateway that can receive HitlChat’s outbound events.
  • Your HitlChat API key for the inbound endpoint — it’s your User ID, shown under My Account → API.
1

Choose “No chatbot” in the setup wizard

In the left menu, open Configuration. On the Integration Setup step, under Select Integration Type, choose No chatbot — your bot runs in your own gateway, so HitlChat doesn’t need one. Click Next.

2

Pick “External / API — Headless Human Handoff”

On the WhatsApp Connection Options step, choose External / API — Headless Human Handoff. This is the “bring your own transport” option: HitlChat acts as the agent inbox only, while your gateway stays the WhatsApp webhook receiver and sender. Click Next.

3

Enter your details & save

Fill in the four fields and click Save:

  • WhatsApp Business Account ID — from Meta; we use it to match the inbound payloads you forward.
  • Phone Number ID — from Meta; included in the outbound payloads we send you.
  • Meta Access Token — a permanent / system-user token. HitlChat uses it only to download inbound media (images, video, audio, documents) so you can forward Meta payloads verbatim. It is never used to send messages.
  • Webhook URL — your gateway endpoint. We send agent replies and resolved events here.

On save, HitlChat validates your Meta credentials (token, Phone Number ID and WABA) and checks that your webhook URL is reachable — if anything is wrong, the save is rejected with a clear message.

HitlChat External / API headless human handoff configuration: WhatsApp Business Account ID, Phone Number ID, Meta Access Token and Webhook URL

The External / API configuration step.

Use a permanent token. A short-lived token will expire and break inbound media.

How the two-way flow works

  1. A customer messages your number → Meta → your gateway (unchanged).
  2. Your gateway POSTs the message to HitlChat’s inbound API → it appears in the agent inbox.
  3. An agent replies → HitlChat sends the reply to your webhook as a ready-to-send Meta payload.
  4. Your gateway forwards it to Meta → the customer receives it.
  5. The agent resolves the chat → HitlChat fires conversation_resolved to your webhook.

The next section shows the exact API calls and payloads for each step.

Authentication & base URL

The inbound API is authenticated with your API key as a Bearer token. Your key is your User ID, shown inside HitlChat under My Account → API.

Authorization: Bearer YOUR_API_KEY
https://api-portal.hitlchat.io/api/v1/public/

Step 4 · Forward inbound messages

From your gateway, POST the verbatim Meta webhook payload to the inbound endpoint — no reshaping. The first message for a contact opens a conversation (and creates the contact); later messages append to it.

POST/v1/public/inbound
# Forward a text message exactly as Meta sent it
curl -X POST https://api-portal.hitlchat.io/api/v1/public/inbound \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "object": "whatsapp_business_account",
    "entry": [{
      "id": "YOUR_WHATSAPP_BUSINESS_ID",
      "changes": [{
        "field": "messages",
        "value": {
          "messaging_product": "whatsapp",
          "metadata": { "phone_number_id": "YOUR_PHONE_NUMBER_ID" },
          "contacts": [{ "profile": { "name": "John" }, "wa_id": "447700900123" }],
          "messages": [{
            "from": "447700900123", "id": "wamid.ABC", "timestamp": "1733670000",
            "type": "text", "text": { "body": "I need to speak to a human" }
          }]
        }
      }]
    }]
  }'
The entry[0].id (WhatsApp Business ID) and phone_number_id must match what you configured — that’s how we route the message to your account.

Inbound media (images, video, files)

Forward media verbatim too — including the Meta media id, exactly as Meta sends it. HitlChat downloads the file from Meta using the access token you saved and renders it in the inbox. No transformation needed on your side.

# The messages[] entry for an inbound image (rest of the envelope is identical)
"messages": [{
  "from": "447700900123", "id": "wamid.IMG", "timestamp": "1733670200",
  "type": "image",
  "image": { "mime_type": "image/jpeg", "id": "META_MEDIA_ID", "caption": "Receipt" }
}]
Works the same for video, audio and document — use the matching type and object.

Optional: prior chat history (handoff context)

On the message that opens a conversation, you can attach a top-level prior_history array so the agent sees the earlier bot conversation. It’s text-only — for a past media turn, describe it in text.

# Add this sibling key alongside "object" / "entry"
"prior_history": [
  { "direction": "inbound",  "text": "What are your hours?", "timestamp": "2026-06-08T09:14:00Z" },
  { "direction": "outbound", "text": "9am-5pm, Mon-Fri.",   "timestamp": "2026-06-08T09:14:05Z" }
]

Step 5 · Receive agent replies on your webhook

When an agent replies in the inbox, HitlChat POSTs an outbound_message event to your Webhook URL. It carries meta_payload — the exact body to POST to Meta. Your gateway just forwards it with your own token.

# What HitlChat sends to your webhook
{
  "event": "outbound_message",
  "contact_number": "447700900123",
  "phone_number_id": "YOUR_PHONE_NUMBER_ID",
  "meta_payload": {
    "messaging_product": "whatsapp", "to": "447700900123",
    "type": "text", "text": { "body": "Hi John, happy to help!" }
  }
}
For images we send "image": { "link": "…" } — a public link Meta fetches, so your gateway needs no extra upload call.

Step 6 · Handle the resolved event

When an agent marks the chat Resolved by Human, HitlChat fires a conversation_resolved event to the same webhook so you can clear your session state.

{
  "event": "conversation_resolved",
  "contact_number": "447700900123",
  "resolved_status": "Resolved by Human",
  "resolved_datetime": "2026-06-09T10:05:00Z"
}

Every endpoint, field and response

The full interactive reference — auto-generated from the live API — documents every parameter and lets you try calls in the browser.

Open the full API reference →

Headless Human Handoff FAQs

What is headless human handoff?

It’s a HitlChat connection mode where your own gateway stays the WhatsApp webhook receiver and sender, and HitlChat is used purely as the live-agent inbox. You push inbound messages to our API, and we emit agent replies and a resolved event back to your webhook.

When should I use External / API mode instead of connecting WhatsApp directly?

Use it when you already run your own WhatsApp pipeline (for example a flow that receives the Meta webhook and runs your bot) and only want HitlChat for the human-agent step. If you’d rather HitlChat manage the WhatsApp connection, pick Facebook Login, Manual Configuration, or QR Code instead.

Do I forward Meta payloads verbatim?

Yes. Forward the exact Meta webhook payload to POST /v1/public/inbound — text and media alike, with no reshaping. The only optional addition is a top-level prior_history array on the message that opens a conversation.

Why does HitlChat need my Meta access token if my gateway sends the messages?

Only to download inbound media. A Meta inbound media message references the file by a media id that can only be fetched with the access token. Storing it lets you forward media payloads verbatim — HitlChat downloads the file and shows it in the inbox. The token is never used to send messages; your gateway still sends.

How do agent replies get back to WhatsApp?

When an agent replies, HitlChat POSTs an outbound_message event to your webhook URL containing meta_payload — the exact body to send to Meta. Your gateway forwards that to the Meta API with your own credentials.

What is the conversation_resolved webhook?

When an agent marks a chat “Resolved by Human”, HitlChat fires a conversation_resolved event to your webhook so you can clean up your own session state.

How do images and other media work?

Inbound: forward the verbatim payload (media id) — we download it from Meta with your token and render it. Outbound: we send the image as a public link in meta_payload, so Meta fetches it and your gateway needs no extra upload step.

What’s my API key for the inbound endpoint?

It’s your User ID, shown inside HitlChat under My Account → API. Send it as Authorization: Bearer YOUR_API_KEY. Keep it secret — it grants access to your account’s data.

Can I test it without my own gateway?

Yes. Use POST /v1/public/inbound/test-resolved-webhook to fire a sample resolved event to your webhook, and point your Webhook URL at a tool like webhook.site to inspect the outbound payloads. You can also POST sample inbound payloads with cURL or Postman.

Related guides

← Back to all guides·See pricing

Stories from real businesses

Daniel Ortega

eCommerce Ops Manager

"WhatsApp is where most of our online customer conversations happen. Our Voiceflow assistant handles the basic questions really well, but when questions get more complicated hitlchat allows our team to jump in instantly without having to move the customer to another channel. It feels like true live chat inside WhatsApp and we’ve seen higher conversions because of it"

Sanjay Mehta

Conversational AI Agency

"The hitlchat setup is super simple, and its easy to use! Most of our clients run small teams handling WhatsApp conversations powered by a Voiceflow bot. hitlchat gives them one shared workspace to manage all their conversations. Being able to step into bot conversations directly inside WhatsApp has transformed their support workflows."

Lucas Bennett

Voiceflow Developer

"We've been building Voiceflow WhatsApp assistants for our clients across various industries (healthcare, ecommerce, restaurants etc) for a few years now. We had been looking for a way to route conversations from the Voiceflow assistant to live human agent for some time. Eventually we found out about hitlchat and honestly its been a gamechanger for us ever since. Our clients love it, and as a result we love it!"

Ready to try hitlchat ?

Create Your Free Account Now

No credit card required