Verifying a WhatsApp webhook endpoint
Before delivering any event, Meta calls your endpoint with a GET carrying hub.mode, hub.verify_token and hub.challenge. Your endpoint must compare the token and return the challenge as the raw body. Anything else and delivery never starts.
- A GET before any delivery
- Return the raw challenge, not JSON
- Failure is silent, not an error
Nothing charged for 7 days. Cancel anytime.
The value that must be echoed back as the response body.
The value of hub.mode on a verification request.
The only scheme Meta will verify. HTTP is rejected before the call.
What exactly does Meta send?
A GET request to your URL with three query parameters. hub.mode is set to subscribe. hub.verify_token is the token you configured when setting the destination. hub.challenge is a value Meta generates for this attempt.
Your endpoint should compare hub.verify_token against the token you chose, and if it matches, respond 200 with hub.challenge as the entire response body. Not wrapped in JSON, not with quotes around it, not with a trailing newline that some frameworks add by default.
If the token does not match, respond 403. That is the whole protocol, and it is deliberately small.
Why does a wrong answer fail silently?
Because verification failing is not an error in your system, it is an absence in Meta's.
When the challenge is not echoed correctly, Meta simply does not begin delivering to that destination. Your server returns 200 to the verification, your logs show a request arrived, and no dashboard anywhere reports a problem. The only symptom is that messages never come, which most people diagnose as a Coexistence problem rather than as a handshake problem.
This is why validating before the call is worth doing. We check that the URL is HTTPS and that a verify token was supplied before making the Graph request, so a malformed destination fails immediately rather than looking connected.
What else can block verification?
Three things that have nothing to do with the code.
Authentication in front of the endpoint. A gateway, a basic auth layer or an IP allowlist will reject Meta's request, and Meta has no credentials to present. The verification route has to be reachable without them.
A redirect. Meta calls the URL you gave it, and a 301 to a canonical host is not followed in a way that completes the handshake. Give it the final URL.
And a framework that serialises the response. Returning a string from a handler that wraps everything in JSON produces a body with quotes around the challenge, which does not match.
Common mistakes
- Returning JSON. The body has to be the raw challenge value with nothing around it.
- Putting the endpoint behind authentication. Meta has no credentials and will be rejected.
- Giving Meta a URL that redirects. Use the final one.
EasyCoexistence validates that a destination is HTTPS and has a verify token before calling Meta, and records a failed handshake on the connection timeline rather than discarding the destination.
Frequently asked questions
What token should I use?
Any string you choose. It exists so your endpoint can tell Meta's request from anyone else's who learns the URL.
How often does verification happen?
On setup, and again whenever the destination is set. A working endpoint is not re-verified on every event.
Can I test it myself?
Yes. Call your own endpoint with the three parameters and check that the body comes back as exactly the challenge value.
What if my server was down during verification?
The handshake fails and the destination does not activate. Saving it again re-runs it.
Keep reading
Ready to get started?
Set up WhatsApp Coexistence in minutes, not months. The app keeps working on the phone.
Start Free TrialNothing charged for 7 days. Cancel anytime.Verified on