Webhooks
Receive real-time notifications for message events, status updates, and more.
Setting Up Webhooks
- Create an endpoint
Set up an HTTPS endpoint on your server to receive webhook events. - Configure in Dashboard
Go to Dashboard → Developer → Webhooks and add your endpoint URL. - Select events
Choose which events you want to receive notifications for. - Verify signatures
Always verify the webhook signature to ensure requests are from Aerostic.
Event Types
message.receivedTriggered when a new message is received from a customer
{
"event": "message.received",
"timestamp": "2026-01-30T15:45:00Z",
"data": {
"id": "msg_abc123",
"from": "+919876543210",
"type": "text",
"text": "Hi, I need help with my order",
"wamid": "wamid.ABGGFlC..."
}
}message.sentTriggered when a message is successfully sent
{
"event": "message.sent",
"timestamp": "2026-01-30T15:45:05Z",
"data": {
"id": "msg_def456",
"to": "+919876543210",
"status": "sent",
"wamid": "wamid.ABGGFlC..."
}
}message.deliveredTriggered when a message is delivered to the recipient
{
"event": "message.delivered",
"timestamp": "2026-01-30T15:45:10Z",
"data": {
"id": "msg_def456",
"to": "+919876543210",
"status": "delivered",
"deliveredAt": "2026-01-30T15:45:10Z"
}
}message.readTriggered when a message is read by the recipient
{
"event": "message.read",
"timestamp": "2026-01-30T15:46:00Z",
"data": {
"id": "msg_def456",
"to": "+919876543210",
"status": "read",
"readAt": "2026-01-30T15:46:00Z"
}
}message.failedTriggered when a message fails to send
{
"event": "message.failed",
"timestamp": "2026-01-30T15:45:05Z",
"data": {
"id": "msg_ghi789",
"to": "+919876543210",
"status": "failed",
"error": {
"code": "INVALID_RECIPIENT",
"message": "Phone number is not on WhatsApp"
}
}
}contact.createdTriggered when a new contact is added
{
"event": "contact.created",
"timestamp": "2026-01-30T15:45:00Z",
"data": {
"id": "contact_xyz",
"phone": "+919876543210",
"name": "John Doe",
"tags": ["new", "website"]
}
}Signature Verification
Security Best Practice
Always verify webhook signatures to prevent spoofed requests.
Every webhook request includes an X-Aerostic-Signature header. Verify this signature using your webhook secret:
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return signature === `sha256=${expectedSignature}`;
}
// Express.js middleware example
app.post('/webhook', express.raw({ type: '*/*' }), (req, res) => {
const signature = req.headers['x-aerostic-signature'];
const isValid = verifyWebhookSignature(req.body, signature, WEBHOOK_SECRET);
if (!isValid) {
return res.status(401).json({ error: 'Invalid signature' });
}
const event = JSON.parse(req.body);
console.log('Received event:', event.event);
// Process the event...
res.status(200).json({ received: true });
});Retry Policy
If your endpoint returns a non-2xx status code, we'll retry the webhook with exponential backoff:
| Attempt | Delay |
|---|---|
| Attempt 1 | Immediate |
| Attempt 2 | 30 seconds |
| Attempt 3 | 5 minutes |
| Attempt 4 | 30 minutes |
| Attempt 5 | 2 hours |
After 5 failed attempts, the webhook will be marked as failed and you'll receive an email notification.
Best Practices
Respond quickly
Return a 200 status within 5 seconds
Process async
Queue events for background processing
Handle duplicates
Use event IDs to detect duplicates
Use HTTPS
Secure your endpoint with TLS