Custom WhatsApp Automation With the Cloud API: A Technical Guide
WhatsApp is where a lot of customers actually reply. An email sits unread and a web chat closes when the tab does, but a WhatsApp message gets answered, and business messaging on it is growing steadily with US companies too. That makes it one of the highest-leverage channels to automate, which is why so many businesses start with a no-code builder like ManyChat to get a bot live quickly.
That is a fine place to begin, and for simple marketing flows it may be all you ever need. But the moment you want the conversation to reach into your own systems, pull a real order status, respect logic that lives in your database, keep the customer data in your own infrastructure, you bump into the ceiling of a third-party tool. This guide is about going one level deeper: building on the official WhatsApp Business Cloud API from Meta, so the automation is genuinely yours. The examples target a Vercel or Node app.
ManyChat versus the Cloud API: when to graduate
No-code builders are great for broadcasts and simple question-and-answer bots, and for a non-technical team that needs to edit flows without a developer. Stay there while that is what you need.
Graduate to the Cloud API when the automation has to be part of your product rather than a layer beside it: when a reply needs live data from your database, when the logic has real branching tied to your business rules, when per-contact pricing starts scaling against you, or when you would rather customer conversations not pass through a third party. At that point the Cloud API gives you the depth, the cost control, and the data ownership that a builder cannot.
How the Cloud API actually works
The Cloud API is hosted by Meta, so you do not run any messaging infrastructure. The setup has a few moving parts: a Meta app, a WhatsApp Business Account, a phone number registered to it, and a permanent access token your server uses to send messages. Inbound messages arrive at a webhook you host.
The shape of the integration is simple once those exist. A customer sends a message, Meta delivers it to your webhook, your app decides what to do, and you reply by calling the Graph API. Everything interesting, the logic, the state, the data, lives in your app, with Meta acting purely as the transport.
Receiving messages: the webhook
Two things hit your webhook. First, a one-time verification handshake when you register the URL, a GET request you answer by echoing back the challenge if the verify token matches. Then the real traffic: POST requests carrying inbound messages, nested a few levels deep in the payload.
// GET: Meta's verification handshake
export async function GET(req: Request) {
const url = new URL(req.url);
if (url.searchParams.get("hub.verify_token") === process.env.WA_VERIFY_TOKEN) {
return new Response(url.searchParams.get("hub.challenge") ?? "");
}
return new Response("forbidden", { status: 403 });
}
// POST: inbound messages
export async function POST(req: Request) {
const body = await req.json();
const msg = body.entry?.[0]?.changes?.[0]?.value?.messages?.[0];
if (msg) await handleMessage(msg.from, msg.text?.body ?? "");
return new Response("ok"); // ack fast, process the rest in the background
}
As with any webhook, acknowledge quickly and do the slow work asynchronously, and verify the payload signature Meta provides so nobody can post fake messages to your endpoint.
Sending messages: the 24-hour window and templates
This is the rule that breaks naive bots, so it is worth understanding before you build anything. WhatsApp draws a hard line between two kinds of outbound messages. Inside a 24-hour window after the customer's last message, you can reply with free-form content, normal conversation. Outside that window, you cannot send free text at all, you may only send a pre-approved message template.
async function send(to: string, payload: object) {
await fetch(`https://graph.facebook.com/v21.0/${process.env.WA_PHONE_ID}/messages`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.WA_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ messaging_product: "whatsapp", to, ...payload }),
});
}
// inside the 24-hour window: free-form text
send(to, { type: "text", text: { body: "Your order shipped." } });
// outside it: a template you submitted and Meta approved in advance
send(to, { type: "template", template: { name: "order_update", language: { code: "en_US" } } });
The practical consequence is that proactive notifications, an order update sent hours later, must be built as templates and submitted for approval ahead of time. Design your templates early, because approval is not instant and your automation depends on them.
Conversation state: build a simple state machine
Each inbound message arrives on its own, with no memory of what came before, so the conversation only feels continuous if you make it. Store state per customer, keyed by phone number, in your database: where they are in a flow, what you last asked, any data collected so far.
Model the flow as an explicit state machine rather than a tangle of nested conditionals. Each state knows the valid next steps for a given reply, which keeps a multi-step flow, ask for an order number, look it up, offer choices, readable and safe to extend. It also makes the unhappy paths, an unexpected reply, a timeout, a request for a human, something you handle deliberately instead of by accident.
Opt-in, compliance, and human handoff
WhatsApp is strict about consent, and your account's health depends on respecting it. Send proactive messages only to people who explicitly opted in, honor the 24-hour window, and always offer a clear way to stop. Meta tracks a quality rating on your number and will cap your messaging limits if users block or report you, so good behavior is not just polite, it protects the channel.
And never trap someone in a bot. The fastest way to frustrate a customer is a loop with no exit, so build in a reliable handoff to a human, on a keyword, after a failed step, or on request, that routes the conversation to your team. Automation should handle the common cases and get out of the way for everything else.
A WhatsApp automation checklist
- Use a builder for simple broadcasts, graduate to the Cloud API when you need real data and logic.
- Stand up the Meta app, WhatsApp Business Account, number, and a permanent token.
- Verify the webhook handshake, then acknowledge inbound messages fast and verify their signature.
- Respect the 24-hour window, and submit templates for approval well before you need them.
- Track conversation state per phone number, modeled as an explicit state machine.
- Collect explicit opt-in, offer a clear stop, and watch your quality rating.
- Build a dependable handoff to a human for anything the bot should not handle.
FAQ
Do I need the official WhatsApp API, or is ManyChat enough?
ManyChat is enough for broadcasts and simple bots a non-technical person edits, so start there if that is all you need. Move to the official Cloud API when replies must use live data from your own systems, when the logic has real branching, when per-contact pricing scales against you, or when you want customer data in your own infrastructure rather than a third party's. The API gives depth and ownership a builder cannot.
What is the 24-hour window in WhatsApp?
It is the period after a customer's most recent message during which you may send free-form replies. Within 24 hours you can converse normally, but once it closes you can only send pre-approved message templates, not arbitrary text. This rule exists to prevent spam, and it is why proactive notifications like shipping updates must be built as templates and submitted for Meta's approval ahead of time.
Why do I need message templates?
Because outside the 24-hour window WhatsApp does not allow free-form outbound messages, only templates you submitted and Meta approved in advance. Any message your system initiates, an order update, a reminder, an alert, has to be a template. Plan and submit them early, since approval takes time and the rest of your proactive automation cannot run until the templates it depends on are live.
How do I receive WhatsApp messages in my app?
You host a webhook and register it with Meta. First you answer a one-time verification handshake by echoing back the challenge when the verify token matches, then Meta sends inbound messages as POST requests with the message nested in the payload. Acknowledge quickly, verify the signature so the requests are genuine, and process the message asynchronously, looking up state by the sender's phone number to continue the conversation.
Is automating WhatsApp allowed and compliant?
Yes, when you follow the rules. Use the official Cloud API, message only people who explicitly opted in, respect the 24-hour window and template requirements, and always offer a way to opt out. Meta scores your number's quality and will throttle you if people block or report your messages, so compliant, genuinely useful automation is also what keeps the channel healthy and your sending limits high.
If WhatsApp is where your customers reply and you want automation that reaches into your real systems, tell me what the conversations need to do and I will map out the cleanest way to build it on the Cloud API.
Want a hand applying this?
Tell me where your business is stuck and I will give you a straight, useful read, no pitch.