Webhooks Implementation Summary
Overview
This document summarizes the implementation of webhook functionality for the Agent Passport Registry system, providing real-time notifications for status changes with retry logic and dead-letter handling.
Features Implemented
F1. Status Change Webhook ā FULLY IMPLEMENTED
Functionality: Real-time webhook notifications for agent status changes with robust retry logic.
Implementation:
functions/utils/webhook.ts- Core webhook utilitiesfunctions/api/admin/status.ts- Enhanced status endpoint with webhook integrationfunctions/api/admin/webhook-test.ts- Webhook testing endpoint
Key Features:
- Real-time Notifications: POST webhook on every status change
- Retry Logic: Exponential backoff with configurable attempts
- Dead Letter Handling: Failed webhooks are logged for manual processing
- Signature Verification: HMAC-SHA256 signatures for webhook security
- Timeout Protection: Configurable timeouts to prevent hanging requests
- Testing Endpoint: Dedicated endpoint for webhook validation
Architecture
How Webhooks Work with Cloudflare Pages + Next.js
The webhook system is designed to work within Cloudflare's constraints:
- Edge Execution: Webhooks are sent from Cloudflare Pages Functions (edge runtime)
- Synchronous Processing: Webhooks are sent immediately after status updates
- Retry Logic: Built-in exponential backoff for failed deliveries
- Dead Letter Logging: Failed webhooks are logged to console (extensible to external services)
Limitations and Considerations
Current Limitations:
- No Persistent Queues: Retries happen synchronously within the request
- Limited Execution Time: Cloudflare Functions have execution time limits
- No Background Workers: No persistent background processing for retries
Production Recommendations:
- For high-volume systems, consider using Cloudflare Queues or Durable Objects
- Implement external dead letter queue (e.g., database, external logging service)
- Consider using Cloudflare Workers for more advanced webhook processing
API Endpoints
POST /api/admin/status (Enhanced)
Purpose: Update agent status with webhook notifications
Webhook Integration: Automatically sends webhook if WEBHOOK_URL is configured
Response Enhancement:
{
"ok": true,
"agent_id": "string",
"status": "string",
"previous_status": "string",
"updated_at": "2024-01-15T10:30:00Z",
"message": "Agent status updated from 'active' to 'suspended'",
"webhook": {
"sent": true,
"attempts": 1,
"error": null
}
}
POST /api/admin/webhook-test
Purpose: Test webhook configuration and delivery
Request Body:
{
"webhook_url": "https://your-webhook-endpoint.com/webhook",
"webhook_secret": "optional-secret-key",
"test_agent_id": "optional-test-agent-id"
}
Response:
{
"ok": true,
"test_url": "https://your-webhook-endpoint.com/webhook",
"test_payload": {
"agent_id": "test-agent",
"status": "suspended",
"previous_status": "active",
"updated_at": "2024-01-15T10:30:00Z",
"event_type": "status_change",
"timestamp": "2024-01-15T10:30:00Z"
},
"result": {
"success": true,
"attempt": 1,
"error": null,
"response_status": 200,
"response_time_ms": 150,
"total_time_ms": 200
},
"message": "Webhook test successful"
}
Webhook Payload
Status Change Event
{
"agent_id": "agent_123",
"status": "suspended",
"previous_status": "active",
"updated_at": "2024-01-15T10:30:00Z",
"event_type": "status_change",
"timestamp": "2024-01-15T10:30:00Z"
}
Headers
Content-Type: application/json
User-Agent: Agent-Passport-Webhook/1.0
X-Webhook-Event: status_change
X-Webhook-Attempt: 1
X-Webhook-Signature: sha256=abc123... (if secret configured)
Configuration
Environment Variables
Add to wrangler.toml:
[vars]
# Webhook configuration (optional)
WEBHOOK_URL = "https://your-webhook-endpoint.com/webhook"
WEBHOOK_SECRET = "your-webhook-secret-key"
Webhook Configuration Options
interface WebhookConfig {
url: string; // Webhook endpoint URL
secret?: string; // Optional HMAC secret for signature verification
retry_attempts?: number; // Number of retry attempts (default: 3)
retry_delay_ms?: number; // Base delay between retries (default: 1000ms)
timeout_ms?: number; // Request timeout (default: 5000ms)
}
Security
Signature Verification
Webhooks include HMAC-SHA256 signatures when a secret is configured:
// Verify webhook signature
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature.replace('sha256=', '')),
Buffer.from(expectedSignature)
);
}
Best Practices
- Always verify signatures when secret is provided
- Use HTTPS for webhook endpoints
- Implement idempotency to handle duplicate webhooks
- Log webhook deliveries for debugging and monitoring
- Set appropriate timeouts to prevent hanging requests
Testing
Test Coverage
- F1.1: Webhook test endpoint returns 200 with test result
- F1.2: Webhook test unauthorized access returns 401
- F1.3: Webhook test missing URL returns 400
- F1.4: Webhook test invalid URL returns 400
- F1.5: Status change includes webhook information in response
- F1.6: Webhook payload has correct structure
- F1.7: Webhook retry logic handles failed requests
- F1.8: Webhook test with signature works
Running Tests
# Run webhook tests
pnpm run test:webhooks
# Run all tests including webhooks
pnpm run test:all
Usage Examples
Configure Webhook
# Set environment variables
export WEBHOOK_URL="https://your-app.com/webhook"
export WEBHOOK_SECRET="your-secret-key"
# Deploy with webhook configuration
wrangler pages deploy
Test Webhook Configuration
curl -X POST "https://your-domain.com/api/admin/webhook-test" \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"webhook_url": "https://your-webhook-endpoint.com/webhook",
"webhook_secret": "your-secret-key"
}'
Receive Webhook
// Express.js webhook handler example
app.post('/webhook', express.raw({type: 'application/json'}), (req, res) => {
const signature = req.headers['x-webhook-signature'];
const payload = req.body.toString();
// Verify signature
if (signature && !verifyWebhookSignature(payload, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const data = JSON.parse(payload);
// Handle status change
if (data.event_type === 'status_change') {
console.log(`Agent ${data.agent_id} status changed from ${data.previous_status} to ${data.status}`);
// Update your system accordingly
}
res.status(200).send('OK');
});
Monitoring and Debugging
Webhook Response Information
The status update endpoint returns webhook delivery information:
{
"webhook": {
"sent": true, // Whether webhook was sent
"attempts": 1, // Number of attempts made
"error": null // Error message if failed
}
}
Dead Letter Logging
Failed webhooks are logged with detailed information:
{
"timestamp": "2024-01-15T10:30:00Z",
"webhook_url": "https://your-webhook-endpoint.com/webhook",
"payload": { /* webhook payload */ },
"failure_reason": "Connection timeout",
"attempts": 3,
"response_status": null
}
Future Enhancements
- Cloudflare Queues Integration: Use Cloudflare Queues for reliable webhook delivery
- Durable Objects: Implement persistent retry logic with Durable Objects
- Webhook History: Store webhook delivery history in KV
- Multiple Webhooks: Support multiple webhook endpoints per event
- Event Filtering: Filter webhooks based on event types or conditions
- Webhook Dashboard: Admin interface for webhook management and monitoring
Implementation Status
ā F1. Status change webhook: Fully implemented with retry logic, dead-letter handling, and comprehensive testing
The webhook implementation provides a robust foundation for real-time notifications while working within Cloudflare's architectural constraints. The system is production-ready for moderate webhook volumes and can be extended for higher-scale requirements.