WhatsApp AI Agent

What you build: a WhatsApp identity that, when a customer messages it, is answered by an AI agent. A hosted agent replies automatically; you can also send messages yourself, pull answers from a knowledge base, and switch a conversation to a human. You can reach out first with an approved template.

Customer → WhatsApp message ──▶ message.received webhook (notification)
hosted agent auto-replies ──┤ (or) your app → POST /v1/messages
Customer ◀── AI reply in the same WhatsApp thread

Who it’s for: Nigerian D2C brands, informal commerce, POS agents, and anyone whose customers live on WhatsApp rather than email. This is Voicebip’s clearest differentiator — a genuine WhatsApp-first AI channel, not a voice tool with messaging bolted on.

WhatsApp’s 24-hour window & billing. You can freely reply within 24 hours of the customer’s last message (a “service” conversation). To message a customer outside that window you must send a pre-approved template, which opens a new billable conversation. Voicebip bills per 24-hour conversation, per category (not per message).

Prerequisites

  • A WhatsApp-enabled sender (a Voicebip number with the whatsapp channel) and its phone_number_id.
  • An agent to run the conversation. A hosted agent auto-replies; a BYOM agent receives each inbound message at its webhook_url and you compose the reply.
  • A webhook receiver for message.received / message.delivered.

Step 1 — Receive an inbound message

When a customer messages your WhatsApp number, Voicebip fires message.received to your workspace webhook:

1{
2 "event_id": "evt_1c…",
3 "event_type": "message.received",
4 "channel": "whatsapp",
5 "from": "+2348031234567",
6 "number": "+2347000001111",
7 "timestamp": "2026-07-02T10:00:00Z",
8 "payload": {
9 "conversation_id": "conv_7d…",
10 "message_id": "msg_9a…",
11 "text": "Do you deliver to Ibadan?"
12 }
13}

For a hosted agent this is a notification — the AI dispatcher answers automatically while the conversation’s ai_mode is ai. For a BYOM agent, the inbound message is instead POSTed to the agent’s webhook_url as a BYOMMessagingWebhookRequest ({agent_id, conversation_id, channel, from_number, to_number, inbound_message, history, metadata}) and you return the reply text.

Step 2 — Send a message yourself

To send (or when a human is driving the thread), call POST /v1/messages. All of agent_id, channel, from_number, to_number, body are required; WhatsApp also needs phone_number_id:

$curl -X POST https://api.voicebip.com/v1/messages \
> -H "Authorization: Bearer pk_xxx" -H "Content-Type: application/json" \
> -d '{
> "agent_id": "agt_PAEZ_njcfm2kycpjs",
> "channel": "whatsapp",
> "from_number": "+2347000001111",
> "to_number": "+2348031234567",
> "phone_number_id": "1234567890",
> "body": "Yes — we deliver to Ibadan in 2 to 3 business days. Want to place an order?"
> }'
1{ "message_id": "msg_2f…", "status": "queued" }

To ground the reply first, query a knowledge base (POST …/query), compose from the returned chunks, then send.

Step 3 — Reach out first with a template

To start a conversation (or re-engage after 24h), send a pre-approved template. Positional variables go in parameters (an array of strings, filling {{1}}, {{2}}, …):

$curl -X POST https://api.voicebip.com/v1/messages/template \
> -H "Authorization: Bearer pk_xxx" -H "Content-Type: application/json" \
> -d '{
> "agent_id": "agt_PAEZ_njcfm2kycpjs",
> "from_number": "+2347000001111",
> "to_number": "+2348031234567",
> "template_name": "order_shipped",
> "language_code": "en",
> "parameters": ["Ada", "AC-4821", "tomorrow"]
> }'

This opens a new billable conversation window; once the customer replies you’re back in the free 24h service window.

Step 4 — Hand off to a human

Conversations carry an ai_mode. To let a human take over a thread, transition it to human (the AI dispatcher stops answering):

$curl -X PATCH https://api.voicebip.com/v1/conversations/conv_7d… \
> -H "Authorization: Bearer pk_xxx" -H "Content-Type: application/json" \
> -d '{ "ai_mode": "human", "reason": "billing dispute — agent escalated" }'

ai_mode values: ai (AI dispatcher answers), human (operator has taken over), closed (terminated — the next inbound message starts a fresh conversation). The PATCH is idempotent (same-mode returns changed: false). Read the full history any time via GET /v1/conversations/{id} or stream it live with GET /v1/conversations/{id}/stream (SSE).

Step 5 — Respect opt-outs (NDPR)

If a customer sends a stop keyword, Voicebip enrols them in your workspace opt-out list and further sends to that number are refused. Don’t try to bypass it. (Opt-out enforcement is automatic; you’ll see sends to opted-out numbers rejected.)

Config summary

ConcernHow
Inbound trigger (hosted)message.received webhook (agent auto-replies)
Inbound trigger (BYOM)BYOMMessagingWebhookRequest POSTed to the agent’s webhook_url
Send in-windowPOST /v1/messages {agent_id, channel, from_number, to_number, body, phone_number_id}
Proactive / re-engagePOST /v1/messages/template (billable conversation)
Human takeoverPATCH /v1/conversations/{id} {ai_mode: "human"}
Billingper 24h conversation, per category

Test it (sandbox)

$# Simulate an inbound WhatsApp message hitting your webhook
$curl -X POST https://api.voicebip.com/v1/webhooks/test \
> -H "Authorization: Bearer pk_test_xxx" -H "Content-Type: application/json" \
> -d '{ "webhook_url": "https://you.example.com/webhooks", "event_type": "message.received" }'

The test catalogue also covers message.sent, message.delivered, and message.failed, each with a realistic Nigerian payload and a real HMAC signature. See Sandbox Mode.

Troubleshooting

SymptomLikely cause
POST /v1/messages rejectedMissing a required field — agent_id, from_number, to_number, body (and phone_number_id for WhatsApp) are all required.
Template send failsTemplate not approved, or parameters doesn’t fill every {{n}} slot.
Customer never gets repliesConversation is human/closed, or the number is on the opt-out list.
402 WORKSPACE_BLOCKEDWorkspace balance hit zero — top up (billing fail-closed).

Next steps