Webhooks
Configure real-time notifications for message events, delivery receipts, and incoming messages using webhooks.
Overview
Webhooks allow your application to receive real-time HTTP POST notifications when events occur in your Amanah AI account. Instead of polling our API for updates, webhooks push data to your application as events happen.
[Done] Benefits
- Real-time event notifications
- Reduced API polling overhead
- Better user experience
- Automatic retry mechanism
🔧 Requirements
- HTTPS endpoint (SSL required)
- Return 200 status code
- Respond within 30 seconds
- Handle duplicate events
Setup and Configuration
1. Create Webhook Endpoint
Node.js/Express Example
const express = require('express');
const crypto = require('crypto');
const app = express();
app.use(express.json());
// Webhook endpoint
app.post('/webhooks/amanahagent', (req, res) => {
const signature = req.headers['x-webhook-signature'];
const secret = process.env.WEBHOOK_SECRET;
// Verify signature
if (verifySignature(req.body, signature, secret)) {
const event = req.body;
console.log('Received event:', event.event);
console.log('Event data:', event.data);
// Process the event
handleWebhookEvent(event);
res.status(200).send('OK');
} else {
res.status(401).send('Unauthorized');
}
});
function verifySignature(payload, signature, secret) {
const hmac = crypto.createHmac('sha256', secret);
hmac.update(JSON.stringify(payload));
const calculatedSignature = 'sha256=' + hmac.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(calculatedSignature)
);
}
app.listen(3000, () => {
console.log('Webhook server running on port 3000');
});Python/Flask Example
import hmac
import hashlib
import json
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/webhooks/amanahagent', methods=['POST'])
def webhook_handler():
signature = request.headers.get('X-Webhook-Signature')
secret = os.environ.get('WEBHOOK_SECRET')
# Verify signature
if verify_signature(request.data, signature, secret):
event = request.json
print(f"Received event: {event['event']}")
print(f"Event data: {event['data']}")
# Process the event
handle_webhook_event(event)
return jsonify({'status': 'success'}), 200
else:
return jsonify({'error': 'Unauthorized'}), 401
def verify_signature(payload, signature, secret):
calculated_signature = 'sha256=' + hmac.new(
secret.encode(),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, calculated_signature)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=3000)2. Configure Webhook via API
POST https://api.amanahagent.cloud/v1/webhooksRequest Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| url | string | Required | HTTPS URL to receive webhook events |
| events | array | Required | Event types to subscribe to |
| secret | string | Optional | Secret for webhook signature verification |
Example Request
curl -X POST https://api.amanahagent.cloud/v1/webhooks -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" -d '{
"url": "https://your-app.com/webhooks/amanahagent",
"events": [
"message.sent",
"message.delivered",
"message.read",
"message.received"
],
"secret": "your-webhook-secret"
}'Event Types and Payload Structures
message.sent
Triggered when a message is successfully sent to WhatsApp servers.
Payload Structure
{
"event": "message.sent",
"timestamp": "2024-01-15T10:30:00Z",
"data": {
"message_id": "msg_abc123xyz789",
"status": "sent",
"to": "+1234567890",
"type": "text",
"message": "Hello from Amanah AI!",
"sent_at": "2024-01-15T10:30:00Z",
"credits_used": 1
}
}message.delivered
Triggered when a message is successfully delivered to the recipient's device.
Payload Structure
{
"event": "message.delivered",
"timestamp": "2024-01-15T10:30:15Z",
"data": {
"message_id": "msg_abc123xyz789",
"status": "delivered",
"to": "+1234567890",
"delivered_at": "2024-01-15T10:30:15Z"
}
}message.read
Triggered when a message is read by the recipient (if read receipts are enabled).
Payload Structure
{
"event": "message.read",
"timestamp": "2024-01-15T10:35:20Z",
"data": {
"message_id": "msg_abc123xyz789",
"status": "read",
"to": "+1234567890",
"read_at": "2024-01-15T10:35:20Z"
}
}message.failed
Triggered when a message fails to be delivered.
Payload Structure
{
"event": "message.failed",
"timestamp": "2024-01-15T10:30:30Z",
"data": {
"message_id": "msg_abc123xyz789",
"status": "failed",
"to": "+1234567890",
"error": {
"code": "INVALID_PHONE_NUMBER",
"message": "The phone number is not valid"
},
"failed_at": "2024-01-15T10:30:30Z"
}
}message.received
Triggered when you receive an incoming message from a user.
Payload Structure
{
"event": "message.received",
"timestamp": "2024-01-15T10:40:00Z",
"data": {
"message_id": "msg_incoming_xyz123",
"from": "+1234567890",
"type": "text",
"message": "Hello! I need help with my order.",
"received_at": "2024-01-15T10:40:00Z",
"contact": {
"name": "John Doe",
"profile_picture": "https://example.com/profile.jpg"
}
}
}Security and Verification
⚠️ Important Security Note
Always verify webhook signatures to ensure the requests are coming from Amanah AI and haven't been tampered with.
Signature Verification
Each webhook request includes a X-Webhook-Signature header containing an HMAC-SHA256 signature of the request body.
Verification Process
- Get the signature from the
X-Webhook-Signatureheader - Create an HMAC-SHA256 hash of the raw request body using your webhook secret
- Prepend "sha256=" to your calculated hash
- Compare the signatures using a timing-safe comparison function
Verification Examples
JavaScript
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const hmac = crypto.createHmac('sha256', secret);
hmac.update(payload, 'utf8');
const calculatedSignature = 'sha256=' + hmac.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(calculatedSignature)
);
}
// Usage
const isValid = verifyWebhookSignature(
JSON.stringify(req.body),
req.headers['x-webhook-signature'],
process.env.WEBHOOK_SECRET
);
if (!isValid) {
return res.status(401).send('Invalid signature');
}Python
import hmac
import hashlib
def verify_webhook_signature(payload, signature, secret):
calculated_signature = 'sha256=' + hmac.new(
secret.encode('utf-8'),
payload.encode('utf-8'),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, calculated_signature)
# Usage
is_valid = verify_webhook_signature(
request.data.decode('utf-8'),
request.headers.get('X-Webhook-Signature'),
os.environ['WEBHOOK_SECRET']
)
if not is_valid:
return jsonify({'error': 'Invalid signature'}), 401IP Whitelisting
For additional security, you can whitelist the following IP addresses to only accept webhook requests from Amanah AI:
• 52.89.214.238
• 54.218.53.128
• 52.32.178.7Testing Webhooks
Development Tools
🌐 ngrok
Expose your local development server to receive webhooks
ngrok http 3000🔧 Webhook.site
Inspect and debug webhook payloads
https://webhook.siteTest Event
You can trigger a test webhook event to verify your endpoint is working correctly:
POST /webhooks/{webhook_id}/testExample Request
curl -X POST https://api.amanahagent.cloud/v1/webhooks/webhook_123/test -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json"
Webhook Logs
Monitor webhook delivery attempts, response codes, and retry information:
GET /webhooks/{webhook_id}/logsTroubleshooting Common Issues
[Fail] Webhook Not Receiving Events
- Ensure your endpoint is publicly accessible via HTTPS
- Check that your server is returning a 200 status code
- Verify the webhook is configured for the correct events
- Check your firewall settings and IP whitelisting
⚠️ Signature Verification Failing
- Ensure you're using the raw request body for signature calculation
- Verify your webhook secret is correct
- Check that you're using the correct hash algorithm (HMAC-SHA256)
- Use timing-safe comparison functions to prevent timing attacks
🔄 Duplicate Events
- Implement idempotency using the message_id or event timestamp
- Store processed event IDs to avoid duplicate processing
- Handle retries gracefully by returning 200 for already processed events
⏱️ Timeout Issues
- Respond with 200 status within 30 seconds
- Process webhook events asynchronously if needed
- Queue heavy processing tasks for later execution
- Optimize your endpoint for fast response times
Best Practices
[Done] Do
- Always verify webhook signatures
- Return 200 status code quickly
- Implement idempotency checks
- Use HTTPS endpoints
- Log webhook events for debugging
- Handle retries gracefully
- Process events asynchronously
[Fail] Don't
- Skip signature verification
- Take longer than 30 seconds to respond
- Process the same event multiple times
- Use HTTP (non-SSL) endpoints
- Ignore error handling
- Block the webhook response with heavy processing
- Expose webhook secrets in logs