Event Types
| Event | Description |
|---|
dlr | Delivery reports (status updates) |
mo | Inbound messages (mobile-originated) |
Creating Subscriptions
curl -X POST https://api-message.nativehub.live/api/v1/webhooks \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://yourapp.com/webhooks",
"events": ["dlr", "mo"],
"secret": "your_signing_secret"
}'
The secret is optional but recommended for signature verification.
DLR Payload
Delivery reports notify of status changes:
{
"event": "dlr",
"message_id": "msg_abc123",
"status": "delivered",
"error_code": null,
"destination": "+1234567890",
"delivered_at": "2026-02-14T10:30:15Z"
}
Status Values
submitted — Sent to carrier
delivered — Confirmed delivery
failed — Delivery failed
expired — Validity period exceeded
Error Codes
| Code | Description |
|---|
1 | Invalid destination |
2 | Destination unreachable |
3 | Insufficient balance |
4 | Message rejected |
MO Payload
Inbound messages from users:
{
"event": "mo",
"message_id": "msg_xyz789",
"source": "+1234567890",
"destination": "+9876543210",
"content": "STOP",
"received_at": "2026-02-14T10:25:00Z"
}
HMAC Signature Verification
Verify webhook authenticity using the X-Webhook-Signature header:
const crypto = require('crypto');
function verifySignature(payload, signature, secret) {
const hmac = crypto.createHmac('sha256', secret);
hmac.update(JSON.stringify(payload));
const computed = hmac.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(computed)
);
}
app.post('/webhooks', (req, res) => {
const signature = req.headers['x-webhook-signature'];
const secret = 'your_signing_secret';
if (!verifySignature(req.body, signature, secret)) {
return res.status(401).send('Invalid signature');
}
// Process webhook
res.status(200).send('OK');
});
Retry Policy
Failed webhook deliveries are retried with exponential backoff:
| Attempt | Delay |
|---|
| 1 | Immediate |
| 2 | 5 seconds |
| 3 | 25 seconds |
After 3 failed attempts, the webhook is marked as failed and logged.
Return a 200 status code within 5 seconds to avoid retries.
Testing Webhooks
Use the test endpoint to send sample events:
curl -X POST https://api-message.nativehub.live/api/v1/webhooks/webhook_abc123/test \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"event_type": "dlr"}'
Best Practices
- Respond quickly — Acknowledge with 200 status before processing
- Process async — Queue webhook data for background processing
- Verify signatures — Always validate
X-Webhook-Signature
- Handle duplicates — Use
message_id for idempotency
- Monitor failures — Check failed webhook logs regularly
Async Processing Example
const queue = require('./queue');
app.post('/webhooks', async (req, res) => {
// Verify signature
if (!verifySignature(req.body, req.headers['x-webhook-signature'], secret)) {
return res.status(401).send('Invalid signature');
}
// Respond immediately
res.status(200).send('OK');
// Queue for async processing
await queue.add('webhook-processing', req.body);
});