Watchlist
A watchlist is your list of operators you care about, plus the automation layer that fires events when any of them changes. Add an operator once, get alerted whenever its licence status flips, a regulatory action lands, or an expiry date approaches — without writing polling loops against every endpoint we offer.
1. Overview
Section titled “1. Overview”Plan limits (also in pricing):
| Tier | Watchlist cap | Webhooks | Polling |
|---|---|---|---|
| Starter | 25 operators | 1 endpoint | 10 / hour |
| Pro | 250 operators | 5 endpoints | 60 / hour |
| Business | unlimited | 20 endpoints | 600 / hour |
| Enterprise | unlimited | unlimited | unlimited |
Webhooks are the primary alert channel. Polling exists for agents that can’t accept inbound HTTP (corporate networks, air-gapped analytics, local dev) and as a backfill mechanism during webhook outages.
2. Managing the watchlist
Section titled “2. Managing the watchlist”Dashboard
Section titled “Dashboard”Sign in and open app.igregulator.io/watchlist. Type an operator name — we typeahead against every operator slug we know about. Click to add. Click remove to drop.
Same surface via bearer token:
# Current watchlist + count + plan cap (the 50 most recently added)curl -H "Authorization: Bearer igk_..." \ https://api.igregulator.io/v1/watchlist
# Add an operator by slug (lowercase, hyphens) — 201, or 409 if already watchedcurl -X POST -H "Authorization: Bearer igk_..." \ -H "Content-Type: application/json" \ -d '{"operator_slug":"888-uk-limited"}' \ https://api.igregulator.io/v1/watchlist/operators
# Remove (idempotent — 204 either way)curl -X DELETE -H "Authorization: Bearer igk_..." \ https://api.igregulator.io/v1/watchlist/operators/888-uk-limited
# Paginated listing with current licence status per operatorcurl -H "Authorization: Bearer igk_..." \ "https://api.igregulator.io/v1/watchlist/operators?limit=50&offset=0"Discover slugs with GET /v1/operators/search?q=<name>.
3. Receiving events
Section titled “3. Receiving events”Webhook push (primary)
Section titled “Webhook push (primary)”Create an endpoint with the watchlist_only: true flag (default).
Deliveries fire for operators in your watchlist only — no
firehose, no noise. Events covered:
license.status_changedlicense.expiring_30d/_60d/_90dlicense.expiredlicense.issued(only if you were watching the operator when the new licence was detected)regulatory_action.added
See /docs/webhooks for the signing + retry protocol. Quickstart in 2 minutes: /docs/webhooks/quickstart.
Polling (fallback)
Section titled “Polling (fallback)”GET /v1/watchlist/events returns the same envelope events,
pulled. Cursor-paginated so you don’t re-process events between
runs. Rate-limited per plan (see §1). Every response carries
X-Poll-RateLimit-Limit, -Remaining, -Reset, -Window, and a
X-Poll-Recommended-Interval hint in seconds (on a plan with no poll
ceiling: X-Poll-RateLimit-Limit: unlimited, -Reset and the interval
only). limit is 1–500 (default 100); with neither since nor
cursor, you get the last hour.
You don’t need a webhook endpoint to poll: you get every event above for
the operators on your watchlist, plus anything that was queued for your
webhook endpoints (such as coverage.*, if an endpoint subscribes to it).
# Bootstrap: up to 30 days back (matches event retention; GNU date)curl -H "Authorization: Bearer igk_..." \ "https://api.igregulator.io/v1/watchlist/events?since=$(date -u -d '29 days ago' +%FT%TZ)&limit=100"
# Steady state: use the next_cursor from the previous responsecurl -H "Authorization: Bearer igk_..." \ "https://api.igregulator.io/v1/watchlist/events?cursor=eyJ0cy...&limit=100"Response:
{ "events": [ { "event": "license.status_changed", "event_id": "evt_...", "api_version": "2026-04-20", "timestamp": "...", "livemode": true, "data": { ... } } ], "next_cursor": "eyJ0c...", "has_more": true}events payloads are identical to the webhook envelope
(minus the signature — polling authenticates via your API key,
not per-delivery HMAC). Dedupe on event_id whether you’re
receiving via webhook or poll; you’ll use the same key for both.
Polling best practices
Section titled “Polling best practices”- Persist the cursor. Save
next_cursorafter each successful batch to your own DB / disk. On restart, resume from it. - Dedupe on
event_id. Crash windows can cause you to re-process the last batch; same dedupe path you’d use for webhooks covers this. - Respect
X-Poll-Recommended-Interval. It’sceil(3600 / limit)— sleeping that long between polls guarantees you never hit the hour ceiling. Starter = 360 s, Pro = 60 s, Business = 6 s. - On 429, wait until
details.reset_at. Don’t exponential-backoff — the window resets deterministically on the hour boundary. See /docs/rate-limits. - Hybrid webhooks + polling is the resilient pattern. Webhooks
for low latency, polling for the few-hour windows where your
receiver was down and deliveries abandoned. Both ship the same
event_id, so dedupe makes double-processing a no-op. Example in /docs/webhooks § Pattern C.
since= is capped at 30 days
Section titled “since= is capped at 30 days”That matches our event retention. Older values fail with
400 invalid_query and details.reason: "since_exceeds_retention_window".
Rare in practice — the first call uses since, every subsequent call
uses the cursor.
4. Plan limits in detail
Section titled “4. Plan limits in detail”Once your watchlist is at its cap, the next POST /v1/watchlist/operators returns 403 quota_exceeded with
details.reason: "watchlist_quota_exceeded" and the current count +
cap (current_usage, limit). Remove an operator, or email
founder@igregulator.io if you need a higher cap.
Polling ceiling hits return 429 rate_limited with
details.reason: "watchlist_events_poll_limit" and a concrete
details.reset_at timestamp — not exponential backoff, deterministic
hour-boundary reset. Webhooks do not count against this limit. Error
reference: errors.
5. What events don’t fire for watched operators
Section titled “5. What events don’t fire for watched operators”coverage.degraded/coverage.restored— these are jurisdiction-level, not operator-level. They’re emitted regardless of watchlist membership; anyone subscribed to the event type gets them.webhook.endpoint_degraded— reserved for a self-notification about your own endpoints; not sent yet. It would ignore the watchlist.
6. Troubleshooting
Section titled “6. Troubleshooting”- No events arriving — your watchlist may be empty, your webhook
endpoint may not subscribe to the event types, or the operators you
track haven’t had any changes this month. Run
GET /v1/watchlist/eventswith asinceup to 30 days back to see what fired for your watchlist. - Too many events — too-broad subscription. Each of the three expiry windows fires separately; narrow to the one(s) you act on.
- Events for operators I don’t watch — your webhook might
have
watchlist_only: false. CheckPATCH /v1/webhooks/:idwith{ "watchlist_only": true }.
Related: /docs/webhooks, /docs/rate-limits.