Skip to main content

Event Types

EventDescription
dlrDelivery reports (status updates)
moInbound 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

CodeDescription
1Invalid destination
2Destination unreachable
3Insufficient balance
4Message 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:
AttemptDelay
1Immediate
25 seconds
325 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

  1. Respond quickly — Acknowledge with 200 status before processing
  2. Process async — Queue webhook data for background processing
  3. Verify signatures — Always validate X-Webhook-Signature
  4. Handle duplicates — Use message_id for idempotency
  5. 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);
});