Webhooks▾
Webhooks
How Sendport delivers inbound messages, delivery receipts and template review results to your server.
Everything that happens asynchronously reaches you as a webhook: a customer replies, a message is delivered or read, a template clears review, a number's quality rating moves. Polling the API for these is the wrong shape — subscribe instead.
The envelope
POST body
{
"id": "evt_01JZQ6F5H7K9M1P3R5T7V9XZBD",
"object": "event",
"type": "message.received",
"created_at": "2026-09-06T09:41:02.114Z",
"api_version": "2026-09-01",
"data": { }
}idis stable across retries — use it to deduplicate.typeis the event name. New types are added over time; ignore what you do not handle.dataholds the resource, in the same shape the REST API returns it.
Responding
Answer 2xx within 5 seconds. Anything else — a timeout, a 4xx, a 5xx — is a failure and the event is retried. Do the work asynchronously: acknowledge first, enqueue second.
Node
app.post("/hooks/sendport", express.raw({ type: "application/json" }), (req, res) => {
if (!verify(req.body, req.headers["sendport-signature"])) {
return res.status(400).send("bad signature");
}
// Acknowledge immediately, then process off the request path.
res.sendStatus(200);
queue.push(JSON.parse(req.body.toString()));
});Event catalogue
| Event | Fires when |
|---|---|
message.received | A contact sends you a message |
message.sent | WhatsApp accepted an outbound message |
message.delivered | It reached the recipient's device |
message.read | The recipient opened it |
message.failed | Delivery failed permanently |
template.status_updated | Meta approved, rejected or paused a template |
template.quality_updated | A template's quality rating moved |
number.quality_updated | A number's quality rating or messaging tier moved |
conversation.assigned | A thread was assigned to an agent |