Plans from $9.99/moView Plans
Documentation

Webhooks

Learn how to configure and use webhooks to receive real-time notifications for SMS events in textbee.dev. Supports multiple webhook endpoints per account.

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. You can register multiple webhook endpoints on the same account β€” for example one for production, one for a staging integration, and one for your CRM. Each endpoint has its own signing secret and event subscriptions.

  1. Open the dashboard and go to Webhooks (or Settings > Webhooks).
  2. Click Add Webhook or Create Webhook.
  3. (Optional) Give the webhook a short name so you can tell your endpoints apart.
  4. Enter your webhook URL (use HTTPS in production). Private/loopback hosts (e.g. localhost, 127.0.0.1, RFC1918 ranges) are rejected.
  5. Select the events you want: MESSAGE_RECEIVED, MESSAGE_SENT, MESSAGE_DELIVERED, MESSAGE_FAILED (or a subset).
  6. (Recommended) Set a signing secret (at least 20 characters) for signature verification.
  7. Save. textbee.dev will send POST requests to your URL when the selected events occur. If multiple webhooks subscribe to the same event, each one receives its own independent delivery.

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-Signature header
  3. Verify the signature on your server using the secret configured for that specific webhook

If you have multiple webhooks, each one has its own signing secret β€” use the secret that matches the receiving endpoint.

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-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.