Receiving messages
You expose one base URL. We append the platform path and POST JSON to it.
Validate first
Section titled “Validate first”Every dispatch carries the shared token you configured:
x-webhook-token: whsec_…Compare it against your own copy before you parse anything, and reject otherwise. This is the only thing that proves the request came from us.
app.post("/chat/whatsapp/receive", (req, res) => { if (req.headers["x-webhook-token"] !== process.env.NEIKE_WEBHOOK_TOKEN) { return res.sendStatus(401); } const { event, channel, contact, message } = req.body; queue.add({ event, channel, contact, message }); // do the work off the request res.sendStatus(200);});@app.post("/chat/whatsapp/receive")def receive(request): if request.headers.get("x-webhook-token") != os.environ["NEIKE_WEBHOOK_TOKEN"]: return Response(status=401) body = request.json() enqueue(body["channel"], body["contact"], body["message"]) # do the work off the request return Response(status=200)Idempotency
Section titled “Idempotency”message.id is the provider’s message id — the wamid… on WhatsApp,
the mid… on Instagram and Messenger. It is stable across retries, so use it as
your deduplication key. We already deduplicate on our side, but a retry after a
timeout can still reach you twice: your handler must be safe to run again.
Status updates
Section titled “Status updates”As Meta confirms each step, we POST to {base}/chat/whatsapp/update with the
provider message id and the new state:
{ "provider_message_id": "wamid.HBgNNTQ5MTEy…", "status": "delivered" }States are sent, delivered, read and failed. A failed update carries
the reason Meta gave. The path is the same for all three channels.
When your endpoint is down
Section titled “When your endpoint is down”Failed dispatches are retried and recorded. What we tried, what your server answered and when is visible per channel in the console, and a failed event can be replayed once you are back — you do not need to ask us to resend.