Skip to main content

Webhooks API

Create and manage webhook subscriptions to receive real-time notifications when events occur in CronDB.

API Playground

tip

Try this endpoint live in the API Playground.

Requires Starter plan or above

The free plan does not include webhook access.

Endpoints

MethodEndpointDescription
GET/v1/webhooksList your webhooks
POST/v1/webhooksCreate a webhook
PUT/v1/webhooks/{id}Update a webhook
DELETE/v1/webhooks/{id}Delete a webhook
GET/v1/webhooks/deliveriesList all deliveries
GET/v1/webhooks/{id}/deliveriesList deliveries for a webhook
POST/v1/webhooks/{id}/deliveries/{delivery_id}/retryRetry a failed delivery

Plan Limits

PlanMax Webhooks
Free0
Starter2
Pro10
Enterprise50

Create Webhook

POST /v1/webhooks
ParameterTypeRequiredDescription
urlstringYesHTTPS endpoint URL
eventsstring[]YesEvent types to subscribe to (max 20)
curl -X POST \
-H "Authorization: Bearer cdb_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"url": "https://yourapp.com/webhooks/crondb",
"events": [
"alert.domain_matched",
"watchlist.domain_changed",
"sequence.email_replied"
]
}' \
"https://api.crondb.com/v1/webhooks"
import requests

response = requests.post(
"https://api.crondb.com/v1/webhooks",
headers={"Authorization": "Bearer cdb_your_api_key_here"},
json={
"url": "https://yourapp.com/webhooks/crondb",
"events": ["alert.domain_matched", "sequence.email_replied"],
},
)
webhook = response.json()
print(f"Webhook ID: {webhook['id']}, Secret: {webhook['secret']}")

Response (201)

{
"id": 1,
"url": "https://yourapp.com/webhooks/crondb",
"events": ["alert.domain_matched", "sequence.email_replied"],
"secret": "whsec_abc123...",
"is_active": true,
"created_at": "2026-03-22T10:00:00Z"
}
Save the Secret

The webhook secret is shown only once. Use it to verify webhook signatures.


Available Events

EventTrigger
search.alertSaved search finds new matches
keyword.matchTracked keyword detected
audience.updatedAudience has new matching domains
domain.new_matchNew domain matches your criteria
domain.enrichedDomain enrichment completed
intent.high_detectedHigh-intent domain detected
watchlist.changeWatched domain data changed
list.item_addedDomain added to a lead list
list.status_changedList item funnel status changed
export.completedExport job finished
sequence.repliedSequence email received a reply
sequence.bouncedSequence email bounced
sequence.openedSequence email was opened
sequence.clickedSequence email link clicked
sequence.completedContact finished all sequence steps
sequence.unsubscribedContact unsubscribed
*Subscribe to all events

List Deliveries

GET /v1/webhooks/deliveries

View delivery history with success/failure stats.

ParameterTypeDefaultDescription
webhook_idintegernullFilter by webhook
event_typestringnullFilter by event
limitinteger100Max results (max 200)

Response

{
"deliveries": [
{
"id": 42,
"webhook_id": 1,
"event_type": "alert.domain_matched",
"url": "https://yourapp.com/webhooks/crondb",
"status": "delivered",
"status_code": 200,
"attempt": 1,
"created_at": "2026-03-20T14:30:00Z"
}
],
"summary": {
"total_delivered": 156,
"total_failed": 3,
"success_rate": 98.1,
"avg_response_ms": 245
}
}

Retry Failed Delivery

POST /v1/webhooks/{webhook_id}/deliveries/{delivery_id}/retry

Re-attempt delivery for a failed webhook. CronDB uses exponential backoff for automatic retries, but you can manually trigger a retry.

curl -X POST \
-H "Authorization: Bearer cdb_your_api_key_here" \
"https://api.crondb.com/v1/webhooks/1/deliveries/42/retry"

Webhook Payload Format

All webhook payloads follow this structure:

{
"event": "alert.domain_matched",
"timestamp": "2026-03-20T14:30:00Z",
"webhook_id": 1,
"data": { ... }
}

Headers included with each delivery:

HeaderDescription
Content-Typeapplication/json
X-CronDB-EventEvent type
X-CronDB-SignatureHMAC-SHA256 signature
X-CronDB-Delivery-IDUnique delivery ID

Verifying Signatures

Verify webhook authenticity using the HMAC-SHA256 signature:

import hmac
import hashlib

def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode(),
payload,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(f"sha256={expected}", signature)
const crypto = require("crypto");

function verifyWebhook(payload, signature, secret) {
const expected = crypto
.createHmac("sha256", secret)
.update(payload)
.digest("hex");
return signature === `sha256=${expected}`;
}

Next Steps