Webhooks let you receive real-time notifications when events happen in your Waply account. Instead of polling the API, you register an HTTPS endpoint and Waply sends a POST request to it whenever a subscribed event occurs. This is the recommended way to react to inbound messages, conversation updates, and broadcast completions.
Register a webhook
Send a POST request to /webhooks with the URL you want to receive events at and the list of event types you want to subscribe to.
POST /webhooks
The HTTPS URL Waply will send event payloads to. Must use https://. Plain http:// URLs are rejected.
Array of event type strings to subscribe to. See Event types for the full list.
curl --request POST \
--url https://api.waply.io/v1/webhooks \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"url": "https://yourapp.com/waply/webhook",
"events": ["message.received", "conversation.resolved"]
}'
The response includes a secret field. Store this secret securely — you will use it to verify that incoming webhook requests genuinely come from Waply.
{
"id": "wh_01HXYZ",
"url": "https://yourapp.com/waply/webhook",
"events": ["message.received", "conversation.resolved"],
"secret": "whsec_a4b8c16d...",
"created_at": "2026-04-16T10:00:00Z"
}
The secret is only returned in the response to the initial POST /webhooks request. It is not retrievable afterwards. If you lose it, delete the webhook and create a new one.
List webhooks
GET /webhooks
Returns all webhooks registered on your account.
curl --request GET \
--url https://api.waply.io/v1/webhooks \
--header 'Authorization: Bearer YOUR_API_KEY'
Event types
Subscribe to any combination of the following event types when registering a webhook:
| Event type | Triggered when |
|---|
message.received | A new inbound message arrives on any channel |
message.delivered | An outbound message is delivered to the recipient |
message.read | An outbound message is read by the recipient |
conversation.assigned | A conversation is assigned to an agent or team |
conversation.resolved | A conversation is marked as resolved |
contact.created | A new contact is created |
broadcast.completed | A broadcast finishes sending to all recipients |
Webhook payload
Every event Waply sends to your endpoint has the same envelope structure:
{
"event": "message.received",
"timestamp": "2026-04-16T10:05:23Z",
"data": {
"id": "msg_01HABC",
"conversation_id": "conv_01HDEF",
"direction": "inbound",
"type": "text",
"content": "Hello, I need help with my order.",
"status": "delivered",
"created_at": "2026-04-16T10:05:23Z"
}
}
The shape of the data object varies by event type and matches the corresponding API object (Message, Conversation, Contact, or Broadcast).
Verify the webhook signature
Waply signs every webhook request with an HMAC-SHA256 signature so you can confirm it came from Waply and not a third party. The signature is sent in the X-Waply-Signature header as a hex string.
To verify the signature, compute the HMAC-SHA256 of the raw request body using your webhook secret and compare it to the value in the header.
const crypto = require('crypto');
function verifySignature(rawBody, secret, signatureHeader) {
const expected = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
// Use timingSafeEqual to prevent timing attacks
const expectedBuf = Buffer.from(expected, 'hex');
const receivedBuf = Buffer.from(signatureHeader, 'hex');
if (expectedBuf.length !== receivedBuf.length) return false;
return crypto.timingSafeEqual(expectedBuf, receivedBuf);
}
// Express example
app.post('/waply/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-waply-signature'];
if (!verifySignature(req.body, process.env.WAPLY_WEBHOOK_SECRET, signature)) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(req.body);
console.log('Verified event:', event.event);
res.sendStatus(200);
});
Always use your raw request body (before JSON parsing) when computing the signature. Parsing and re-serialising the JSON may change whitespace or key ordering, which will cause the comparison to fail.
Delete a webhook
DELETE /webhooks/
Unregisters a webhook. Waply immediately stops sending events to the associated URL.
The ID of the webhook to delete.
curl --request DELETE \
--url https://api.waply.io/v1/webhooks/wh_01HXYZ \
--header 'Authorization: Bearer YOUR_API_KEY'