How to Reply to WhatsApp Business Messages with an AI Agent

Connect the Postproxy MCP server and let Claude, ChatGPT, or Cursor work your WhatsApp Business inbox — reading conversations, replying, and sending approved templates when the 24-hour window has closed.

What this gets you

An agent that works a WhatsApp Business inbox: it reads the open conversations, drafts replies in your voice, and respects the one rule that makes WhatsApp different from every other channel — after 24 hours of silence, a free-form message is rejected and only an approved template will go through.

Everything below happens through MCP tools. There is no integration to write, no endpoint to call, and no API key to pass around in code — you connect the server once and then work in prompts.

1. Connect the MCP server

Full setup instructions, including the hosted and local options and the one-click Claude and ChatGPT connectors, are on the MCP integration page. The short version, hosted with nothing to install:

Terminal window
claude mcp add --transport http postproxy \
https://mcp.postproxy.dev/mcp?api_key=YOUR_POSTPROXY_API_KEY

Once it’s connected, your client discovers the tools and you can check it’s alive by asking:

“What Postproxy profiles do I have?”

That runs profiles_list. If you get a list back, you’re done with setup.

Develop against the sandbox first. Use a sandbox (t_…) API key and a sandbox WhatsApp profile ships with a fabricated number and two approved seed templates — hello_world and order_update — so the agent can run the whole loop before Meta has reviewed anything of yours. Inbound messages are driven from the Sandbox page in the dashboard.

2. The tools your agent needs

ToolWhat it does
profiles_listFind the WhatsApp profile
profiles_placementsList the phone numbers on it
dm_chats_listList conversations, most recent first, with the messaging-window flag
dm_messages_listRead a thread
dm_message_sendReply — text, media, a template, or interactive buttons
dm_chat_createOpen a conversation with a phone number (needs placement_id)
dm_chat_mark_readSend WhatsApp’s blue ticks
dm_message_reactReact to a customer’s message
whatsapp_templates_listList approved templates and their variable counts

The same dm_* tools already answer Instagram and Messenger, so if you’ve followed letting agents answer DMs and comments, WhatsApp slots into the workflow you have.

3. Connect a WhatsApp Business Account

The agent can start this too, with profile_groups_initialize_connection:

“Start a WhatsApp connection for my Main Brand profile group. The number is currently in the WhatsApp Business app on my phone.”

That last sentence matters — it selects the onboarding mode:

ModeWhenWhat happens
business_appThe number is in the WhatsApp Business app and your team answers from itCoexistence. You scan a QR code, the phone keeps working, the agent sees the same conversations, and up to 6 months of history is imported
apiThe number is already on the Cloud API, or is a fresh numberThe number moves to the Cloud API and stops working in the app
(omitted)You’re not sureThe connect page asks before the Facebook login

The tool returns a URL. Open it, complete Meta’s Embedded Signup, and the account is connected — one profile, with each of its phone numbers as a placement.

Coexistence is usually the right first move: you can put an agent on a live support line without cutting the line over. The trade-offs are Meta’s — lower sending throughput, no group chats through the API, and Meta disconnects a coexistence number whose phone stays offline for around 14 days.

4. Find the profile and its numbers

“List my profiles, then show me the phone numbers on the WhatsApp one.”

profiles_list finds the profile; profiles_placements lists the numbers. Each placement is one phone number, and its id is the placement_id the agent passes to dm_chat_create — required on WhatsApp, because a conversation belongs to a specific number. A customer who writes to two of your numbers has two chats.

The placement also carries the number’s quality_rating and messaging_limit_tier — Meta’s cap on how many conversations that number may start per 24 hours — which is worth glancing at before you point an automation at it.

One rule to hand the agent along with dm_chat_create: a brand-new conversation can only be opened with an approved template. There is no open window yet, so a plain-text first message is rejected. Reaching out cold and replying to someone who just wrote in are different jobs, and only the second one starts with text.

5. Read the inbox

dm_chats_list returns conversations newest-first. A WhatsApp chat comes back like this:

{
"id": "chat_wa789",
"platform": "whatsapp",
"external_placement_id": "106540352242922",
"participant_external_id": "13105550007",
"participant_name": "Ana",
"group": false,
"within_messaging_window": true,
"last_inbound_at": "2026-09-28T08:12:00.000Z",
"last_outbound_at": "2026-09-27T16:40:00.000Z"
}

Two fields drive every decision the agent makes:

  • within_messaging_window — whether a free-form reply is allowed right now.
  • last_inbound_at vs last_outbound_at — whether the customer is still waiting on you.

6. Teach it the window rule

This is the step that decides whether the agent is useful or embarrassing. Meta allows free-form messages only within 24 hours of the customer’s last message. Outside that, a plain text send is rejected — and it’s rejected by Meta after the send is accepted, so the agent can’t learn from a failed call and try again.

within_messaging_window is the pre-flight check. Put the rule in your system prompt rather than hoping the model infers it:

When working WhatsApp chats, always check within_messaging_window first.

If it is true, reply in plain text with dm_message_send.

If it is false, do not send plain text. Call whatsapp_templates_list and send an approved template instead, filling its variables from the conversation. If no template fits the situation, stop and tell me — do not improvise.

7. Reply, or send a template

Inside the window, the agent calls dm_message_send with plain text:

{
"chat_id": "chat_wa789",
"body": "Setting one aside now — it will be at the counter until Friday."
}

Outside it, the same tool takes a template instead of body:

{
"chat_id": "chat_wa789",
"template": {
"name": "order_update",
"language": "en_US",
"variables": ["Ana", "ORD-12345", "Friday"]
}
}

variables are positional — header variables first, then body, then one per dynamic URL button. Each template from whatsapp_templates_list reports a variable_count, and a wrong count comes back as a clear error naming the expected number, so the agent gets something it can correct rather than a silent failure.

Give the agent the template list up front, with a sentence about what each one is for. That’s the difference between a working fallback and an agent that reports it couldn’t reply:

“List the approved WhatsApp templates and tell me which ones you’d use for a delayed order, a ready-for-pickup notice, and an abandoned enquiry.”

A template send also re-opens the 24-hour window, so once the customer replies the agent is back to normal text.

8. Ask with buttons instead of open questions

When the next step is a choice, buttons beat free text — the customer taps, and the agent gets a stable identifier back instead of parsing a sentence. dm_message_send takes WhatsApp’s interactive object:

{
"chat_id": "chat_wa789",
"interactive": {
"type": "button",
"body": { "text": "Your order is ready. Pick up or deliver?" },
"action": {
"buttons": [
{ "type": "reply", "reply": { "id": "PICKUP", "title": "Pick up" } },
{ "type": "reply", "reply": { "id": "DELIVER", "title": "Deliver" } }
]
}
}
}

The tap arrives as an inbound message whose interactive carries the id you assigned. Have the agent branch on that id, not on the message text — otherwise the flow breaks the first time somebody translates a label. Lists (up to 10 rows), call-to-action URLs, catalog products, and Flows use the same envelope.

Interactive messages are session messages: they need an open window, and they can’t go to a group.

9. A session end to end

With the server connected, the whole job is prompting:

“Check the WhatsApp inbox. For every conversation where the customer wrote last and we haven’t replied, draft a response. Show me the drafts before sending anything.”

The agent calls dm_chats_list, compares last_inbound_at against last_outbound_at, reads each thread with dm_messages_list, and drafts. Nothing leaves until you approve.

“For the ones where the window has closed, use the order_update template with the right order number.”

It reads within_messaging_window, pulls the template from whatsapp_templates_list, and sends with template and variables taken from the thread.

“Mark everything you answered as read.”

dm_chat_mark_read sends WhatsApp’s blue ticks, so the customer can see their message was actually seen rather than just receiving a reply out of nowhere.

“Anything that mentions a refund, leave alone and list it for me.”

The useful half of an agent inbox is what it declines to touch.

10. Running it unattended

For a human-in-the-loop workflow, the prompts above are enough. If you want the agent reacting on its own, two things change.

Something has to wake it. MCP tools are pull-only — the agent acts when you or your scheduler asks it to. Either run the loop on a schedule (“every 10 minutes, check for unanswered WhatsApp chats”), or have your own code subscribe to the message.received webhook and trigger the agent per message. The WhatsApp reference lists the events, including message_template.status_updated — worth watching, because Meta can pause a template after approving it, and a paused template is exactly the fallback your unattended loop depends on.

Guardrails stop being optional. WhatsApp is someone’s personal messaging app, and Meta enforces accordingly:

  • Keep draft-then-approve while you’re tuning. One round trip, and it catches the replies you’d rather not have sent.
  • Never let the agent talk its way past the window. The only legitimate routes are an approved template or a genuine transactional notification. Marketing content dressed as a utility message is a policy problem, not a clever workaround.
  • Give it an explicit escape. Refunds, complaints, anything it isn’t sure about — flag for a human instead of answering.
  • Watch the number’s quality rating. It’s what Meta uses to decide how many conversations you can start per day, and a slide toward RED is the clearest signal that automated replies are landing badly.

Where to go next

Ready to get started?

Start with our free plan and scale as your needs grow. No credit card required.