Skip to main content
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

url
string
required
The HTTPS URL Waply will send event payloads to. Must use https://. Plain http:// URLs are rejected.
events
string[]
required
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 typeTriggered when
message.receivedA new inbound message arrives on any channel
message.deliveredAn outbound message is delivered to the recipient
message.readAn outbound message is read by the recipient
conversation.assignedA conversation is assigned to an agent or team
conversation.resolvedA conversation is marked as resolved
contact.createdA new contact is created
broadcast.completedA 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.
id
string
required
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'
{
  "success": true
}