Webhooks
Webhooks deliver events in real time — inbound messages, delivery receipts, device status.
Create
Dashboard → webhooks:
- URL: your public POST endpoint
- Device: optional, limit to a single device
- Format:
Native(JSON),Twilio-compatible(form-encoded), or3CX(JSON 3CX-style) - Events: pick the ones you want
On creation you get a secret — save it to verify signatures.
Events
| Event | When it fires |
|---|---|
sms:received |
An SMS arrives at the phone |
sms:sent |
Confirmed sent by the carrier |
sms:delivered |
Delivered (requires withDeliveryReport: true) |
sms:failed |
Send failed |
mms:received / mms:downloaded / mms:sent / mms:delivered / mms:failed |
MMS lifecycle |
whatsapp:* |
WhatsApp lifecycle |
system:ping |
Device heartbeat |
device:online / device:offline |
Device connectivity |
Verifying signatures
Each request carries:
x-smsgw-event: sms:received
x-smsgw-signature: <hex HMAC-SHA256 of body>
x-smsgw-format: native | twilio | threecx
Node.js verification:
import crypto from 'crypto';
const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
const valid = req.headers['x-smsgw-signature'] === expected;
Retries
On 5xx or timeout (>30s), we retry with exponential backoff — up to 5 attempts in ~30 minutes. Your endpoint should be idempotent — key on messageId.
Payload examples
Native
{ "event": "sms:received", "deviceId": "cm...", "data": { "messageId": "cm...", "from": "+1...", "body": "...", "tenantId": "cm..." }, "at": "..." }
Twilio — form-encoded with From/To/Body/MessageSid/MessageStatus/NumMedia/MediaUrl0..N.
3CX — JSON with MessageType/MessageId/Status/From/To/Body/MediaUrls/ReceivedAt.