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.
- Open the dashboard and go to Webhooks (or Settings > Webhooks).
- Click Add Webhook or Create Webhook.
- Enter your webhook URL (use HTTPS in production).
- Select the events you want: MESSAGE_RECEIVED, MESSAGE_SENT, MESSAGE_DELIVERED, MESSAGE_FAILED (or a subset).
- (Recommended) Set a signing secret (at least 20 characters) for signature verification.
- 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:
- When creating a webhook, set a secret (a random string)
- textbee.dev will include a signature in the
X-Textbee-Signatureheader - 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
- Always return 200 OK immediately after receiving a webhook (process asynchronously if needed)
- Implement idempotency - handle duplicate webhooks gracefully
- Verify webhook signatures to ensure authenticity
- Use HTTPS for webhook URLs in production
- Log all webhook events for debugging and auditing
- Handle errors gracefully - don't let webhook processing crash your server
- Process webhooks asynchronously if processing takes time
- Monitor webhook delivery - set up alerts for failed webhooks
Next Steps
- Receiving SMS - Process incoming messages with webhooks
- Sending SMS - Reply to received messages
- Overview - Explore capabilities
Need help? Check our FAQ or contact support.