Docs

Watchlists and webhooks

Put advertisers on a watchlist, receive signed advertiser.changes webhooks when ads start, stop or change, verify the signature and redeliver.

A watchlist is a list of advertisers we check on a schedule. After each check you receive one event per advertiser with the new, stopped and changed ads.

Create a watchlist

Shell
curl -X POST "https://api.adlibapi.com/v1/watchlists" \
  -H "X-API-Key: $ADLIB_API_KEY" -H "Content-Type: application/json" \
  -d '{"name": "Competitors",
       "advertisers": ["meta:15087023444", "google:AR18378488041124659201"],
       "webhook_url": "https://hooks.example.com/adlib",
       "interval_hours": 24}'

Find advertiser ids with resolve. The shortest interval and the number of advertisers depend on the plan:

Plan Advertisers Shortest interval
Free 1 24 h
Starter 10 24 h
Growth 50 12 h
Pro 250 6 h
Business 1,000 1 h

The first check of an advertiser is the baseline: it records the current ads and sends no event.

The event

JSON
{
  "event": "advertiser.changes",
  "watchlist_id": "0b7c6a8e-1f2d-4c3b-9a8e-5d6f7a8b9c0d",
  "advertiser_id": "meta:15087023444",
  "crawled_at": "2026-10-27T08:00:00Z",
  "summary": { "new": 2, "started": 0, "stopped": 1, "changed": 0 },
  "new": [ { "type": "discovered", "at": "...", "ad_id": "meta:...", "ad": { ... } } ],
  "started": [],
  "stopped": [ ... ],
  "changed": []
}

Every request carries X-AdLib-Event, X-AdLib-Delivery (the delivery id) and X-AdLib-Signature.

Verify the signature

X-AdLib-Signature looks like t=1793102400,v1=5f2c…. v1 is the hex HMAC-SHA256 of "<t>.<raw body>" with your webhook secret (GET /v1/webhooks/secret):

Python
import hashlib, hmac, time

def verify(secret: str, header: str, body: bytes, tolerance: int = 300) -> bool:
    parts = dict(p.split("=", 1) for p in header.split(","))
    t, sig = parts["t"], parts["v1"]
    expected = hmac.new(secret.encode(), f"{t}.".encode() + body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, sig) and abs(time.time() - int(t)) < tolerance

Use the raw body as received, before parsing the JSON. Rotate the secret with POST /v1/webhooks/secret/rotate.

Test, inspect and redeliver

  • POST /v1/webhooks/test sends a signed webhook.ping to a URL.
  • GET /v1/webhooks/deliveries lists recent deliveries with status codes; GET /v1/webhooks/deliveries/{id} includes the payload.
  • POST /v1/webhooks/deliveries/{id}/redeliver queues a delivery again.

Failed deliveries are retried. Answer with a 2xx quickly and do the work afterwards.

Without webhooks

Leave out webhook_url and poll GET /v1/advertisers/{id}/changes?since= instead. The watchlist still records every ad.