How to Set Up the WhatsApp Cloud API Step by Step
1 November 2026 · 7 min read · Türkçe oku
The WhatsApp Cloud API is Meta's hosted way to send and receive WhatsApp messages from your own software. Since Meta retired the On-Premises API (its final client expired on 23 October 2025), the Cloud API is the route every integration takes. The setup itself isn't hard, but it's spread across three Meta screens, and one missed step (usually the webhook field subscription) leaves you with a number that sends but never receives.
This guide walks through the whole flow in order. Meta renames dashboard menus from time to time, so treat the labels below as accurate as of November 2026 and check the official Get Started guide if something looks different.
What you need before you start
- A Meta business portfolio (formerly Business Manager). You can create one during app setup.
- A phone number you own that can receive an SMS or voice call for verification. It must include the country code; short codes aren't supported.
- The number must not be active in the WhatsApp or WhatsApp Business app. If it is, delete that account first.
- A public HTTPS endpoint for webhooks with a valid TLS certificate. Meta doesn't accept self-signed certificates.
Step 1: Create the Meta app
- Go to developers.facebook.com/apps and click Create App.
- Enter an app name and contact email.
- Choose the use case Connect with customers through WhatsApp and click Next. (Older dashboards asked for an app type of Business and then had you add the WhatsApp product. The result is the same.)
- Select or create your business portfolio, review the requirements and click Create app.
You land on the WhatsApp quickstart. Click Start using the API to open the API Setup page.
Step 2: Note your Phone number ID and WABA ID
On API Setup, connect the app to a WhatsApp Business Account (or let Meta create one). Meta also gives you a free test number.
Write down two IDs from this panel:
| ID | What it's used for |
|---|---|
| Phone number ID | The sender. Every send request goes to /<PHONE_NUMBER_ID>/messages. |
| WhatsApp Business Account ID (WABA ID) | The account that owns your templates and billing. Template management uses this ID. |
Meta has started calling the WABA a Messaging account in parts of its docs and dashboard. According to Meta, your existing WABA ID now identifies the Messaging account, and the ID value doesn't change, so integrations keep working.
Step 3: Send a test message
The Generate access token button on API Setup gives you a temporary token. It expires within hours, so only use it for a first test. Pick the test number as From, enter your own mobile number as To, and send the hello_world template.
The same thing from the command line looks like this (use the current Graph API version shown in your dashboard):
curl "https://graph.facebook.com/v23.0/<PHONE_NUMBER_ID>/messages" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"messaging_product": "whatsapp",
"to": "<YOUR_MOBILE_NUMBER>",
"type": "template",
"template": { "name": "hello_world", "language": { "code": "en_US" } }
}'
Reply to the message from your phone. That opens a 24-hour customer service window, and only inside it can you send free-form (non-template) messages. More on that in our guide to the 24-hour window and pricing.
Step 4: Add and register your real number
On API Setup, use Add phone number, or go to WhatsApp Manager → Account tools → Phone numbers. Enter a display name, then verify the number with the SMS or voice code.
A Cloud API number also has to be registered before it can send. Meta only allows this through the API:
curl -X POST "https://graph.facebook.com/v23.0/<PHONE_NUMBER_ID>/register" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Content-Type: application/json" \
-d '{ "messaging_product": "whatsapp", "pin": "123456" }'
The pin is the number's six-digit two-step verification PIN. If two-step verification is already on, use the existing PIN; otherwise the PIN you send becomes it. Meta allows 10 registration requests per number in a 72-hour moving window. After that you get error 133016 and are blocked for 72 hours, so don't put it in a retry loop.
Step 5: Create a permanent system user token
User tokens expire. For a server integration, use a system user token:
- Open Business Settings → System users, click Add, give the user a name and choose the Admin or Employee role. An Employee has to be granted each account explicitly, which is the tighter option.
- Click Assign assets, select your app and grant Manage app (full control).
- Also assign the WhatsApp account to the system user. Meta's docs recommend assigning each account explicitly rather than relying on inherited access.
- Click Generate token, select your app, choose an expiration setting and tick these permissions:
whatsapp_business_messaging(send and receive)whatsapp_business_management(templates, phone numbers, account data)business_management(listed in Meta's current guide)
- Copy the token straight away and store it as a secret.
While you're there, copy the App secret from App settings → Basic. You'll use it to verify webhook signatures.
Step 6: Configure the webhook
Webhooks are how incoming messages and delivery statuses reach you. In the App Dashboard, open WhatsApp → Configuration (or Use cases → Customize → Configuration) and click Edit under Webhook. You enter two values:
- Callback URL: your public HTTPS endpoint.
- Verify token: any secret string you choose. Your server has to know it too.
When you click Verify and save, Meta sends a GET request containing hub.mode=subscribe, hub.verify_token and hub.challenge. Your endpoint must check the token and return the challenge as the response body. A minimal PHP version:
// PHP turns "hub.mode" into "hub_mode" in $_GET
if (($_GET['hub_mode'] ?? '') === 'subscribe'
&& hash_equals(getenv('WA_VERIFY_TOKEN'), $_GET['hub_verify_token'] ?? '')) {
echo $_GET['hub_challenge'];
exit;
}
http_response_code(403);
Every event Meta sends after that is a POST with an X-Hub-Signature-256 header (sha256= followed by an HMAC of the raw body, keyed with your App secret). Meta says you don't have to validate it, but you should:
$expected = 'sha256=' . hash_hmac('sha256', file_get_contents('php://input'), getenv('WA_APP_SECRET'));
$valid = hash_equals($expected, $_SERVER['HTTP_X_HUB_SIGNATURE_256'] ?? '');
Return HTTP 200 quickly and do the heavy work afterwards. If you return anything other than 200, Meta retries for up to 7 days, which can produce duplicates, so dedupe on message ID.
Step 7: Subscribe to the "messages" field
This is the step people miss most often. On the same Configuration page, find Webhook fields and subscribe to messages. That field carries both the messages users send you and the status updates for messages you send. Without it, verification succeeds but nothing ever arrives.
Then send a WhatsApp message to your business number from your phone and check that your endpoint receives a payload with "object": "whatsapp_business_account" and "field": "messages".
Common setup problems
| Symptom | Likely cause |
|---|---|
| "Callback URL or verify token couldn't be validated" | Endpoint isn't public HTTPS, the certificate is invalid or self-signed, or the endpoint doesn't echo hub.challenge |
| Webhook verified but no events | messages field not subscribed |
| Error 190 when sending | Access token expired. Switch to a system user token |
| Error 133010 | Phone number not registered (Step 4) |
| Error 131047 | Free-form message sent outside the 24-hour window. Send a template |
For the full list, see our guide to WhatsApp Cloud API error codes.
Doing this inside a multi-tenant platform
If you run WhatsApp messaging for several clients, each client goes through Steps 1 to 5 with their own business portfolio and number, so Meta bills their own account. Your platform only stores the IDs, token and App secret, and gives each client the callback URL and verify token for Step 6.
That is how Mesvilo works. In a workspace, under WhatsApp → Connect number, the client pastes the Phone number ID, Business Account ID, token and App secret. Mesvilo then shows the callback URL and verify token to enter in Meta, and runs health checks that turn green once the webhook is working. The documentation has the same steps written up so you can share them with clients.
To see the connect screen and the inbox it feeds, try the live demo or read the product overview.
Sources
Run your own WhatsApp platform
Mesvilo is a self-hosted WhatsApp Cloud API SaaS with a shared inbox, templates, campaigns and subscription billing.