Receive real-time notifications on your server when something happens in AdFlow.
How it works
- Register an HTTPS URL + secret at /webhook_endpoints/new
- Select which events you want to receive
- When the event occurs, AdFlow POSTs to your URL with a JSON payload
- Your server validates the signature and processes the payload
Set up an endpoint
In /webhook_endpoints/new:
- URL: must be HTTPS and publicly accessible. No
localhostsupport in production. - Secret: random string (minimum 32 characters). Use
openssl rand -hex 32to generate. - Events: select the types you want. Recommended start:
campaign.*andwebhook.failed.
After saving, click Send test event to confirm your URL is receiving.
Available events
| Event | When it fires |
|---|---|
campaign.enqueued | Campaign sent for publishing |
campaign.paused | Campaign manually paused |
campaign.resumed | Campaign resumed |
profile.created | New profile linked |
profile.blocked | Profile flagged as blocked |
proxy.rotated | IP rotated on a profile |
webhook.delivered | Webhook delivered successfully |
webhook.failed | Failed after 3 attempts |
member.invited | New member invited |
member.removed | Member removed |
Payload format
{
"id": "evt_abc123",
"event": "campaign.enqueued",
"occurred_at": "2026-05-03T10:00:00Z",
"organization_id": "org_xyz789",
"data": {
"resource_type": "campaign",
"resource_id": "cmp_def456",
"changes": {}
}
}
Validate the HMAC signature
Every POST includes the X-AdFlow-Signature header: HMAC-SHA256 of the body using your secret. Always validate before processing.
# Ruby
secret = ENV['ADFLOW_WEBHOOK_SECRET']
expected = OpenSSL::HMAC.hexdigest('SHA256', secret, request.raw_post)
received = request.headers['X-AdFlow-Signature']
halt 401 unless ActiveSupport::SecurityUtils.secure_compare(received, expected)
# Python
import hmac, hashlib, os
secret = os.environ['ADFLOW_WEBHOOK_SECRET'].encode()
expected = hmac.new(secret, request.body, hashlib.sha256).hexdigest()
received = request.headers.get('X-AdFlow-Signature', '')
if not hmac.compare_digest(expected, received):
abort(401)
Retry policy
If your server returns an error (4xx, 5xx) or doesn’t respond within 10s, AdFlow retries:
| Attempt | Delay |
|---|---|
| 1st | 30 seconds |
| 2nd | 1 minute |
| 3rd | 5 minutes |
After 3 consecutive failures, logs webhook.failed in the audit log and stops retrying for that event.
Your endpoint should respond 200 OK even if you decide not to process the event — this prevents AdFlow from re-sending.