WhatsApp Business API & Cloud API
How to Set Up WhatsApp Webhooks
Configure webhook verification, receive WhatsApp events, process incoming messages, and handle message status updates in your backend.
Step 1
How WhatsApp Webhooks Work
WhatsApp webhooks are how your application receives events after the initial API request. Meta sends HTTP requests to your public callback URL when customers message the business and when outbound messages change status. Your backend verifies the endpoint once, then processes POST payloads continuously.
Treat webhook processing as an event pipeline, not as a page request. Acknowledge valid events quickly, log enough information to debug them, and move slower work such as AI calls, CRM updates, or external API requests into background processing when possible.
Implementation Checklist
- Use a public HTTPS callback URL that Meta can reach from the internet.
- Keep the verify token separate from the Graph API access token.
- Log webhook event IDs, message IDs, and event type without logging secrets.
- Make processing idempotent because the same event can be delivered more than once.
Step 2
Create a Public HTTPS Endpoint
Create a Public HTTPS Endpoint belongs to the webhook transport layer. Keep this step focused on receiving or verifying Meta's HTTP request before you run chatbot, CRM, or automation logic. The webhook route should be deterministic, publicly reachable, and easy to test with a known request.
For incoming POST events, extract only the fields your application needs, preserve message and event identifiers, and acknowledge the request quickly. For setup and verification steps, use the exact callback URL and verify token configured in Meta so the handshake can succeed without depending on application state.
Implementation Checklist
- Use HTTPS and a route that is reachable from outside your local network.
- Return the expected HTTP response quickly before starting slow downstream work.
- Log message IDs, event type, and timestamps while redacting tokens and sensitive content.
- Keep webhook processing idempotent because the same event can be delivered more than once.
Step 3
Create the Verification GET Endpoint
Create the Verification GET Endpoint belongs to the webhook transport layer. Keep this step focused on receiving or verifying Meta's HTTP request before you run chatbot, CRM, or automation logic. The webhook route should be deterministic, publicly reachable, and easy to test with a known request.
For incoming POST events, extract only the fields your application needs, preserve message and event identifiers, and acknowledge the request quickly. For setup and verification steps, use the exact callback URL and verify token configured in Meta so the handshake can succeed without depending on application state.
Implementation Checklist
- Use HTTPS and a route that is reachable from outside your local network.
- Return the expected HTTP response quickly before starting slow downstream work.
- Log message IDs, event type, and timestamps while redacting tokens and sensitive content.
- Keep webhook processing idempotent because the same event can be delivered more than once.
Step 4
Add Your Verify Token
Add Your Verify Token belongs to the webhook transport layer. Keep this step focused on receiving or verifying Meta's HTTP request before you run chatbot, CRM, or automation logic. The webhook route should be deterministic, publicly reachable, and easy to test with a known request.
For incoming POST events, extract only the fields your application needs, preserve message and event identifiers, and acknowledge the request quickly. For setup and verification steps, use the exact callback URL and verify token configured in Meta so the handshake can succeed without depending on application state.
Implementation Checklist
- Use HTTPS and a route that is reachable from outside your local network.
- Return the expected HTTP response quickly before starting slow downstream work.
- Log message IDs, event type, and timestamps while redacting tokens and sensitive content.
- Keep webhook processing idempotent because the same event can be delivered more than once.
Step 5
Configure the Callback URL in Meta
Once your HTTPS endpoint and verification GET route are online, open the WhatsApp or Webhooks configuration for the Meta app and enter the public callback URL together with the verify token you chose for your backend.
Meta will immediately call the callback URL with the verification query parameters. Your route must compare the verify token and return the challenge value. If that handshake fails, normal POST webhook events will not be delivered to the endpoint.
Before You Click Verify
- Open the callback URL from outside your local development network and confirm it is reachable over HTTPS.
- Use the same verify token value in Meta and in your server environment.
- Check your backend logs while Meta performs the verification request.
- Do not use your Graph API access token as the webhook verify token.
Step 6
Handle the Verification Challenge
Meta verifies a webhook callback URL with a GET request before it starts sending normal events. Your endpoint reads hub.mode, hub.verify_token, and hub.challenge. When the mode and verify token match your configuration, return hub.challenge as the response body.
The verify token is a secret string you choose for the verification handshake. It is not your Graph API access token. Store it in server configuration and compare it exactly, including case, because a mismatch causes the callback verification step to fail.
Implementation Checklist
- Use a public HTTPS callback URL that Meta can reach from the internet.
- Keep the verify token separate from the Graph API access token.
- Log webhook event IDs, message IDs, and event type without logging secrets.
- Make processing idempotent because the same event can be delivered more than once.
Minimal verification logic
const mode = request.nextUrl.searchParams.get("hub.mode");
const token = request.nextUrl.searchParams.get("hub.verify_token");
const challenge = request.nextUrl.searchParams.get("hub.challenge");
if (mode === "subscribe" && token === process.env.WHATSAPP_VERIFY_TOKEN) {
return new Response(challenge, { status: 200 });
}
return new Response("Forbidden", { status: 403 });Step 7
Receive POST Webhook Events
After verification, Meta sends normal webhook events as POST requests. The route should parse the JSON body, identify the event type, save or queue the useful data, and return a successful response quickly. Do not wait for slow AI, CRM, email, or external API work before acknowledging the webhook.
A single webhook payload can contain message data, message statuses, or other subscribed information. Route each event based on its structure instead of assuming every POST request contains an incoming text message.
Next.js Route Handler Example
export async function POST(request: Request) {
const payload = await request.json();
// Save or queue the event before slow downstream work.
await storeWebhookEvent(payload);
return new Response("EVENT_RECEIVED", { status: 200 });
}Implementation Checklist
- Return a successful HTTP response promptly after accepting the event.
- Store message IDs, event type, and safe correlation identifiers before downstream work.
- Make event processing idempotent because the same webhook can be delivered again.
- Redact tokens and unnecessary personal content from production logs.
Step 8
Parse Incoming Messages
Incoming WhatsApp messages are nested inside the webhook entry and changes structure. Parse defensively because not every change contains a message, and not every message is text. A production parser should identify the sender, provider message ID, timestamp, message type, and the content required by your chatbot or business workflow.
Store the provider message ID before triggering a reply or business action. If Meta retries the same event, that ID gives your application a reliable way to recognize that the customer message has already been processed.
Simplified Extraction Pattern
const value = payload?.entry?.[0]?.changes?.[0]?.value;
const message = value?.messages?.[0];
if (message) {
const from = message.from;
const messageId = message.id;
const type = message.type;
const text = type === "text" ? message.text?.body : undefined;
// Deduplicate messageId before starting business logic.
}Do Not Assume Every Message Is Text
Route text, interactive replies, media, location, contacts, and other supported message types separately. Your chatbot can decide which types it supports and send a clear fallback for unsupported input instead of throwing an exception inside the webhook route.
Step 9
Process Message Status Events
The initial send response is not the final delivery result. Store the outbound WhatsApp message ID and update that record when webhook events report sent, delivered, read, or failed states.
Implementation Checklist
- Match events by WhatsApp message ID.
- Store timestamps and failure details.
- Make repeated status events safe to process.
This guide only covers the part needed for the current workflow. For the complete setup, examples, and troubleshooting, continue with WhatsApp Cloud API Message Statuses Explained.
Step 10
Subscribe the App to the WABA
The callback URL can be verified successfully and still receive no WhatsApp events if the app is not subscribed to the WhatsApp Business Account. Subscribe the app using the WABA ID so events for the phone numbers under that account are sent to the webhook endpoint configured for the app.
Use the WABA ID in this endpoint, not the Phone Number ID. After the request succeeds, send one known incoming or outbound message and confirm the corresponding webhook reaches your backend.
Subscribe Request
curl -X POST \\
"https://graph.facebook.com/<GRAPH_API_VERSION>/<WABA_ID>/subscribed_apps" \\
-H "Authorization: Bearer <ACCESS_TOKEN>"Implementation Checklist
- Use the correct WABA ID for the business phone numbers you are testing.
- Use a token with access to the intended WhatsApp business assets.
- Confirm the callback URL is already verified in the same Meta app.
- Test an event immediately and inspect backend logs before continuing.
Step 11
Store and Log Webhook Events
A webhook endpoint must be publicly reachable over HTTPS and able to respond quickly to Meta. During setup, Meta verifies the callback URL. After that, POST requests carry incoming messages, status updates, and other subscribed events to your backend.
Keep the webhook route small. Validate the request, parse the event, store or queue the important data, and return a successful response promptly. Heavy CRM calls, AI generation, or long database work should not make Meta wait for the HTTP response.
Implementation Checklist
- Use a public HTTPS callback URL that Meta can reach from the internet.
- Keep the verify token separate from the Graph API access token.
- Log webhook event IDs, message IDs, and event type without logging secrets.
- Make processing idempotent because the same event can be delivered more than once.
Step 12
Common Webhook Problems
A webhook endpoint must be publicly reachable over HTTPS and able to respond quickly to Meta. During setup, Meta verifies the callback URL. After that, POST requests carry incoming messages, status updates, and other subscribed events to your backend.
Keep the webhook route small. Validate the request, parse the event, store or queue the important data, and return a successful response promptly. Heavy CRM calls, AI generation, or long database work should not make Meta wait for the HTTP response.
Implementation Checklist
- Use a public HTTPS callback URL that Meta can reach from the internet.
- Keep the verify token separate from the Graph API access token.
- Log webhook event IDs, message IDs, and event type without logging secrets.
- Make processing idempotent because the same event can be delivered more than once.
Related Guides
Continue Learning
Need Implementation Help?
Need Help With Your WhatsApp or Automation Project?
If you need help building, integrating, troubleshooting, or improving a production system, you can discuss the project with me directly.
