Pro: $9.99/mo or $99.99/yrView Plans
Documentation

Webhooks

Learn how to configure and use webhooks to receive real-time notifications for SMS events in textbee.dev.

Webhooks let textbee.dev notify your server in real time when events happen, so you don’t need to poll the API.

What are Webhooks?

Webhooks are HTTP callbacks that textbee.dev sends to your server when specific events occur. This enables event-driven architectures and real-time integrations.

Supported Events

textbee.dev supports the following webhook events:

  • MESSAGE_RECEIVED: When an SMS is received on your device
  • MESSAGE_SENT: When an SMS has been sent from your device
  • MESSAGE_DELIVERED: When an SMS has been delivered to the recipient
  • MESSAGE_FAILED: When sending an SMS has failed

Setting Up Webhooks

Set up webhooks in the dashboard. You need a public URL that accepts HTTP POST requests and returns 200 to acknowledge receipt.

  1. Open the dashboard and go to Webhooks (or Settings > Webhooks).
  2. Click Add Webhook or Create Webhook.
  3. Enter your webhook URL (use HTTPS in production).
  4. Select the events you want: MESSAGE_RECEIVED, MESSAGE_SENT, MESSAGE_DELIVERED, MESSAGE_FAILED (or a subset).
  5. (Recommended) Set a signing secret (at least 20 characters) for signature verification.
  6. Save. textbee.dev will send POST requests to your URL when the selected events occur.

Webhook Payloads

Payloads are JSON with event, timestamp, and data. Return 200 quickly and process in the background if needed.

MESSAGE_RECEIVED

{
  "event": "MESSAGE_RECEIVED",
  "timestamp": "2026-01-20T10:30:00Z",
  "data": {
    "_id": "abc123",
    "sender": "+1234567890",
    "message": "Hello!",
    "receivedAt": "2025-01-15T10:30:00Z",
    "device": { "_id": "device123", "enabled": true, "model": "Pixel 7" },
    "createdAt": "2025-01-15T10:30:01Z",
    "updatedAt": "2025-01-15T10:30:01Z"
  }
}

MESSAGE_SENT

Sent when an SMS has been sent from your device. data includes message id, recipient(s), and device info.

MESSAGE_DELIVERED

Sent when the carrier reports delivery. data includes message id, recipient, and delivery time.

MESSAGE_FAILED

Sent when sending failed. data includes message id, recipient, and error details.

Webhook Security

Signature Verification

To verify that webhooks are coming from textbee.dev, use signature verification:

  1. When creating a webhook, set a secret (a random string)
  2. textbee.dev will include a signature in the X-Textbee-Signature header
  3. Verify the signature on your server

Example: Signature Verification

const crypto = require('crypto');

function verifyWebhookSignature(payload, signature, secret) {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(JSON.stringify(payload))
    .digest('hex');
  
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

app.post('/webhook/textbee', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-textbee-signature'];
  const secret = process.env.WEBHOOK_SECRET;
  
  if (!verifyWebhookSignature(req.body, signature, secret)) {
    return res.status(401).json({ error: 'Invalid signature' });
  }
  
  const payload = JSON.parse(req.body);
  // Process webhook...
  
  res.status(200).json({ success: true });
});

Webhook Handler Examples

Node.js/Express

const express = require('express');
const app = express();

app.use(express.json());

app.post('/webhook/textbee', (req, res) => {
  const { event, data } = req.body;
  switch (event) {
    case 'MESSAGE_RECEIVED':
      console.log(`Received from ${data.sender}: ${data.message}`);
      break;
    case 'MESSAGE_SENT':
      console.log(`Sent to ${data.recipient}`);
      break;
    case 'MESSAGE_DELIVERED':
      console.log(`Delivered to ${data.recipient}`);
      break;
    case 'MESSAGE_FAILED':
      console.error(`Failed to ${data.recipient}: ${data.error}`);
      break;
    default:
      console.log(`Event: ${event}`);
  }
  res.status(200).json({ success: true });
});

app.listen(3000, () => {
  console.log('Webhook server listening on port 3000');
});

Python/Flask

from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route('/webhook/textbee', methods=['POST'])
def webhook():
    payload = request.json
    event = payload.get('event')
    data = payload.get('data') or {}
    if event == 'MESSAGE_RECEIVED':
        print(f"Received from {data.get('sender')}: {data.get('message')}")
    elif event == 'MESSAGE_SENT':
        print(f"Sent to {data.get('recipient')}")
    elif event == 'MESSAGE_DELIVERED':
        print(f"Delivered to {data.get('recipient')}")
    elif event == 'MESSAGE_FAILED':
        print(f"Failed to {data.get('recipient')}: {data.get('error')}")
    return jsonify({'success': True}), 200

if __name__ == '__main__':
    app.run(port=3000)

Webhook Retries

If your webhook endpoint returns a non-2xx status code, the delivery attempt is considered failed.

Best Practices

  1. Always return 200 OK immediately after receiving a webhook (process asynchronously if needed)
  2. Implement idempotency - handle duplicate webhooks gracefully
  3. Verify webhook signatures to ensure authenticity
  4. Use HTTPS for webhook URLs in production
  5. Log all webhook events for debugging and auditing
  6. Handle errors gracefully - don't let webhook processing crash your server
  7. Process webhooks asynchronously if processing takes time
  8. Monitor webhook delivery - set up alerts for failed webhooks

Next Steps

Need help? Check our FAQ or contact support.