Most WhatsApp Cloud API setup guides stop at the test number and the hello_world template, which is the part that never breaks. The parts that break are the permanent token, the webhook handshake, the display name review, and the moment you swap the Meta-provided test number for a real one.
I have run this setup dozens of times, including for AI Walay, a multi-tenant WhatsApp Business SaaS where every new customer means another number, another token and another webhook subscription. This is the sequence I follow, in order, with the failure modes attached to each step.
What do you need before starting WhatsApp Cloud API setup?
You need four things before you touch the Meta App Dashboard: a Facebook account, a Meta business portfolio, a phone number that has no WhatsApp account currently attached to it, and an HTTPS endpoint with a valid certificate. Missing any one of them will stall you halfway through.
The phone number requirement is the one people get wrong. If the number is already running the consumer WhatsApp app or the WhatsApp Business app, you must delete that account first, and deleting it destroys the chat history on it. If that history matters, get a fresh number. The trade-offs between the app and the API are covered in WhatsApp Business API vs the WhatsApp Business App.
Self-signed certificates are explicitly not supported for webhooks, per Meta's Graph API webhooks documentation. During development, a tunnel with a real certificate is fine. In production, terminate TLS properly.
The five gates in a Cloud API setup, and what each one actually unblocks.
| Gate | Who approves it | What it unblocks | Typical blocker |
|---|---|---|---|
| Meta app + WhatsApp product | Automatic | Test number, temporary token, API access | Wrong app type selected at creation |
| Phone number registration | Automatic | Sending from your own number | Number still bound to a WhatsApp account |
| Display name review | Meta review team | The name customers see in the chat header | Name does not relate to the verified business |
| Business verification | Meta review team | Higher messaging limits and going live | Business documents do not match the portfolio name |
| Template approval | Automated + review | Sending outside the 24-hour service window | Marketing content submitted under the utility category |
How do you create the Meta app and business portfolio?
Create the business portfolio first at business.facebook.com, then create the app inside the Meta App Dashboard and attach it to that portfolio. Doing it in the reverse order leaves you with an orphaned app that cannot be assigned to a System User later.
In the App Dashboard, choose the business app type and add the WhatsApp product from the product list. Meta then provisions a WhatsApp Business Account, a test phone number, and a phone number ID. Note the phone number ID and the WhatsApp Business Account ID somewhere you will not lose them, because every subsequent call needs one or the other.
The test number sends only to a small allowlist of recipient numbers you add manually in the dashboard. It is a smoke test, not a staging environment. Do not build your whole integration against it and expect production behaviour to match, because the test number never goes through display name review and never carries a quality rating.
"The Meta test number will make your integration look finished while hiding every constraint that governs real sending."
How do you add and register your business phone number?
Add the number in the WhatsApp Manager, verify it by SMS or voice call, then register it against the Cloud API with a POST to the phone number ID. Verification and registration are two separate steps and people routinely stop after the first one.
The registration sequence, in the order Meta expects it.
- 1In WhatsApp Manager, choose Add phone number and enter the number plus a proposed display name and business category.
- 2Complete the SMS or voice verification code challenge. The number must be able to receive one of the two.
- 3Set a six-digit two-step verification PIN. Store it in your secrets manager, not in a spreadsheet.
- 4Call POST to the Graph API path PHONE_NUMBER_ID/register with messaging_product set to whatsapp and pin set to that six-digit value.
- 5Confirm the number status reads Connected in WhatsApp Manager before you attempt any send.
Meta's registration reference documents a throttle of ten registration requests per number in any 72-hour window, returning error code 133016 once you cross it. That limit exists to stop exactly the loop you are about to write when the first attempt fails. Fix the cause before retrying rather than hammering the endpoint.
If you plan to manage many numbers across many clients, model the number, its PIN, its WhatsApp Business Account ID and its token as one tenant record from day one. Retrofitting multi-tenancy onto a single-number integration is a rewrite, which is why the WhatsApp Business API architecture matters before you write the first handler.
What happens during WhatsApp display name review?
The display name is the business name shown in the chat header, and Meta reviews it against your business identity before it can be used. Until it is approved, the number can exist and register but the customer-facing name stays pending.
Reviews are judged on whether the name plausibly represents the business behind the portfolio. Generic names, unrelated names, and names stuffed with keywords or offers get rejected. In my experience the turnaround swings widely, from a few hours to most of a week, so submit the display name early rather than as the last item before launch.
Display names that get rejected, based on what I have watched fail.
- A trading name with no connection to the legal entity in the business portfolio
- Names containing offers, discounts or calls to action
- A bare generic noun such as Support or Sales with no brand attached
- Names that imply a Meta or WhatsApp affiliation
How do you generate a permanent access token?
Create a System User in Business Settings, assign your app and WhatsApp Business Account to it, and generate a token with the whatsapp_business_messaging, whatsapp_business_management and business_management permissions. The token on the app dashboard expires within 24 hours and is only useful for the first curl.
Give the System User admin access to the WhatsApp Business Account asset, not just the app. This is the single most common cause of a token that authenticates fine but returns a permissions error the moment you call a phone number endpoint. The token is valid, the asset assignment is missing.
Token types and where each one belongs.
| Token | Lifetime | Use it for | Do not use it for |
|---|---|---|---|
| Dashboard temporary token | About 24 hours | The first manual test send | Anything committed to a repo or config |
| System User token | No expiry unless revoked | Production sending and webhook management | Sharing across unrelated client accounts |
| Embedded Signup token | Exchanged per client | Multi-tenant SaaS onboarding customers | A single-brand internal integration |
Treat the System User token like a database password. It can send messages billed to your account, so it belongs in a secrets manager with rotation, which is table stakes on any full-stack Python build I ship.
How do you verify the WhatsApp webhook?
Meta verifies your webhook with a GET request carrying hub.mode, hub.verify_token and hub.challenge. Your endpoint compares the verify token to the one you configured, then returns the raw hub.challenge value as the response body. Return anything else and the subscription fails.
The two mistakes I see constantly: returning the challenge wrapped in JSON instead of as plain text, and returning a 200 without the challenge at all. Meta wants the value echoed, nothing around it.
from fastapi import FastAPI, Request, Response, HTTPException
import hmac, hashlib, os
app = FastAPI()
VERIFY_TOKEN = os.environ["WA_VERIFY_TOKEN"]
APP_SECRET = os.environ["WA_APP_SECRET"]
@app.get("/webhooks/whatsapp")
def verify(request: Request):
p = request.query_params
if p.get("hub.mode") == "subscribe" and p.get("hub.verify_token") == VERIFY_TOKEN:
# echo the challenge as plain text, not JSON
return Response(content=p.get("hub.challenge"), media_type="text/plain")
raise HTTPException(status_code=403)
@app.post("/webhooks/whatsapp")
async def receive(request: Request):
body = await request.body()
digest = hmac.new(APP_SECRET.encode(), body, hashlib.sha256).hexdigest()
sent = request.headers.get("X-Hub-Signature-256", "")
if not hmac.compare_digest("sha256=" + digest, sent):
raise HTTPException(status_code=403)
# enqueue and return immediately; Meta retries on any non-200
return Response(status_code=200)Validate the X-Hub-Signature-256 header on every inbound POST. Without it your endpoint accepts forged message events from anyone who finds the URL. Then acknowledge with a 200 fast and do the real work in a queue, because Meta retries on non-200 responses and a slow handler turns one customer message into a pile of duplicates.
Finally, subscribe the app to the messages field on the WhatsApp Business Account. Configuring the callback URL is not the same as subscribing to events, and a silent webhook is almost always an unsubscribed field.
How do you send your first template message?
Send a POST to PHONE_NUMBER_ID/messages with type set to template and the hello_world template, addressed to a number on your allowlist. If that returns a message ID and the phone rings, every credential in the chain is correct.
Templates exist because you cannot message a customer freely outside the service window that their own message opens. Meta categorises templates as marketing, utility or authentication, and category drives both approval strictness and billing. Submitting promotional copy under utility gets it recategorised or rejected, and the mechanics are unpacked in WhatsApp Business API pricing.
Once the first send works, the interesting work starts: routing inbound messages, holding conversation state, and deciding what an automated reply is allowed to say. That is the layer I build for ecommerce teams on top of the raw API, not the transport itself.
How do you go live and raise your messaging limits?
Going live is the part of WhatsApp Cloud API setup that no amount of code shortens. It means completing Meta business verification, getting the display name approved, and switching the app out of development mode. Messaging limits then start capped at a fixed number of unique customers you can message in a rolling 24-hour window and step up as you send quality traffic.
Business verification wants documents that match the legal entity name on the portfolio exactly. A utility bill in a director's name will not clear it. Get this queued early because it is the longest pole in the whole setup and it gates the limits that make the channel useful.
Your quality rating is scored on how recipients react. Blocks and reports drag it down and can push a number back to lower limits. The fastest way to destroy a new number is to import a cold list and blast marketing templates in week one. Warm up with utility and service traffic first and let volume follow the quality rating rather than the other way round.
The go-live checklist I run before handing a number to a client.
- Business verification approved and the portfolio name matching legal documents
- Display name approved and rendering correctly in a real chat
- System User token stored in a secrets manager with a rotation owner named
- Webhook signature validation on, with a queue behind the 200 response
- At least one utility template approved for order or booking updates
- An opt-out path that actually stops sends, wired to your contact record
Done properly, WhatsApp Cloud API setup is a two-hour job wrapped in two weeks of Meta review queues. If you want the setup handled and the automation layer built on top of it, that is what my WhatsApp Business integration work and broader AI automation services cover.
Key takeaways
- WhatsApp Cloud API setup is five approval gates, not one form: app creation, number registration, display name review, business verification and template approval.
- A phone number cannot be used until any existing WhatsApp account on it is deleted, which destroys that number's chat history.
- Registration is a POST to PHONE_NUMBER_ID/register with messaging_product and a six-digit two-step verification PIN.
- Production requires a System User token with the WhatsApp Business Account assigned as an asset, not just the app.
- Webhook verification means echoing hub.challenge as plain text, and every inbound POST should be signature-checked against X-Hub-Signature-256.
- Business verification and quality rating, not code, determine how many customers you can actually reach per day.
Frequently asked questions
- How much does WhatsApp Cloud API setup cost?
- Setup itself is free. Meta charges for messages, not for API access or the Cloud API hosting. Costs come from template messages priced by category and destination country, plus your own hosting for the webhook service. Check Meta's official WhatsApp Business Platform pricing page for current rates, since Meta has changed the billing model more than once.
- Can I use my existing WhatsApp Business app number for the Cloud API?
- Yes, but you must delete the WhatsApp Business app account on that number first, and deleting it permanently removes the chat history stored on the device. If those conversations matter to the business, register a new number for the API and keep the app number running separately for walk-in traffic.
- How long does WhatsApp display name review take?
- It varies. In the setups I have run, approval has landed in a few hours and it has also taken most of a week. Submit the display name as soon as you add the number rather than at launch. Rejections usually trace back to a name that does not match the business entity in your Meta portfolio.
- What is the difference between the Cloud API and the On-Premises API?
- The Cloud API is hosted by Meta, so there is no container to run, no upgrades to schedule and no infrastructure bill. The On-Premises API ran in your own environment and Meta has sunset it. For new builds the Cloud API is the only sensible choice unless you have a hard data residency mandate.
- Do I need Meta business verification to send messages?
- Not to test. An unverified app can send to a small allowlist using the test number, which is enough to prove your integration. To message real customers at meaningful volume you need business verification completed, the display name approved and the app moved out of development mode.
- Why is my WhatsApp webhook not receiving messages?
- Usually because the app is not subscribed to the messages field on the WhatsApp Business Account. Setting a callback URL and passing verification is only half the job. Also check that TLS is valid and not self-signed, that you return a 200 quickly, and that the number is registered rather than merely verified.
- Is the WhatsApp Cloud API worth it for a small business?
- It is worth it once you need automation, multiple agents on one number, or CRM integration. If one person answers every message on a phone, the WhatsApp Business app is enough and the API adds cost and complexity. The break point is usually shared inbox pressure or a need for automated order and booking updates.
Sources
Written by Syed Husnain Haider Bukhari
AI engineer, data scientist, and founder of Revolutionary Technologies LLC. Ships production AI agents, automations, and data platforms for teams in the US, UK, and UAE — including AgentFlow, AI Walay, and ProLeads.
Get in touch →Related pages
Want this built instead of researched?
Book a 30-minute scoping call. You get a one-page plan and a fixed-scope quote within 48 hours.
Start a conversation