Skip to content

Endpoints

Every endpoint has full schemas in the API reference and an interactive executor in the playground. This page is a map, not a reference — use it to pick which surface you need.

10 requests per IP per hour on each of these without a key; with a valid key, your plan’s quota applies instead (rate limits).

EndpointUse
GET /v1/checkVerify a domain or licence number in one round trip. Answers with a verdict (licensed, licensed_provisional, licence_not_active, domain_not_listed, related_host_listed, name_match_only, not_found, generic_term) and a quotable verdict_detail; a host and its www. counterpart are the same site, other subdomains are not (related_hosts[]); match names the regulator (regulator_name), the licence (license_id for /v1/licenses/{id}) and where its status was published (status_source_url, status_observed_at); _meta.register / _meta.stale_jurisdictions say how fresh the registers behind it are. Dual-licensed domains carry a jurisdictions[] array, and match.verification_url links to the regulator’s own verification page where one exists (CW cert / TGC seal). See the confidence guide.
GET /v1/jurisdictionsList the seven jurisdictions we cover, with name / country / currency / licence types.
GET /v1/operators/search?q=…Search operators by display name, slug or registered (legal) name — a case-insensitive substring match. Trading names and domains are not searched; use /v1/check for a domain. Unauthenticated: capped at 3 rows.
GET /v1/health/coveragePer-jurisdiction scraper freshness — last successful scrape, age in hours, fresh vs stale flag per our SLA (UKGC / AN / TGC / IOM 24 h, MGA / CW / KH 48 h) — plus domain_coverage (methodology).
EndpointUse
POST /v1/check/batchUp to 100 domains in one request, resolved like /v1/check — verdict, verdict_detail, match, confidence on every row, but no jurisdictions[], alternatives[] or as_of; an entry we can’t look up is a per-row error with no verdict; checked_jurisdictions and _meta.stale_jurisdictions once at the top. POST only: any other method is 405 method_not_allowed with Allow: POST, key or no key. See batch.
GET /v1/jurisdictions/:codeSingle jurisdiction detail. The code is case-insensitive.
GET /v1/jurisdictions/:code/operatorsPaginated operators holding at least one licence (any status) in that jurisdiction. ?limit= 1–200 (default 50), ?offset=. Ordered by internal operator id — stable across pages, not alphabetical. The code is case-insensitive (ukgc); an unknown code is 404 jurisdiction_not_found, as on /v1/jurisdictions/:code, not an empty list.
GET /v1/operators/:slugFull operator detail — metadata + licences + domains. Each licence carries status_qualifier and license_reference_is_ours (true for KH, TGC, IOM: license_number is our reference), with issued_date / expiry_date as YYYY-MM-DD. Each domain carries verification_url (the regulator’s own page, where one exists) and verification_page_status / verification_page_read_at — what that page printed about the licence at our latest read, verbatim, and when; a word that isn’t “in force” means the page is not proof (verification_url). The slug is case-insensitive. Supports ?as_of=.
GET /v1/operators/:slug/licensesEvery licence for one operator (not paginated), with the same status_qualifier and license_reference_is_ours. Append ?include_history=true for each licence’s status-change log.
GET /v1/operators/:slug/regulatory-actionsEnforcement actions linked to one operator — fines, warnings, suspensions, revocations. ?limit= 1–100 (default 20), ?offset=, ?sort=date_desc (default) / date_asc / amount_desc / type_asc. An empty list means none is linked to this operator, not a clean record: many published actions aren’t matched to an operator yet (UKGC 107 of 107 linked, MGA 2 of 160, CW 0 of 18 on 2026-09-28). The response says so itself: _meta.note says what the list does and doesn’t mean (on an empty list: that it is not a clean record), and _meta.sources_read lists the regulator publications we read.
GET /v1/licenses/:license_idLicence by uuid. Useful when you want a pinned detail page. Carries the status’s own provenance: status_source_url, status_observed_at, last_listed_at, not_listed_since; status_qualifier; license_reference_is_ours; issued_date / expiry_date as YYYY-MM-DD. Supports ?as_of=.
GET /v1/licenses/:license_id/historyStatus-change timeline for a single licence (the whole timeline, not paginated). Each event has a note and the evidence hash (snapshot_sha256, snapshot_fetched_at) — events are never deleted. Only corrected_at means an event was withdrawn: it is set, with correction_note saying why, when we later found the event wrong. A correction_note without corrected_at is a reworded note on an event that stands.
GET /v1/export/:datasetPro and above. A whole dataset — licences, operators or domains (links) — as one CSV or NDJSON file (?format=csv|json), optionally sliced by ?jurisdiction= / ?status=; each row carries its status provenance. 10 exports a day on Pro, 100 on Business; below Pro → 402 export_requires_pro. No as_of. See export.
EndpointUse
GET /v1/watchlistSummary: { count, limit, operators } — your plan’s cap and the 50 most recently added operators.
GET /v1/watchlist/operatorsYour watched operators with a current licence status each. ?limit= 1–200 (default 50), ?offset=.
POST /v1/watchlist/operatorsAdd { "operator_slug": "…" } → 201. Already watched → 409.
DELETE /v1/watchlist/operators/:slugRemove → 204, whether or not it was on the list.
GET /v1/watchlist/eventsPoll for events (the webhook envelope, pulled). ?since= or ?cursor=, ?limit= 1–500 (default 100); a per-hour poll ceiling per plan. See watchlist.
EndpointUse
POST /v1/webhooksCreate { url, events, watchlist_only?, description? } → 201 with the signing secret, shown once.
GET /v1/webhooksList your endpoints (no secrets).
PATCH /v1/webhooks/:idChange url, events, active, watchlist_only or description.
DELETE /v1/webhooks/:idDelete the endpoint → 204. Its secrets and delivery history, pending deliveries included, go with it.
POST /v1/webhooks/:id/rotate_secretIssue a new secret; the old one keeps signing for 7 days.
GET /v1/webhooks/:id/deliveriesRecent deliveries, newest first. ?status=all / pending / delivered / failed / abandoned, ?limit= 1–200 (default 100).
POST /v1/webhooks/:id/testSend a signed test.ping now; returns { delivered, http_status, response_body, latency_ms, error }.

See webhooks.

EndpointUse
GET /v1/healthLiveness probe. 200 if postgres + redis are reachable, 503 otherwise.
GET /v1/statsHeadline counts — licence records by status, per-jurisdiction licences and last register read (with the same fresh/stale rule as /v1/health/coverage), operators, linked domains and how many carry the regulator’s own certificate or seal, brand pages, status changes read in the last 30 days, withdrawn events — each with its definition in the body (definitions). No key and no per-IP cap: one payload for everyone, recounted at most every 10 minutes. The igregulator.io homepage prints it.
GET /openapi.jsonCanonical OpenAPI 3.1 spec. Consume it, generate a client, etc.
  • Paginated lists take ?limit= + ?offset= and return total, limit, offset next to the rows:

    • GET /v1/operators/search → { q, total, limit, offset, operators, _meta }
    • GET /v1/jurisdictions/:code/operators → { jurisdiction_code, total, limit, offset, operators }
    • GET /v1/operators/:slug/regulatory-actions → { operator_slug, total, limit, offset, sort, regulatory_actions }
    • GET /v1/watchlist/operators → { total, limit, offset, operators }

    Defaults and maxima differ per endpoint — see pagination.

  • Unpaginated lists return everything in one envelope:

    • GET /v1/operators/:slug/licenses → { operator_slug, licenses }
    • GET /v1/licenses/:license_id/history → { license_id, license_number, history, _meta }
    • GET /v1/jurisdictions → { jurisdictions }; GET /v1/webhooks → { endpoints }
  • GET /v1/watchlist/events is cursor-paginated: { events, next_cursor, has_more }.

  • Detail endpoints: GET /v1/jurisdictions/:code and GET /v1/licenses/:license_id return the row itself (the licence with a _meta block). GET /v1/operators/:slug returns { operator, licenses, domains, _meta } — its licenses[] and domains[] are complete, bare arrays; /licenses returns the same licences, plus optional history.

  • Timestamps are ISO-8601 UTC (2026-04-19T12:00:00.000Z).

  • Dates — a licence’s issued_date and expiry_date, /v1/check’s match.expires_at, a regulatory action’s decision_date — are YYYY-MM-DD strings: the register publishes a day, not an instant.

  • as_of takes a YYYY-MM-DD date or an ISO-8601 datetime with a UTC offset, nothing else (point-in-time).

  • UUIDs are lowercase, hyphenated, v4.

  • Operator slugs are lowercase; /v1/operators/:slug… resolves one in any case (Flutter-UK-Limited finds flutter-uk-limited). Jurisdiction codes are uppercase and resolve in any case too.