Skip to content

All licences for an operator

GET
/v1/operators/{slug}/licenses

Every licence record we hold for the operator, in every status, sorted by jurisdiction_code, license_number — the whole list in one response (not paginated). Append ?include_history=true to embed the status-change timeline under each licence; omit for the slimmer detail view. Agents that want a cross-jurisdiction compliance view should call this instead of the single-licence endpoint.

slug
required
string

The operator’s slug, from /v1/operators/search or a /v1/check match’s operator_slug. Case-insensitive.

include_history
boolean

When true, each licence includes its status-change history[].

All of the operator’s licences.

object
operator_slug
required
string
licenses
required
Array
object
id
string format: uuid
license_number

The licence number as the regulator’s register prints it — except for KH (Kahnawake), TGC (Tobique) and IOM (Isle of Man), whose registers publish none. For those three it is an iGregulator reference we assign: KH/IG/<slug> or KH/CSPA/<slug>, TGC/B2C/<slug> or TGC/B2B/<slug>, IOM/OGRA/<company key>. The reference is stable and /v1/check?license_number= accepts it, but no regulator issued it: do not present it to a user as the licence number.

string
license_reference_is_ours

true when license_number is an iGregulator reference, not a number the regulator published — every KH, TGC and IOM licence (their registers publish none). Never present such a reference to a user as the licence number. Same field as on a /v1/check match.

boolean
jurisdiction_code

Jurisdiction code — UKGC, MGA, CW (Curaçao), KH (Kahnawake), AN (Anjouan), TGC (Tobique) or IOM (Isle of Man). GET /v1/jurisdictions lists them with names and licence types.

string
status

Canonical licence status. Only active means “licensed right now”. Every other value is “not a pass” — but three of them are not enforcement decisions, and a rule that lumps them in with revoked publishes a claim about a real business that no regulator made.

not_in_register — the regulator’s public register no longer lists this licence, since not_listed_since. An observation about the register, not a decision by the regulator: licences drop off because they expired, were surrendered, were renumbered, or the page had a bad day. Nobody published a reason and we do not invent one. It is not a revocation. (Until 2026-09-17 we reported this as revoked; that was wrong, every affected record has been corrected, and its history says so.)

surrendered — the operator gave the licence up (UKGC publishes “Surrendered”; Kahnawake “voluntary termination … in good standing”; the Isle of Man GSC, on its Former Licence Holders list, “Surrendered”). Also not an enforcement decision: nobody took it away. 627 UKGC licences carried revoked for this until 2026-09-17.

unknown — the register lists this licence and published a status we could not classify: a new phrase, a reworded sentence, a typo. We do not guess: two of our scrapers used to default an unreadable status to active, and that is precisely the bug this value exists to make impossible. Read upstream_status for the regulator’s own words.

None of these is a synonym for any other:

  • None of them means “not licensed” in the enforcement sense. Do not present them as such.
  • None of them means “probably fine”. Do not treat them as a pass.

A rule like if (status === "revoked") block() will silently let surrendered, not_in_register and unknown through. If your flow makes an automated allow/deny decision, approve only on active and escalate everything else to a human.

revoked and suspended are only ever set from a regulator publication we actually read — an enforcement register, a revoked-licences page, an explicit status column — never from a licence disappearing. (The Isle of Man’s Former Licence Holders list says Cancelled for a licence the Commission cancelled under s.13 of the Online Gambling Regulation Act 2001; we store that as revoked.)

string
Allowed values: active suspended revoked expired pending unknown surrendered not_in_register
status_qualifier

When status is right but not the whole truth; same field as on a /v1/check match. provisional_under_assessment: a Curaçao licence the CGA register reads as “Assessment in progress” past its stated term — active, because the CGA keeps such a licence in force until it decides, but a decision is outstanding and expiry_date may already be past. Derived from the regulator’s wording on every read. null otherwise.

string | null
Allowed values: provisional_under_assessment
license_types

Multi-valued type vocabulary, sourced verbatim from the regulator. Stable values per jurisdiction (audited 2026-04-21):

  • UKGC — Remote, Non-Remote, Ancillary Remote
  • MGA — Type 1, Type 2, Type 3, Type 4, B2B, B2C
  • CW (Curaçao) — B2C, B2B
  • KH (Kahnawake) — Interactive Gaming Permit, CSPA
  • AN (Anjouan) — B2C, B2B, White Labeling
  • TGC (Tobique) — B2C, B2B
  • IOM (Isle of Man) — Full, Network Services, Software Supply (the Online Gambling Regulation Act 2001 licence types, as the register writes them)

Add a new value to your client mapping when a regulator publishes one — we don’t reject unknown strings. Multi-jurisdiction operators carry one license row per jurisdiction, so this array is per-licence.

Array<string>
license_type_raw
string
not_listed_since

When the regulator’s public register stopped listing this licence (first pull that missed it) — the date behind status: not_in_register. null = listed in the most recent pull. An observation about the register, not a regulator decision: it does not mean revoked. A licence can briefly carry this while still active (one missed pull, inside our grace window).

string | null format: date-time
license_category

Cross-jurisdiction harmonised category — derived by @igregulator/normalizer so a multi-regulator query can group by it. UKGC Remote, MGA Type 1/2, CW B2C, IOM Full map to remote; UKGC Non-Remote to non-remote; IOM Network Services and Software Supply to ancillary; etc.

string
Allowed values: remote non-remote ancillary permit other
issued_date

As the register gives it: a calendar date, YYYY-MM-DD (no time, no zone).

string | null format: date
expiry_date

As the register gives it: a calendar date, YYYY-MM-DD. A past date next to status: active is normal for a provisional_under_assessment licence (see status_qualifier).

string | null format: date
last_verified_at

When our scraper last reconciled this record against its register.

string format: date-time
source_url

The register this licence is listed in. Not necessarily where its current status came from — cite status_source_url for that.

string format: uri
status_source_url

The page that published THIS status — provenance is per status, not per licence. Often not the register in source_url: a Curaçao or Anjouan revocation comes from the regulator’s enforcement / revoked-licences page, a Kahnawake termination from its advisory notice, an MGA status from the licensee’s verification page. Cite this, not source_url, when you explain a non-active status. null for a status set before we tracked provenance.

string | null format: uri
status_observed_at

The latest read of status_source_url that still said this status. When the status CHANGED is in the licence history (/v1/licenses/{license_id}/history), not here. null when status_source_url is.

string | null format: date-time
last_listed_at

The last time we saw this licence listed in its register. With not_listed_since it reads “no longer listed since X; last seen listed on Y”. null when we have no such read on record.

string | null format: date-time
raw_data

Scraper-specific fields captured verbatim from the upstream register (e.g. UKGC activity categories, CGA company-type flags). Not a stable integration surface. Keys here are added, renamed, or removed without a deprecation window when a scraper is updated — they do not carry the 90-day Sunset guarantee that top-level fields do. Use license_types, license_category, status, issued_date, expiry_date for stable compliance logic; read raw_data only for diagnostic / investigative purposes.

object
key
additional properties
any
as_of

Point-in-time status, present only when ?as_of= was supplied. Answers ONLY within the observation window: we never extrapolate a status before tracking_since (the first time we recorded the licence).

object
as_of
required

The resolved instant (UTC). A bare YYYY-MM-DD resolves to the end of that day; today’s date resolves to now.

string format: date-time
knowledge
required

observed: the date is within our window, status is known. corrected: the event in effect on that date is one we later WITHDREW (see correction) — status is null. We do not report the withdrawn status, and we do not fall back to the one before it either: neither is something we observed for that date. before_tracking: the date predates when we started watching — status is null, NOT a guess. no_such_license: we have no history for this licence. no_license_resolved: a fuzzy /v1/check match with no specific licence to time-travel.

string
Allowed values: observed corrected before_tracking no_such_license no_license_resolved
status_as_of
required

Licence status as of the date, or null when not observed.

string | null
established_by
required

The history transition in effect at the date — when this status was last confirmed relative to the query.

object
changed_at
string format: date-time
new_status
string
change_type
string
source_url
string
correction

Present only when knowledge is corrected. The event that was in effect at the date and that we later withdrew. withdrawn_status is what we USED to say — never quote it as the status.

object
changed_at
string format: date-time
withdrawn_status
string
corrected_at
string format: date-time
note
string | null
tracking_since
required

Lower bound of our knowledge — when we first observed this licence.

string | null format: date-time
history

Only with ?include_history=true: every event for this licence, most recent first.

Array
object
id
string format: uuid
changed_at
string format: date-time
previous_status
One of:

Canonical licence status. Only active means “licensed right now”. Every other value is “not a pass” — but three of them are not enforcement decisions, and a rule that lumps them in with revoked publishes a claim about a real business that no regulator made.

not_in_register — the regulator’s public register no longer lists this licence, since not_listed_since. An observation about the register, not a decision by the regulator: licences drop off because they expired, were surrendered, were renumbered, or the page had a bad day. Nobody published a reason and we do not invent one. It is not a revocation. (Until 2026-09-17 we reported this as revoked; that was wrong, every affected record has been corrected, and its history says so.)

surrendered — the operator gave the licence up (UKGC publishes “Surrendered”; Kahnawake “voluntary termination … in good standing”; the Isle of Man GSC, on its Former Licence Holders list, “Surrendered”). Also not an enforcement decision: nobody took it away. 627 UKGC licences carried revoked for this until 2026-09-17.

unknown — the register lists this licence and published a status we could not classify: a new phrase, a reworded sentence, a typo. We do not guess: two of our scrapers used to default an unreadable status to active, and that is precisely the bug this value exists to make impossible. Read upstream_status for the regulator’s own words.

None of these is a synonym for any other:

  • None of them means “not licensed” in the enforcement sense. Do not present them as such.
  • None of them means “probably fine”. Do not treat them as a pass.

A rule like if (status === "revoked") block() will silently let surrendered, not_in_register and unknown through. If your flow makes an automated allow/deny decision, approve only on active and escalate everything else to a human.

revoked and suspended are only ever set from a regulator publication we actually read — an enforcement register, a revoked-licences page, an explicit status column — never from a licence disappearing. (The Isle of Man’s Former Licence Holders list says Cancelled for a licence the Commission cancelled under s.13 of the Online Gambling Regulation Act 2001; we store that as revoked.)

string
Allowed values: active suspended revoked expired pending unknown surrendered not_in_register
new_status

Canonical licence status. Only active means “licensed right now”. Every other value is “not a pass” — but three of them are not enforcement decisions, and a rule that lumps them in with revoked publishes a claim about a real business that no regulator made.

not_in_register — the regulator’s public register no longer lists this licence, since not_listed_since. An observation about the register, not a decision by the regulator: licences drop off because they expired, were surrendered, were renumbered, or the page had a bad day. Nobody published a reason and we do not invent one. It is not a revocation. (Until 2026-09-17 we reported this as revoked; that was wrong, every affected record has been corrected, and its history says so.)

surrendered — the operator gave the licence up (UKGC publishes “Surrendered”; Kahnawake “voluntary termination … in good standing”; the Isle of Man GSC, on its Former Licence Holders list, “Surrendered”). Also not an enforcement decision: nobody took it away. 627 UKGC licences carried revoked for this until 2026-09-17.

unknown — the register lists this licence and published a status we could not classify: a new phrase, a reworded sentence, a typo. We do not guess: two of our scrapers used to default an unreadable status to active, and that is precisely the bug this value exists to make impossible. Read upstream_status for the regulator’s own words.

None of these is a synonym for any other:

  • None of them means “not licensed” in the enforcement sense. Do not present them as such.
  • None of them means “probably fine”. Do not treat them as a pass.

A rule like if (status === "revoked") block() will silently let surrendered, not_in_register and unknown through. If your flow makes an automated allow/deny decision, approve only on active and escalate everything else to a human.

revoked and suspended are only ever set from a regulator publication we actually read — an enforcement register, a revoked-licences page, an explicit status column — never from a licence disappearing. (The Isle of Man’s Former Licence Holders list says Cancelled for a licence the Commission cancelled under s.13 of the Online Gambling Regulation Act 2001; we store that as revoked.)

string
Allowed values: active suspended revoked expired pending unknown surrendered not_in_register
change_type
string
Allowed values: created status_change renewed revoked data_update
source_url
string
detected_by
string
note

What we observed, in words — e.g. “No longer listed in the public register since 2026-08-04.”

string | null
snapshot_sha256

SHA-256 of the exact payload this change was read from, stored on our side. null for events recorded before 2026-09-17 and for runs whose snapshot could not be filed. Ask support for that payload by hash if you need to audit a claim — a hash you can check against your own copy of the regulator’s page is the point.

string | null
snapshot_fetched_at

When that payload was fetched from the regulator.

string | null format: date-time
corrected_at

Set when a later review found this event asserted something we had not read from the regulator. The event is kept for the audit trail; treat it as withdrawn and read correction_note.

string | null format: date-time
correction_note
string | null
license_id
string format: uuid

Invalid query / parameters.

object
error
required

Human-readable error summary.

string
code
required

HTTP-status-level class. Stable enum; branch on details.reason for finer control. Current values: invalid_query, invalid_slug, invalid_license_id, invalid_jurisdiction_code, invalid_pagination, not_found, auth_required, auth_invalid, auth_revoked, payment_required, quota_exceeded, rate_limited, server_error.

string
details
required
object
reason
required

Machine-readable refinement of the top-level code. Stable vocabulary; branch on this in clients. Examples: invalid_input, missing_required_parameter, conflicting_parameters, operator_not_found, license_not_found, jurisdiction_not_found, route_not_found, api_key_missing, malformed_header, api_key_invalid, api_key_revoked, quota_exceeded, export_requires_pro, export_daily_limit_reached, as_of_not_supported, dataset_not_found, internal_error.

string
field

Present only when the error maps to a specific request input field (query param, path param, body key). Omitted for errors that aren’t field-scoped (e.g. rate_limited, auth_revoked).

string
suggestion

Optional human-readable / agent-actionable hint describing how to resolve the error.

string
{
"reason": "api_key_revoked",
"suggestion": "Generate a new API key at https://app.igregulator.io/api-keys. Revoked keys cannot be restored."
}
{
"error": "API key has been revoked",
"code": "auth_revoked",
"details": {
"reason": "api_key_revoked",
"suggestion": "Generate a new API key at https://app.igregulator.io/api-keys. Revoked keys cannot be restored."
}
}

Missing / malformed / revoked API key.

object
error
required

Human-readable error summary.

string
code
required

HTTP-status-level class. Stable enum; branch on details.reason for finer control. Current values: invalid_query, invalid_slug, invalid_license_id, invalid_jurisdiction_code, invalid_pagination, not_found, auth_required, auth_invalid, auth_revoked, payment_required, quota_exceeded, rate_limited, server_error.

string
details
required
object
reason
required

Machine-readable refinement of the top-level code. Stable vocabulary; branch on this in clients. Examples: invalid_input, missing_required_parameter, conflicting_parameters, operator_not_found, license_not_found, jurisdiction_not_found, route_not_found, api_key_missing, malformed_header, api_key_invalid, api_key_revoked, quota_exceeded, export_requires_pro, export_daily_limit_reached, as_of_not_supported, dataset_not_found, internal_error.

string
field

Present only when the error maps to a specific request input field (query param, path param, body key). Omitted for errors that aren’t field-scoped (e.g. rate_limited, auth_revoked).

string
suggestion

Optional human-readable / agent-actionable hint describing how to resolve the error.

string
{
"reason": "api_key_revoked",
"suggestion": "Generate a new API key at https://app.igregulator.io/api-keys. Revoked keys cannot be restored."
}
{
"error": "API key has been revoked",
"code": "auth_revoked",
"details": {
"reason": "api_key_revoked",
"suggestion": "Generate a new API key at https://app.igregulator.io/api-keys. Revoked keys cannot be restored."
}
}

The key’s plan does not cover this request — canceled or no plan (plan_inactive), or a legacy trial key calling anything but /v1/check and the other endpoints that work without a key (endpoint_requires_paid_plan), or a plan below Pro asking for an export (export_requires_pro). Paid plans are not on sale yet: email founder@igregulator.io and we will sort it out.

object
error
required

Human-readable error summary.

string
code
required

HTTP-status-level class. Stable enum; branch on details.reason for finer control. Current values: invalid_query, invalid_slug, invalid_license_id, invalid_jurisdiction_code, invalid_pagination, not_found, auth_required, auth_invalid, auth_revoked, payment_required, quota_exceeded, rate_limited, server_error.

string
details
required
object
reason
required

Machine-readable refinement of the top-level code. Stable vocabulary; branch on this in clients. Examples: invalid_input, missing_required_parameter, conflicting_parameters, operator_not_found, license_not_found, jurisdiction_not_found, route_not_found, api_key_missing, malformed_header, api_key_invalid, api_key_revoked, quota_exceeded, export_requires_pro, export_daily_limit_reached, as_of_not_supported, dataset_not_found, internal_error.

string
field

Present only when the error maps to a specific request input field (query param, path param, body key). Omitted for errors that aren’t field-scoped (e.g. rate_limited, auth_revoked).

string
suggestion

Optional human-readable / agent-actionable hint describing how to resolve the error.

string
{
"reason": "api_key_revoked",
"suggestion": "Generate a new API key at https://app.igregulator.io/api-keys. Revoked keys cannot be restored."
}
{
"error": "API key has been revoked",
"code": "auth_revoked",
"details": {
"reason": "api_key_revoked",
"suggestion": "Generate a new API key at https://app.igregulator.io/api-keys. Revoked keys cannot be restored."
}
}

No row matched.

object
error
required

Human-readable error summary.

string
code
required

HTTP-status-level class. Stable enum; branch on details.reason for finer control. Current values: invalid_query, invalid_slug, invalid_license_id, invalid_jurisdiction_code, invalid_pagination, not_found, auth_required, auth_invalid, auth_revoked, payment_required, quota_exceeded, rate_limited, server_error.

string
details
required
object
reason
required

Machine-readable refinement of the top-level code. Stable vocabulary; branch on this in clients. Examples: invalid_input, missing_required_parameter, conflicting_parameters, operator_not_found, license_not_found, jurisdiction_not_found, route_not_found, api_key_missing, malformed_header, api_key_invalid, api_key_revoked, quota_exceeded, export_requires_pro, export_daily_limit_reached, as_of_not_supported, dataset_not_found, internal_error.

string
field

Present only when the error maps to a specific request input field (query param, path param, body key). Omitted for errors that aren’t field-scoped (e.g. rate_limited, auth_revoked).

string
suggestion

Optional human-readable / agent-actionable hint describing how to resolve the error.

string
{
"reason": "api_key_revoked",
"suggestion": "Generate a new API key at https://app.igregulator.io/api-keys. Revoked keys cannot be restored."
}
{
"error": "API key has been revoked",
"code": "auth_revoked",
"details": {
"reason": "api_key_revoked",
"suggestion": "Generate a new API key at https://app.igregulator.io/api-keys. Revoked keys cannot be restored."
}
}

Rate limit reached. Public endpoints: 10 req / IP / hour — a free API key (no card, 10,000 requests / month) from https://app.igregulator.io/signup lifts it. Authenticated: per plan tier; paid tiers are not open yet, so email founder@igregulator.io for a higher limit. Retry after the window surfaced in X-RateLimit-Reset.

object
error
required

Human-readable error summary.

string
code
required

HTTP-status-level class. Stable enum; branch on details.reason for finer control. Current values: invalid_query, invalid_slug, invalid_license_id, invalid_jurisdiction_code, invalid_pagination, not_found, auth_required, auth_invalid, auth_revoked, payment_required, quota_exceeded, rate_limited, server_error.

string
details
required
object
reason
required

Machine-readable refinement of the top-level code. Stable vocabulary; branch on this in clients. Examples: invalid_input, missing_required_parameter, conflicting_parameters, operator_not_found, license_not_found, jurisdiction_not_found, route_not_found, api_key_missing, malformed_header, api_key_invalid, api_key_revoked, quota_exceeded, export_requires_pro, export_daily_limit_reached, as_of_not_supported, dataset_not_found, internal_error.

string
field

Present only when the error maps to a specific request input field (query param, path param, body key). Omitted for errors that aren’t field-scoped (e.g. rate_limited, auth_revoked).

string
suggestion

Optional human-readable / agent-actionable hint describing how to resolve the error.

string
{
"reason": "api_key_revoked",
"suggestion": "Generate a new API key at https://app.igregulator.io/api-keys. Revoked keys cannot be restored."
}
{
"error": "API key has been revoked",
"code": "auth_revoked",
"details": {
"reason": "api_key_revoked",
"suggestion": "Generate a new API key at https://app.igregulator.io/api-keys. Revoked keys cannot be restored."
}
}
X-RateLimit-Limit
integer
X-RateLimit-Remaining
integer
X-RateLimit-Reset
integer

Unix epoch seconds.

X-Upgrade-URL
string format: uri

Unexpected server error.

object
error
required

Human-readable error summary.

string
code
required

HTTP-status-level class. Stable enum; branch on details.reason for finer control. Current values: invalid_query, invalid_slug, invalid_license_id, invalid_jurisdiction_code, invalid_pagination, not_found, auth_required, auth_invalid, auth_revoked, payment_required, quota_exceeded, rate_limited, server_error.

string
details
required
object
reason
required

Machine-readable refinement of the top-level code. Stable vocabulary; branch on this in clients. Examples: invalid_input, missing_required_parameter, conflicting_parameters, operator_not_found, license_not_found, jurisdiction_not_found, route_not_found, api_key_missing, malformed_header, api_key_invalid, api_key_revoked, quota_exceeded, export_requires_pro, export_daily_limit_reached, as_of_not_supported, dataset_not_found, internal_error.

string
field

Present only when the error maps to a specific request input field (query param, path param, body key). Omitted for errors that aren’t field-scoped (e.g. rate_limited, auth_revoked).

string
suggestion

Optional human-readable / agent-actionable hint describing how to resolve the error.

string
{
"reason": "api_key_revoked",
"suggestion": "Generate a new API key at https://app.igregulator.io/api-keys. Revoked keys cannot be restored."
}
{
"error": "API key has been revoked",
"code": "auth_revoked",
"details": {
"reason": "api_key_revoked",
"suggestion": "Generate a new API key at https://app.igregulator.io/api-keys. Revoked keys cannot be restored."
}
}