Webhooks
Receive real-time notifications when events happen in your newsletter.
Setting Up Webhooks
Via Dashboard
- Go to your newsletter → Settings → Webhooks
- Click "Add Webhook"
- Enter your endpoint URL
- Select events to subscribe to
- Save the webhook
Via API
POST /api/v1/webhook_subscriptions
{
"url": "https://your-app.com/webhooks/dailydraft",
"events": ["subscription.created", "issue.sent"]
}
Available Events
| Event | Description |
|---|---|
subscription.created |
New subscriber added |
subscription.unsubscribed |
Subscriber unsubscribed |
subscription.bounced |
Email bounced (hard bounce) |
issue.sent |
Issue finished sending |
email.opened |
Subscriber opened email |
email.clicked |
Subscriber clicked a link |
Webhook Payload
All webhooks follow this format:
{
"event": "subscription.created",
"timestamp": "2025-01-10T12:00:00Z",
"newsletter_id": 123,
"data": {
// Event-specific data
}
}
Event Payloads
subscription.created
{
"event": "subscription.created",
"timestamp": "2025-01-10T12:00:00Z",
"newsletter_id": 123,
"data": {
"subscription_id": 456,
"email": "[email protected]",
"name": "New User",
"tags": [],
"source": "api"
}
}
subscription.unsubscribed
{
"event": "subscription.unsubscribed",
"timestamp": "2025-01-10T12:00:00Z",
"newsletter_id": 123,
"data": {
"subscription_id": 456,
"email": "[email protected]",
"reason": "user_request"
}
}
issue.sent
{
"event": "issue.sent",
"timestamp": "2025-01-10T12:00:00Z",
"newsletter_id": 123,
"data": {
"issue_id": 42,
"subject": "Weekly Newsletter #42",
"total_sent": 1500,
"sent_at": "2025-01-10T09:00:00Z"
}
}
email.opened
{
"event": "email.opened",
"timestamp": "2025-01-10T12:05:00Z",
"newsletter_id": 123,
"data": {
"issue_id": 42,
"subscription_id": 456,
"email": "[email protected]",
"opened_at": "2025-01-10T12:05:00Z"
}
}
email.clicked
{
"event": "email.clicked",
"timestamp": "2025-01-10T12:10:00Z",
"newsletter_id": 123,
"data": {
"issue_id": 42,
"subscription_id": 456,
"email": "[email protected]",
"link_url": "https://example.com/article",
"clicked_at": "2025-01-10T12:10:00Z"
}
}
Webhook Security
Signature Verification
Each webhook includes a signature header for verification:
X-DailyDraft-Signature: sha256=abc123...
Verify the signature:
require 'openssl'
def verify_webhook(payload, signature, secret)
expected = "sha256=" + OpenSSL::HMAC.hexdigest(
'sha256',
secret,
payload
)
Rack::Utils.secure_compare(expected, signature)
end
IP Allowlisting
DailyDraft webhooks come from these IP addresses:
34.102.136.0/24
35.190.0.0/24
Retry Policy
Failed webhooks are retried with exponential backoff:
- 1st retry: 1 minute
- 2nd retry: 5 minutes
- 3rd retry: 30 minutes
- 4th retry: 2 hours
- 5th retry: 24 hours
After 5 failed attempts, the webhook is marked as failed.
Success Response
Return a 2xx status code to acknowledge receipt:
HTTP/1.1 200 OK
{"received": true}
Managing Webhooks via API
List Webhooks
GET /api/v1/webhook_subscriptions
Create Webhook
POST /api/v1/webhook_subscriptions
{
"url": "https://your-app.com/webhooks",
"events": ["subscription.created", "subscription.unsubscribed"]
}
Delete Webhook
DELETE /api/v1/webhook_subscriptions/:id
Testing Webhooks
Use the dashboard to send test events:
- Go to Settings → Webhooks
- Click "Test" on any webhook
- Select an event type
- Click "Send Test"
Or use a tool like webhook.site to inspect payloads.
Still need help?
Can't find what you're looking for? Chat with our AI assistant or create a support ticket.
Sign in to get support