Webhooks Guide
Complete guide to UncleBTech webhooks including supported events, payload structures, and secure webhook processing.
Webhooks Guide
UncleBTech webhooks provide real-time notifications about important events in your account, allowing you to automate workflows and integrate with external systems. This guide covers webhook setup, event types, and secure processing.
Webhook Overview
What Are Webhooks?
Webhook Basics:
- Real-Time Notifications: Immediate notification when events occur
- HTTP POST Requests: Events sent as HTTP POST requests to your endpoint
- JSON Payload: Event data sent in JSON format
- Secure Delivery: Signed requests for verification and security
- Retry Logic: Automatic retries for failed deliveries
Webhook vs Polling:
# Traditional polling (inefficient) while (true) { check_for_new_invoices(); sleep(60); // Check every minute } # Webhook approach (efficient) webhook_endpoint('/invoices/created', function(event) { process_new_invoice(event.data); });
Webhook Architecture
Event Flow:
UncleBTech System → Event Trigger → Webhook Queue →
HTTP POST → Your Endpoint → Response Verification →
Retry Logic (if needed)
Delivery Guarantees:
- At-Least-Once Delivery: Events delivered at least once, possibly more
- Retry Logic: Failed deliveries retried with exponential backoff
- Timeout Handling: 30-second timeout for webhook responses
- Dead Letter Queue: Failed events stored for manual review
Supported Webhook Events
Service Events
Service Lifecycle Events:
# Service created service.created { "id": "svc_wp_123456", "type": "wordpress_hosting", "plan": "advanced", "domain": "example.com", "status": "provisioning", "created_at": "2025-01-21T10:00:00Z" } # Service activated service.activated { "id": "svc_wp_123456", "status": "active", "server_ip": "192.168.1.100", "control_panel_url": "https://cp.unclebtech.com/...", "activated_at": "2025-01-21T10:30:00Z" } # Service suspended service.suspended { "id": "svc_wp_123456", "status": "suspended", "reason": "payment_overdue", "suspended_at": "2025-01-21T10:00:00Z", "grace_period_ends": "2025-01-31T23:59:59Z" } # Service cancelled service.cancelled { "id": "svc_wp_123456", "status": "cancelled", "reason": "customer_request", "cancelled_at": "2025-01-21T10:00:00Z", "data_retention_until": "2025-02-21T10:00:00Z" }
Domain Events
Domain Lifecycle Events:
# Domain registered domain.registered { "domain": "newdomain.com", "registrar": "unclebtech", "expires_at": "2026-01-21T10:00:00Z", "nameservers": ["ns1.unclebtech.com", "ns2.unclebtech.com"], "registered_at": "2025-01-21T10:00:00Z" } # Domain transferred domain.transferred { "domain": "example.com", "transfer_status": "completed", "previous_registrar": "other-registrar", "transferred_at": "2025-01-21T10:00:00Z", "expires_at": "2026-01-21T10:00:00Z" } # Domain expiring soon domain.expiring { "domain": "example.com", "expires_at": "2025-02-21T10:00:00Z", "days_until_expiry": 30, "auto_renew_enabled": false, "renewal_price": "14.99" } # Domain expired domain.expired { "domain": "example.com", "expired_at": "2025-01-21T10:00:00Z", "grace_period_ends": "2025-02-21T10:00:00Z", "redemption_fee": "75.00" }
Billing Events
Payment and Invoice Events:
# Invoice created invoice.created { "id": "inv_123456", "number": "UBT-2025-001234", "amount": "17.99", "currency": "GBP", "due_date": "2025-01-28T23:59:59Z", "services": ["svc_wp_123456"], "created_at": "2025-01-21T10:00:00Z" } # Payment succeeded payment.succeeded { "id": "pay_123456", "invoice_id": "inv_123456", "amount": "17.99", "currency": "GBP", "payment_method": { "type": "card", "last4": "4242" }, "processed_at": "2025-01-21T10:30:00Z" } # Payment failed payment.failed { "id": "pay_123457", "invoice_id": "inv_123456", "amount": "17.99", "currency": "GBP", "failure_reason": "insufficient_funds", "retry_at": "2025-01-24T10:00:00Z", "failed_at": "2025-01-21T10:00:00Z" } # Subscription renewed subscription.renewed { "service_id": "svc_wp_123456", "previous_expires_at": "2025-01-21T10:00:00Z", "new_expires_at": "2025-02-21T10:00:00Z", "amount_charged": "14.99", "renewed_at": "2025-01-21T10:00:00Z" }
Support Events
Support Ticket Events:
# Ticket created ticket.created { "id": "tkt_123456", "number": "UBT-2025-001234", "subject": "WordPress site loading slowly", "department": "technical", "priority": "normal", "customer": { "id": "acc_123456", "email": "customer@example.com" }, "created_at": "2025-01-21T10:00:00Z" } # Ticket updated ticket.updated { "id": "tkt_123456", "status": "in_progress", "assigned_to": "Technical Support Team", "last_reply": { "from": "support", "message": "We're investigating the performance issue...", "created_at": "2025-01-21T11:00:00Z" }, "updated_at": "2025-01-21T11:00:00Z" } # Ticket resolved ticket.resolved { "id": "tkt_123456", "status": "resolved", "resolution": "Performance issue resolved by enabling advanced caching", "resolved_by": "Technical Support Team", "resolved_at": "2025-01-21T12:00:00Z" }
Webhook Configuration
Setting Up Webhooks
Create Webhook Endpoint:
POST /api/v1/webhooks { "url": "https://your-app.com/webhooks/unclebtech", "events": [ "service.created", "service.suspended", "payment.failed", "ticket.created" ], "secret": "your-webhook-secret-key", "active": true, "description": "Production webhook for service monitoring" } # Response { "success": true, "data": { "id": "wh_123456", "url": "https://your-app.com/webhooks/unclebtech", "events": ["service.created", "service.suspended", "payment.failed", "ticket.created"], "secret": "wh_secret_abc123", "active": true, "created_at": "2025-01-21T10:00:00Z" } }
List Configured Webhooks:
GET /api/v1/webhooks # Response { "success": true, "data": [ { "id": "wh_123456", "url": "https://your-app.com/webhooks/unclebtech", "events": ["service.created", "payment.failed"], "active": true, "last_delivery": "2025-01-21T09:30:00Z", "delivery_success_rate": "99.5%" } ] }
Update Webhook Configuration:
PUT /api/v1/webhooks/wh_123456 { "events": [ "service.created", "service.suspended", "service.cancelled", "payment.failed", "invoice.created" ], "active": true }
Webhook Security
Signature Verification:
import hmac import hashlib def verify_webhook_signature(payload, signature, secret): """Verify webhook signature for security""" expected_signature = hmac.new( secret.encode('utf-8'), payload.encode('utf-8'), hashlib.sha256 ).hexdigest() return hmac.compare_digest(signature, expected_signature) # Usage in webhook handler def handle_webhook(request): payload = request.body signature = request.headers.get('X-UncleBTech-Signature') if not verify_webhook_signature(payload, signature, webhook_secret): return HttpResponse(status=401) event = json.loads(payload) process_webhook_event(event) return HttpResponse(status=200)
Security Headers:
# Webhook request headers X-UncleBTech-Signature: sha256=abc123... X-UncleBTech-Event: payment.failed X-UncleBTech-Delivery: wh_delivery_123456 User-Agent: UncleBTech-Webhooks/1.0
Webhook Event Processing
Event Handler Examples
Node.js/Express Webhook Handler:
const express = require('express'); const crypto = require('crypto'); const app = express(); app.use(express.raw({ type: 'application/json' })); app.post('/webhooks/unclebtech', (req, res) => { const signature = req.headers['x-unclebtech-signature']; const payload = req.body; // Verify signature const expectedSignature = crypto .createHmac('sha256', process.env.WEBHOOK_SECRET) .update(payload) .digest('hex'); if (signature !== `sha256=${expectedSignature}`) { return res.status(401).send('Invalid signature'); } const event = JSON.parse(payload); // Process event switch (event.type) { case 'payment.failed': handlePaymentFailed(event.data); break; case 'service.suspended': handleServiceSuspended(event.data); break; case 'ticket.created': handleTicketCreated(event.data); break; default: console.log(`Unhandled event type: ${event.type}`); } res.status(200).send('OK'); }); function handlePaymentFailed(data) { // Send notification to customer // Update internal billing system // Trigger account review process }
PHP Webhook Handler:
<?php function handleUncleBTechWebhook() { $payload = file_get_contents('php://input'); $signature = $_SERVER['HTTP_X_UNCLEBTECH_SIGNATURE'] ?? ''; // Verify signature $expectedSignature = 'sha256=' . hash_hmac('sha256', $payload, $webhookSecret); if (!hash_equals($signature, $expectedSignature)) { http_response_code(401); exit('Invalid signature'); } $event = json_decode($payload, true); switch ($event['type']) { case 'service.created': // Send welcome email // Update CRM system // Provision additional services break; case 'invoice.created': // Sync with accounting system // Send custom invoice notification // Update payment tracking break; case 'ticket.created': // Notify support team // Update helpdesk system // Trigger auto-responses break; } http_response_code(200); echo 'OK'; }
Event Processing Patterns
Idempotent Processing:
# Ensure idempotent webhook processing def process_webhook_event(event): event_id = event['id'] # Check if event already processed if EventLog.objects.filter(event_id=event_id).exists(): return # Already processed # Process the event try: handle_event(event) # Log successful processing EventLog.objects.create( event_id=event_id, event_type=event['type'], status='processed', processed_at=timezone.now() ) except Exception as e: # Log failed processing EventLog.objects.create( event_id=event_id, event_type=event['type'], status='failed', error_message=str(e), processed_at=timezone.now() ) raise
Webhook Event Details
Service Event Payloads
Complete Service Created Event:
{ "id": "evt_123456", "type": "service.created", "created_at": "2025-01-21T10:00:00Z", "data": { "service": { "id": "svc_wp_123456", "type": "wordpress_hosting", "plan": "advanced", "domain": "example.com", "status": "provisioning", "server_ip": "192.168.1.100", "resource_limits": { "storage": "10 GB", "bandwidth": "100 GB", "php_memory": "512 MB" }, "expires_at": "2025-02-21T10:00:00Z" }, "customer": { "id": "acc_123456", "email": "customer@example.com", "name": "John Smith" } } }
Service Suspended Event:
{ "id": "evt_123457", "type": "service.suspended", "created_at": "2025-01-21T10:00:00Z", "data": { "service": { "id": "svc_wp_123456", "domain": "example.com", "status": "suspended", "suspension_reason": "payment_overdue", "suspended_at": "2025-01-21T10:00:00Z", "grace_period_ends": "2025-01-31T23:59:59Z" }, "invoice": { "id": "inv_123456", "amount": "17.99", "due_date": "2025-01-14T23:59:59Z", "days_overdue": 7 } } }
Payment Event Payloads
Payment Failed Event:
{ "id": "evt_123458", "type": "payment.failed", "created_at": "2025-01-21T10:00:00Z", "data": { "payment": { "id": "pay_123456", "invoice_id": "inv_123456", "amount": "17.99", "currency": "GBP", "failure_code": "card_declined", "failure_message": "Your card was declined", "payment_method": { "type": "card", "last4": "4242", "brand": "visa", "exp_month": 12, "exp_year": 2024 } }, "retry_schedule": { "next_retry": "2025-01-24T10:00:00Z", "max_retries": 3, "current_attempt": 1 }, "customer": { "id": "acc_123456", "email": "customer@example.com" } } }
Payment Succeeded Event:
{ "id": "evt_123459", "type": "payment.succeeded", "created_at": "2025-01-21T10:30:00Z", "data": { "payment": { "id": "pay_123457", "invoice_id": "inv_123456", "amount": "17.99", "currency": "GBP", "payment_method": { "type": "card", "last4": "4242", "brand": "visa" }, "processed_at": "2025-01-21T10:30:00Z" }, "services_affected": [ { "id": "svc_wp_123456", "action": "renewed", "new_expiry": "2025-02-21T10:30:00Z" } ] } }
Support Event Payloads
Ticket Created Event:
{ "id": "evt_123460", "type": "ticket.created", "created_at": "2025-01-21T10:00:00Z", "data": { "ticket": { "id": "tkt_123456", "number": "UBT-2025-001234", "subject": "WordPress site loading slowly", "department": "technical", "priority": "normal", "status": "open", "service_id": "svc_wp_123456", "created_at": "2025-01-21T10:00:00Z" }, "customer": { "id": "acc_123456", "email": "customer@example.com", "name": "John Smith" }, "initial_message": { "message": "My WordPress site has been loading very slowly...", "attachments": ["screenshot.png"] } } }
Webhook Endpoint Implementation
Basic Webhook Endpoint
Flask (Python) Example:
from flask import Flask, request, jsonify import hmac import hashlib import json app = Flask(__name__) @app.route('/webhooks/unclebtech', methods=['POST']) def handle_webhook(): # Get payload and signature payload = request.get_data() signature = request.headers.get('X-UncleBTech-Signature', '') # Verify signature if not verify_signature(payload, signature): return jsonify({'error': 'Invalid signature'}), 401 # Parse event try: event = json.loads(payload) except json.JSONDecodeError: return jsonify({'error': 'Invalid JSON'}), 400 # Process event try: process_event(event) return jsonify({'status': 'success'}), 200 except Exception as e: # Log error but return 200 to prevent retries for application errors log_error(f"Webhook processing error: {str(e)}") return jsonify({'status': 'error', 'message': str(e)}), 500 def verify_signature(payload, signature): expected = hmac.new( WEBHOOK_SECRET.encode(), payload, hashlib.sha256 ).hexdigest() return hmac.compare_digest(signature, f'sha256={expected}') def process_event(event): event_type = event['type'] event_data = event['data'] if event_type == 'payment.failed': handle_payment_failed(event_data) elif event_type == 'service.suspended': handle_service_suspended(event_data) elif event_type == 'ticket.created': handle_ticket_created(event_data) else: log_info(f"Unhandled event type: {event_type}")
Advanced Webhook Processing
Async Processing with Queue:
import asyncio from celery import Celery # Celery configuration for async processing celery_app = Celery('webhook_processor') @app.route('/webhooks/unclebtech', methods=['POST']) def handle_webhook(): # Verify signature (same as above) # Queue event for async processing event = json.loads(request.get_data()) process_webhook_async.delay(event) # Return immediately return jsonify({'status': 'queued'}), 200 @celery_app.task def process_webhook_async(event): """Process webhook event asynchronously""" try: # Process the event process_event(event) # Update processing status update_event_status(event['id'], 'processed') except Exception as e: # Handle errors and retry logic update_event_status(event['id'], 'failed', str(e)) raise
Webhook Testing and Debugging
Testing Webhook Endpoints
Webhook Testing Tool:
# Test webhook endpoint manually curl -X POST https://your-app.com/webhooks/unclebtech \ -H "Content-Type: application/json" \ -H "X-UncleBTech-Signature: sha256=test-signature" \ -H "X-UncleBTech-Event: payment.failed" \ -d '{ "id": "evt_test_123", "type": "payment.failed", "created_at": "2025-01-21T10:00:00Z", "data": { "payment": { "id": "pay_test_123", "invoice_id": "inv_test_123", "failure_reason": "card_declined" } } }'
Webhook Validation:
# Validate webhook configuration POST /api/v1/webhooks/wh_123456/test { "event_type": "payment.failed" } # Response { "success": true, "data": { "test_delivery_id": "del_test_123456", "status": "delivered", "response_code": 200, "response_time": "245ms", "delivered_at": "2025-01-21T10:00:00Z" } }
Webhook Delivery Monitoring
Check Delivery Status:
GET /api/v1/webhooks/wh_123456/deliveries?limit=10 # Response { "success": true, "data": [ { "id": "del_123456", "event_id": "evt_123456", "event_type": "payment.failed", "status": "delivered", "response_code": 200, "response_time": "245ms", "attempts": 1, "delivered_at": "2025-01-21T10:00:00Z" }, { "id": "del_123457", "event_id": "evt_123457", "event_type": "service.suspended", "status": "failed", "response_code": 500, "attempts": 3, "last_attempt": "2025-01-21T09:45:00Z", "next_retry": "2025-01-21T11:00:00Z" } ] }
Retry Failed Deliveries:
POST /api/v1/webhooks/wh_123456/deliveries/del_123457/retry # Response { "success": true, "data": { "delivery_id": "del_123457", "status": "retrying", "scheduled_at": "2025-01-21T10:05:00Z" } }
Integration Examples
Customer Onboarding Automation
Automated Onboarding Workflow:
// Handle service creation webhook function handleServiceCreated(event) { const service = event.data.service; const customer = event.data.customer; // 1. Send welcome email sendWelcomeEmail(customer.email, { serviceName: service.type, domain: service.domain, controlPanelUrl: service.control_panel_url }); // 2. Create onboarding tasks createOnboardingTasks(customer.id, service.id); // 3. Schedule follow-up scheduleFollowUp(customer.id, '7 days'); // 4. Update CRM updateCRM(customer.id, { status: 'active_customer', services: [service.id] }); }
Billing System Integration
Sync with Accounting System:
def handle_invoice_created(event): invoice_data = event['data']['invoice'] # Create invoice in accounting system accounting_invoice = { 'external_id': invoice_data['id'], 'customer_id': invoice_data['customer']['id'], 'amount': invoice_data['amount'], 'currency': invoice_data['currency'], 'due_date': invoice_data['due_date'], 'line_items': [ { 'description': item['description'], 'amount': item['amount'], 'service_id': item['service_id'] } for item in invoice_data['line_items'] ] } # Sync with accounting system accounting_system.create_invoice(accounting_invoice) def handle_payment_succeeded(event): payment_data = event['data']['payment'] # Mark invoice as paid in accounting system accounting_system.mark_invoice_paid( external_id=payment_data['invoice_id'], payment_date=payment_data['processed_at'], payment_method=payment_data['payment_method']['type'] )
Support System Integration
Helpdesk Integration:
function handleTicketCreated(event) { const ticket = event.data.ticket; const customer = event.data.customer; // Create ticket in external helpdesk const helpdeskTicket = { external_id: ticket.id, subject: ticket.subject, customer_email: customer.email, priority: mapPriority(ticket.priority), department: ticket.department, initial_message: event.data.initial_message.message, service_context: { service_id: ticket.service_id, service_type: getServiceType(ticket.service_id) } }; helpdesk.createTicket(helpdeskTicket); // Set up bidirectional sync setupTicketSync(ticket.id, helpdeskTicket.id); } function handleTicketUpdated(event) { const ticket = event.data.ticket; // Sync updates to external helpdesk helpdesk.updateTicket(ticket.id, { status: ticket.status, last_reply: ticket.last_reply, assigned_to: ticket.assigned_to }); }
Webhook Best Practices
Endpoint Design
Webhook Endpoint Best Practices:
- Return Quickly: Process webhooks asynchronously, return 200 immediately
- Idempotent Processing: Handle duplicate events gracefully
- Proper Error Handling: Return appropriate HTTP status codes
- Signature Verification: Always verify webhook signatures
- Logging: Log all webhook events for debugging and audit
Response Codes:
# Appropriate response codes 200 OK: Event processed successfully 400 Bad Request: Invalid payload format 401 Unauthorized: Invalid signature 500 Internal Server Error: Processing error (will trigger retry)
Security Considerations
Webhook Security Checklist:
- HTTPS Only: Only accept webhooks over HTTPS
- Signature Verification: Always verify webhook signatures
- IP Whitelisting: Optionally whitelist UncleBTech IP addresses
- Rate Limiting: Implement rate limiting on webhook endpoints
- Input Validation: Validate all webhook payload data
IP Whitelist (Optional):
# UncleBTech webhook source IPs 185.199.108.0/24 185.199.109.0/24 185.199.110.0/24 185.199.111.0/24
Error Handling and Retries
Retry Logic:
# Webhook retry schedule Attempt 1: Immediate Attempt 2: 1 minute later Attempt 3: 5 minutes later Attempt 4: 15 minutes later Attempt 5: 1 hour later Attempt 6: 6 hours later Final: 24 hours later (then marked as failed)
Handling Retry Logic:
def handle_webhook_with_retry(event): max_retries = 3 retry_count = 0 while retry_count < max_retries: try: process_event(event) return True except TemporaryError as e: retry_count += 1 if retry_count >= max_retries: log_permanent_failure(event, e) return False # Exponential backoff sleep_time = 2 ** retry_count time.sleep(sleep_time) except PermanentError as e: log_permanent_failure(event, e) return False
Webhook Reliability Tip: Design your webhook endpoints to be idempotent and handle duplicate events gracefully. UncleBTech may send the same event multiple times to ensure delivery.
Webhook Management
Managing Webhook Subscriptions
Update Event Subscriptions:
PUT /api/v1/webhooks/wh_123456 { "events": [ "service.created", "service.suspended", "service.cancelled", "payment.failed", "payment.succeeded", "invoice.created", "ticket.created", "ticket.resolved" ], "active": true }
Disable Webhook Temporarily:
PUT /api/v1/webhooks/wh_123456 { "active": false, "reason": "maintenance" }
Delete Webhook:
DELETE /api/v1/webhooks/wh_123456 # Response { "success": true, "message": "Webhook deleted successfully" }
Webhook Analytics
Delivery Statistics:
GET /api/v1/webhooks/wh_123456/analytics?period=30d # Response { "success": true, "data": { "total_deliveries": 1250, "successful_deliveries": 1238, "failed_deliveries": 12, "success_rate": "99.04%", "average_response_time": "245ms", "event_breakdown": { "payment.failed": 45, "service.created": 23, "ticket.created": 156, "invoice.created": 89 } } }
Troubleshooting Webhooks
Common Issues
Webhook Not Receiving Events:
- Check Endpoint URL: Ensure URL is accessible and returns 200
- Verify HTTPS: Webhook endpoints must use HTTPS
- Check Firewall: Ensure firewall allows incoming connections
- Validate Response: Endpoint must return 200 status code
- Check Event Filters: Verify you're subscribed to the correct events
Signature Verification Failing:
- Check Secret: Ensure webhook secret matches configuration
- Verify Algorithm: Use SHA-256 HMAC for signature verification
- Check Encoding: Ensure proper encoding of payload and secret
- Debug Signatures: Log expected vs received signatures for debugging
Debugging Tools
Webhook Testing Service:
# Use webhook testing service for development POST /api/v1/webhooks { "url": "https://webhook.site/unique-url", "events": ["payment.failed"], "active": true }
Local Development with ngrok:
# Expose local development server ngrok http 3000 # Use ngrok URL for webhook testing POST /api/v1/webhooks { "url": "https://abc123.ngrok.io/webhooks/unclebtech", "events": ["service.created"], "active": true }
Getting Webhook Support
Webhook Support Resources
Support Channels:
- Email: webhooks@unclebtech.com for webhook-specific issues
- API Documentation: Comprehensive webhook documentation and examples
- Developer Forum: Community support for webhook integration
- GitHub Examples: Sample webhook implementations in multiple languages
Common Support Requests:
- Signature Verification Issues: Help with implementing signature verification
- Event Processing: Guidance on processing specific event types
- Delivery Issues: Troubleshooting webhook delivery problems
- Integration Patterns: Best practices for webhook integrations
Information for Webhook Support
When Contacting Webhook Support:
- Webhook ID: Include webhook ID from your configuration
- Event Type: Specific event types experiencing issues
- Delivery ID: Include delivery ID for failed webhook deliveries
- Error Messages: Complete error messages from your endpoint
- Request/Response: Full request and response details
- Timeline: When the issue started and frequency
Ready to implement webhooks? Start by setting up a simple webhook endpoint and subscribing to basic events like service.created
. Use our testing tools to verify your implementation before going live.