🔒 AhaSend Webhook Handler (Secured)

This Cloudflare Worker handles AhaSend webhook notifications and incoming email routing with enterprise-grade security.

Database Connected: All webhook events and emails are stored in D1 Database!

🔐 Security Enabled: HMAC Signature Verification & Replay Attack Protection

🟢 Database Ready - Tables Created Successfully

🔐 Security Features:

Available Endpoints:

POST /webhook

🔒 SECURED with WEBHOOK_SECRET: Receives AhaSend webhook notifications with signature verification

Supported events: message.*, suppression.created, domain.dns_error

Required Headers:

POST /incoming-email

🔒 SECURED with ROUTE_SECRET: Handles incoming email routing and processing with signature verification

Uses separate route secret for email routing security

Required Headers:

GET /attachments/{id}

📎 NEW: Download email attachments stored in R2 bucket

Secure direct access to attachment files with proper content headers

GET /stats

Returns comprehensive analytics and statistics from D1 database

Includes security metrics, signature validation stats, and R2 storage analytics

GET /health

Health check endpoint

Supported AhaSend Events:

Database Storage:

All webhook events and incoming emails are automatically stored with:

📎 R2 Object Storage:

Email attachments are efficiently stored in Cloudflare R2 with:

⚙️ Setup Instructions:

  1. Set Webhook Secret: npx wrangler secret put WEBHOOK_SECRET
  2. Set Route Secret: npx wrangler secret put ROUTE_SECRET
  3. Configure AhaSend Webhooks: URL: https://your-worker-url.workers.dev/webhook
  4. Configure AhaSend Email Routing: URL: https://your-worker-url.workers.dev/incoming-email
  5. Content Type: application/json for both endpoints
  6. Security: Use respective secrets from AhaSend dashboard (webhook vs route)

View statistics and security metrics at: https://your-worker-url.workers.dev/stats

⚠️ Security Notice: This webhook handler requires proper HMAC signature verification. Requests without valid signatures will be rejected with 401 status code. Different endpoints use different secrets: