Setting up a webhook endpoint involves two parts: building the HTTP endpoint on your server that will receive events, and registering that endpoint URL in the relevant platform dashboard. This article walks through both steps with code examples and covers testing and debugging your endpoint.
Prerequisites
- A publicly accessible HTTPS URL — your endpoint must be reachable from the internet. Local development URLs (localhost, 127.0.0.1) will not work directly — see the local testing section below.
- A valid TLS/SSL certificate — the URL must use HTTPS. Self-signed certificates are not accepted.
- Your server must respond with HTTP 200 within 30 seconds of receiving the webhook.
Part 1 — Building Your Webhook Endpoint
Your endpoint needs to: receive the POST request, verify the signature, return 200 immediately, then process the payload. Here are minimal working examples:
PHP (plain)
<?php
// webhook.php
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$secret = getenv('WEBHOOK_SECRET');
$expected = 'sha256=' . hash_hmac('sha256', $payload, $secret);
if (!hash_equals($expected, $signature)) {
http_response_code(401);
exit('Invalid signature');
}
// Return 200 immediately
http_response_code(200);
echo 'OK';
// Flush output so response is sent before processing
if (function_exists('fastcgi_finish_request')) {
fastcgi_finish_request();
}
// Process the event asynchronously
$event = json_decode($payload, true);
handleEvent($event);
function handleEvent(array $event): void {
switch ($event['event']) {
case 'email.delivered':
// Update your database record
break;
case 'email.bounced':
// Handle bounce
break;
// Add more cases as needed
}
}
Python (Flask)
import os, hmac, hashlib
from flask import Flask, request, jsonify
app = Flask(__name__)
WEBHOOK_SECRET = os.environ.get('WEBHOOK_SECRET')
@app.route('/webhooks/rackwave', methods=['POST'])
def handle_webhook():
payload = request.get_data()
signature = request.headers.get('X-Webhook-Signature', '')
expected = 'sha256=' + hmac.new(
WEBHOOK_SECRET.encode(), payload, hashlib.sha256
).hexdigest()
if not hmac.compare_digest(expected, signature):
return jsonify(error='Invalid signature'), 401
# Return 200 immediately
event = request.get_json()
# Process asynchronously (e.g. push to queue)
process_event.delay(event) # Celery task
return jsonify(success=True), 200
Node.js (Express)
const express = require('express');
const crypto = require('crypto');
const app = express();
app.use(express.raw({ type: 'application/json' }));
app.post('/webhooks/rackwave', (req, res) => {
const signature = req.headers['x-webhook-signature'] || '';
const expected = 'sha256=' + crypto
.createHmac('sha256', process.env.WEBHOOK_SECRET)
.update(req.body)
.digest('hex');
if (!crypto.timingSafeEqual(
Buffer.from(expected), Buffer.from(signature)
)) {
return res.status(401).send('Invalid signature');
}
// Respond immediately
res.status(200).json({ success: true });
// Process asynchronously
const event = JSON.parse(req.body);
processEvent(event);
});
app.listen(3000);
Part 2 — Registering Your Endpoint in MigoSMTP
- Log in to your MigoSMTP dashboard.
- Go to Developer → Webhooks in the left sidebar.
- Click Add Webhook.
- Enter your endpoint URL (must be HTTPS).
- Select the events you want to subscribe to (e.g.
email.delivered,email.bounced,email.opened). - Copy the displayed Webhook Secret — store it as the
WEBHOOK_SECRETenvironment variable on your server. - Click Save Webhook.
- Click Send Test Event to fire a test payload to your endpoint and confirm it responds correctly.
Part 2 — Registering Your Endpoint in Telnxo
- Log in to your Telnxo dashboard.
- Go to Developer → Webhooks.
- Click Create Webhook.
- Enter your endpoint URL.
- Select event categories: SMS events, Voice events, WhatsApp events — or all.
- Copy the Webhook Secret and store securely.
- Click Save.
- Use Test Webhook to send a sample payload and verify delivery.
Part 2 — Registering for Portal Subscription Events (Rackwave)
Subscription lifecycle events (plan activated, invoice paid, service suspended) are configured from the Rackwave portal, not the individual platform dashboards:
- Log in to the Rackwave portal.
- Go to My Account → Webhooks or ask your account manager to configure this.
- Register your endpoint URL and select subscription event types.
Testing Webhooks Locally
Since webhook deliveries require a public URL, you need a tunnelling tool for local development:
| Tool | How to Use | Free Tier |
|---|---|---|
| ngrok | ngrok http 3000 — creates a public HTTPS URL forwarding to localhost:3000 |
Yes — random URL, resets on restart |
| Cloudflare Tunnel | cloudflared tunnel --url http://localhost:3000 |
Yes — no account required for quick tunnels |
| VS Code Forward Port | Port forwarding via GitHub Codespaces or VS Code Remote tunnels | Yes (with GitHub account) |
Webhook Delivery Log
Both MigoSMTP and Telnxo dashboards include a Webhook Delivery Log showing every webhook attempt — the event type, your endpoint URL, the HTTP response code received, the response body, and whether delivery succeeded or failed. Use this log to debug endpoint issues without needing external logging tools.