Skip to content

Search operators by name

GET
/v1/operators/search

A case-insensitive substring match on display_name, slug and registered_name — the operator’s list of trading names is not searched (for UKGC, registered_name often holds the brand, so bet365 still finds the Hillside entities). To go from a website to its operator, use GET /v1/check?domain=. Results ranked: exact slug match > display-name prefix > the rest, then by display_name. Operators are returned whatever the status of their licences — a hit is not a statement that the operator is licensed.

No key needed. Without one: 10 requests / IP / hour, and at most 3 rows per request whatever ?limit= says (limit in the response is the value applied; total still counts every match, and offset still pages).

With a valid key: your plan’s limits, limit up to 100 (default 20).

q
required
string
>= 1 characters <= 200 characters

The text to look for, 1–200 characters after trimming. Matched literally, case-insensitively, anywhere in the name or slug — % and _ are ordinary characters, not wildcards.

Example

888
limit
integer
default: 20 >= 1 <= 100

Rows per page. Out of range is a 400. Without a key the effective value is at most 3.

offset
integer
0

One page of matching operators (possibly empty).

Media type application/json
object
q
required

The search term as applied (trimmed).

string
total
required

Every operator that matches, not just this page.

integer
limit
required

The limit actually applied: without a key at most 3, whatever ?limit= asked for.

integer
offset
required
integer
operators
required
Array

Operator row plus per-item provenance _meta. Used inside OperatorSearchResult.operators[].

object
id
required
string format: uuid
slug
required

Lower-case, URL-safe; the key of /v1/operators/{slug}.

string
display_name
required
string
registered_name
required

The name the register gives next to the entity. For UKGC this is often the trading name (e.g. bet365, paddy power), not a legal name.

string | null
country
required

null for almost every operator: the register loaders do not record a country. Only operators first seen through the Curaçao certificate registry carry one (CW). Do not filter on it.

string | null
upstream_ids
required

The operator’s id in each register it appears in, keyed by jurisdiction code.

object
key
additional properties
string
created_at
required

When we first recorded the operator.

string format: date-time
updated_at
required

When the operator’s own row last changed (a rename) — NOT when we last read a register about it; for that use a licence’s last_verified_at or the search row’s _meta.scraped_at.

string format: date-time
_meta
required

Single-resource provenance envelope — answers “where did this come from and how fresh is it?” for one record.

object
scraped_at
required

ISO-8601 timestamp when iGregulator’s scraper last fetched this record.

string format: date-time
source_modified_at
required

Reserved: when the regulator last modified the record on its register, as opposed to when we fetched it. Always null today, for every jurisdiction — we do not store an upstream modification time. Kept in the shape so clients need not branch if it is ever populated. For freshness use scraped_at; for when a licence’s status was last read from its source, status_observed_at on the licence.

string | null format: date-time
source_url
required

The regulator page this answer rests on. For a licence — including a /v1/check match — it is the page that published the licence’s current STATUS (status_source_url: an enforcement register, a revoked-licences list, an advisory notice), falling back to the register the licence is listed in when they are the same page. Null when not attributable to a single URL.

string | null format: uri
confidence_hint
required

authoritative — UKGC: the Commission’s own machine-readable register export (a ZIP). scraped — every other jurisdiction (MGA, CW, KH, AN, TGC, IOM, ON, SE, ES, BE, DE, CO, UA): parsed from the published HTML/PDF pages or spreadsheet export; also every operator-search row. derived — a computed answer, not a direct lookup: a fuzzy or no-match /v1/check, with no source row behind it.

string
Allowed values: authoritative scraped derived
_meta
required

Aggregate provenance envelope for list responses. Describes the freshness window of the returned rows.

object
freshness_range
required

The oldest and newest timestamp among the returned rows — search: when each operator’s licences were last verified; history: the events’ changed_at. Both null when no row was returned.

object
oldest
required
string | null format: date-time
newest
required
string | null format: date-time
total_sources
required

On /v1/licenses/{license_id}/history: the number of distinct source_url values among the events. On /v1/operators/search: always 1 — a placeholder, not a count; do not read it.

integer

Example

{
"q": "888",
"total": 1,
"limit": 3,
"offset": 0,
"operators": [
{
"id": "fa30b85c-4749-4f91-9490-2615b76a4832",
"slug": "888-uk-limited",
"display_name": "888 UK Limited",
"registered_name": "888",
"country": null,
"upstream_ids": {
"UKGC": "39028"
},
"created_at": "2026-04-17T15:15:41.414Z",
"updated_at": "2026-04-17T15:15:41.414Z",
"_meta": {
"scraped_at": "2026-10-07T03:00:12.644Z",
"source_modified_at": null,
"source_url": null,
"confidence_hint": "scraped"
}
}
],
"_meta": {
"freshness_range": {
"oldest": "2026-10-07T03:00:12.644Z",
"newest": "2026-10-07T03:00:12.644Z"
},
"total_sources": 1
}
}
X-RateLimit-Limit
integer

Without a key: 10 — requests per IP per clock hour on THIS endpoint (each keyless endpoint has its own counter). With a valid key these three X-RateLimit-* headers describe your monthly quota instead, and the X-Monthly-Quota-* headers are sent too — see any keyed endpoint.

X-RateLimit-Remaining
integer

Requests left this hour, this one counted. A refused request (400) counts.

X-RateLimit-Reset
integer

Unix epoch seconds of the top of the next UTC hour, when the counter starts again.

X-RateLimit-Policy
string

tier=public;limit=10;window=hour without a key; tier=authenticated with one.

RateLimit-Policy
string

The same limit in the IETF draft form, "default";q=10;w=3600. Not sent on a keyed call.

X-Upgrade-URL
string format: uri

Always https://igregulator.io/pricing.

q is missing or empty, or limit / offset is out of range.

Media type application/json

The body of every non-2xx response.

object
error
required

Human-readable summary. The wording can change; do not branch on it.

string
code
required

The error class. Mostly one per HTTP status, with two exceptions to know: quota_exceeded is a 429 for the monthly request quota and a 403 for a plan cap (watchlist size, webhook endpoints). A 409 carries conflict (it carried invalid_query before 1.24.0). Branch on the HTTP status and details.reason. forbidden is only ever sent to a signed-in MCP connection, never to an API key.

string
Allowed values: invalid_query invalid_slug invalid_license_id invalid_jurisdiction_code invalid_pagination auth_required auth_invalid auth_revoked payment_required forbidden not_found method_not_allowed conflict quota_exceeded rate_limited server_error
details
required

Always present. reason is always set; field and suggestion when they apply; limit errors add the numbers below.

object
reason
required

Machine-readable refinement of the top-level code — branch on this. Values: invalid_input, missing_required_parameter, conflicting_parameters, not_a_valid_hostname, hostname_too_long, invalid_pagination, invalid_cursor, since_exceeds_retention_window, invalid_event_type, invalid_jurisdiction, as_of_not_supported, api_key_missing, malformed_header, api_key_invalid, api_key_revoked, plan_inactive, plan_ended, export_requires_pro, geo_checks_require_business, watchlist_quota_exceeded, webhook_quota_exceeded, operator_not_found, license_not_found, jurisdiction_not_found, webhook_not_found, dataset_not_found, route_not_found, method_not_allowed, watchlist_duplicate, no_active_secret, quota_exceeded, monthly_request_limit_reached, per_second_limit_exceeded, watchlist_events_poll_limit, export_daily_limit_reached, geo_check_quota_exceeded, internal_error. A rejected webhook URL carries the SSRF check’s reason (invalid_url, invalid_scheme, empty_host, blocked_hostname, unresolvable_host, private_ip_blocked). New values can be added.

string
field

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

string
suggestion

A hint a person or an agent can act on. Present on every error today.

string
limit

On a limit error (429, and the 403 plan caps): the ceiling that was reached.

integer
current_usage

On a keyed limit error: how much of limit is used. Not on the keyless per-IP 429 or the watchlist-poll 429.

integer
reset_at

When the counter starts again — on the keyless per-IP 429, the monthly quota, the watchlist-poll limit and the export daily limit. Not on the per-second limit (retry after one second).

string format: date-time
plan_tier

The key’s plan, on plan-scoped limit errors and on export_requires_pro.

string
required_plan

On export_requires_pro: the lowest plan that includes the feature.

string
window

On watchlist_events_poll_limit: always hour.

string
key
additional properties
any

Example

{
"error": "q required; limit 1–100; offset 0–1000000",
"code": "invalid_query",
"details": {
"reason": "invalid_input",
"suggestion": "Provide ?q=<search term>, optional ?limit=1..100 (default 20) and ?offset=0.. (default 0)."
}
}

The API key is missing, malformed, unknown or revoked. On an endpoint that works without a key this is only ever sent when a key WAS sent and is not valid — drop the header, or fix the key.

Media type application/json

The body of every non-2xx response.

object
error
required

Human-readable summary. The wording can change; do not branch on it.

string
code
required

The error class. Mostly one per HTTP status, with two exceptions to know: quota_exceeded is a 429 for the monthly request quota and a 403 for a plan cap (watchlist size, webhook endpoints). A 409 carries conflict (it carried invalid_query before 1.24.0). Branch on the HTTP status and details.reason. forbidden is only ever sent to a signed-in MCP connection, never to an API key.

string
Allowed values: invalid_query invalid_slug invalid_license_id invalid_jurisdiction_code invalid_pagination auth_required auth_invalid auth_revoked payment_required forbidden not_found method_not_allowed conflict quota_exceeded rate_limited server_error
details
required

Always present. reason is always set; field and suggestion when they apply; limit errors add the numbers below.

object
reason
required

Machine-readable refinement of the top-level code — branch on this. Values: invalid_input, missing_required_parameter, conflicting_parameters, not_a_valid_hostname, hostname_too_long, invalid_pagination, invalid_cursor, since_exceeds_retention_window, invalid_event_type, invalid_jurisdiction, as_of_not_supported, api_key_missing, malformed_header, api_key_invalid, api_key_revoked, plan_inactive, plan_ended, export_requires_pro, geo_checks_require_business, watchlist_quota_exceeded, webhook_quota_exceeded, operator_not_found, license_not_found, jurisdiction_not_found, webhook_not_found, dataset_not_found, route_not_found, method_not_allowed, watchlist_duplicate, no_active_secret, quota_exceeded, monthly_request_limit_reached, per_second_limit_exceeded, watchlist_events_poll_limit, export_daily_limit_reached, geo_check_quota_exceeded, internal_error. A rejected webhook URL carries the SSRF check’s reason (invalid_url, invalid_scheme, empty_host, blocked_hostname, unresolvable_host, private_ip_blocked). New values can be added.

string
field

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

string
suggestion

A hint a person or an agent can act on. Present on every error today.

string
limit

On a limit error (429, and the 403 plan caps): the ceiling that was reached.

integer
current_usage

On a keyed limit error: how much of limit is used. Not on the keyless per-IP 429 or the watchlist-poll 429.

integer
reset_at

When the counter starts again — on the keyless per-IP 429, the monthly quota, the watchlist-poll limit and the export daily limit. Not on the per-second limit (retry after one second).

string format: date-time
plan_tier

The key’s plan, on plan-scoped limit errors and on export_requires_pro.

string
required_plan

On export_requires_pro: the lowest plan that includes the feature.

string
window

On watchlist_events_poll_limit: always hour.

string
key
additional properties
any

Examples

{
"error": "Authorization header required",
"code": "auth_required",
"details": {
"reason": "api_key_missing",
"suggestion": "Attach an API key: `Authorization: Bearer <key>`. No key yet? Start a 14-day free trial of Starter (card required) at https://app.igregulator.io/signup; an existing account creates keys at https://app.igregulator.io/api-keys."
}
}

Only when a key was sent and its account has no plan or a canceled one (plan_inactive), or its plan’s end date has passed (plan_ended). The same request without the Authorization header is answered (within the per-IP limit).

Media type application/json

The body of every non-2xx response.

object
error
required

Human-readable summary. The wording can change; do not branch on it.

string
code
required

The error class. Mostly one per HTTP status, with two exceptions to know: quota_exceeded is a 429 for the monthly request quota and a 403 for a plan cap (watchlist size, webhook endpoints). A 409 carries conflict (it carried invalid_query before 1.24.0). Branch on the HTTP status and details.reason. forbidden is only ever sent to a signed-in MCP connection, never to an API key.

string
Allowed values: invalid_query invalid_slug invalid_license_id invalid_jurisdiction_code invalid_pagination auth_required auth_invalid auth_revoked payment_required forbidden not_found method_not_allowed conflict quota_exceeded rate_limited server_error
details
required

Always present. reason is always set; field and suggestion when they apply; limit errors add the numbers below.

object
reason
required

Machine-readable refinement of the top-level code — branch on this. Values: invalid_input, missing_required_parameter, conflicting_parameters, not_a_valid_hostname, hostname_too_long, invalid_pagination, invalid_cursor, since_exceeds_retention_window, invalid_event_type, invalid_jurisdiction, as_of_not_supported, api_key_missing, malformed_header, api_key_invalid, api_key_revoked, plan_inactive, plan_ended, export_requires_pro, geo_checks_require_business, watchlist_quota_exceeded, webhook_quota_exceeded, operator_not_found, license_not_found, jurisdiction_not_found, webhook_not_found, dataset_not_found, route_not_found, method_not_allowed, watchlist_duplicate, no_active_secret, quota_exceeded, monthly_request_limit_reached, per_second_limit_exceeded, watchlist_events_poll_limit, export_daily_limit_reached, geo_check_quota_exceeded, internal_error. A rejected webhook URL carries the SSRF check’s reason (invalid_url, invalid_scheme, empty_host, blocked_hostname, unresolvable_host, private_ip_blocked). New values can be added.

string
field

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

string
suggestion

A hint a person or an agent can act on. Present on every error today.

string
limit

On a limit error (429, and the 403 plan caps): the ceiling that was reached.

integer
current_usage

On a keyed limit error: how much of limit is used. Not on the keyless per-IP 429 or the watchlist-poll 429.

integer
reset_at

When the counter starts again — on the keyless per-IP 429, the monthly quota, the watchlist-poll limit and the export daily limit. Not on the per-second limit (retry after one second).

string format: date-time
plan_tier

The key’s plan, on plan-scoped limit errors and on export_requires_pro.

string
required_plan

On export_requires_pro: the lowest plan that includes the feature.

string
window

On watchlist_events_poll_limit: always hour.

string
key
additional properties
any

Examples

{
"error": "Active subscription required",
"code": "payment_required",
"details": {
"reason": "plan_inactive",
"suggestion": "Current plan_tier: canceled — this account has no active plan. Renew or choose a plan at https://app.igregulator.io/billing (by card, or by invoice for three months or more; Starter starts with a 14-day free trial, card required), or email founder@igregulator.io."
}
}

Without a key: the per-IP limit of this endpoint, 10 requests per hour (rate_limited / quota_exceeded) — every keyless endpoint has its own counter, a refused request (400) counts, and an API key lifts it — Starter (10,000 requests / month) starts with a 14-day free trial, card required, at https://app.igregulator.io/signup. With a key: the limits of the key — see the key_* examples.

Media type application/json

The body of every non-2xx response.

object
error
required

Human-readable summary. The wording can change; do not branch on it.

string
code
required

The error class. Mostly one per HTTP status, with two exceptions to know: quota_exceeded is a 429 for the monthly request quota and a 403 for a plan cap (watchlist size, webhook endpoints). A 409 carries conflict (it carried invalid_query before 1.24.0). Branch on the HTTP status and details.reason. forbidden is only ever sent to a signed-in MCP connection, never to an API key.

string
Allowed values: invalid_query invalid_slug invalid_license_id invalid_jurisdiction_code invalid_pagination auth_required auth_invalid auth_revoked payment_required forbidden not_found method_not_allowed conflict quota_exceeded rate_limited server_error
details
required

Always present. reason is always set; field and suggestion when they apply; limit errors add the numbers below.

object
reason
required

Machine-readable refinement of the top-level code — branch on this. Values: invalid_input, missing_required_parameter, conflicting_parameters, not_a_valid_hostname, hostname_too_long, invalid_pagination, invalid_cursor, since_exceeds_retention_window, invalid_event_type, invalid_jurisdiction, as_of_not_supported, api_key_missing, malformed_header, api_key_invalid, api_key_revoked, plan_inactive, plan_ended, export_requires_pro, geo_checks_require_business, watchlist_quota_exceeded, webhook_quota_exceeded, operator_not_found, license_not_found, jurisdiction_not_found, webhook_not_found, dataset_not_found, route_not_found, method_not_allowed, watchlist_duplicate, no_active_secret, quota_exceeded, monthly_request_limit_reached, per_second_limit_exceeded, watchlist_events_poll_limit, export_daily_limit_reached, geo_check_quota_exceeded, internal_error. A rejected webhook URL carries the SSRF check’s reason (invalid_url, invalid_scheme, empty_host, blocked_hostname, unresolvable_host, private_ip_blocked). New values can be added.

string
field

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

string
suggestion

A hint a person or an agent can act on. Present on every error today.

string
limit

On a limit error (429, and the 403 plan caps): the ceiling that was reached.

integer
current_usage

On a keyed limit error: how much of limit is used. Not on the keyless per-IP 429 or the watchlist-poll 429.

integer
reset_at

When the counter starts again — on the keyless per-IP 429, the monthly quota, the watchlist-poll limit and the export daily limit. Not on the per-second limit (retry after one second).

string format: date-time
plan_tier

The key’s plan, on plan-scoped limit errors and on export_requires_pro.

string
required_plan

On export_requires_pro: the lowest plan that includes the feature.

string
window

On watchlist_events_poll_limit: always hour.

string
key
additional properties
any

Examples

{
"error": "Public rate limit reached (10/hour/IP).",
"code": "rate_limited",
"details": {
"reason": "quota_exceeded",
"suggestion": "Start a 14-day free trial of Starter (card required) at https://app.igregulator.io/signup for an API key — 10,000 requests/month, no per-IP cap — and send it as \"Authorization: Bearer <key>\". Or wait until reset_at, the top of the next hour (UTC; also the X-RateLimit-Reset header).",
"limit": 10,
"reset_at": "2026-10-08T01:00:00.000Z"
}
}
X-RateLimit-Limit
integer

Without a key: 10 — requests per IP per clock hour on THIS endpoint (each keyless endpoint has its own counter). With a valid key these three X-RateLimit-* headers describe your monthly quota instead, and the X-Monthly-Quota-* headers are sent too — see any keyed endpoint.

X-RateLimit-Remaining
integer

Requests left this hour, this one counted. A refused request (400) counts.

X-RateLimit-Reset
integer

Unix epoch seconds of the top of the next UTC hour, when the counter starts again.

X-RateLimit-Policy
string

tier=public;limit=10;window=hour without a key; tier=authenticated with one.

RateLimit-Policy
string

The same limit in the IETF draft form, "default";q=10;w=3600. Not sent on a keyed call.

X-Upgrade-URL
string format: uri

Always https://igregulator.io/pricing.

Unexpected server error. Safe to retry.

Media type application/json

The body of every non-2xx response.

object
error
required

Human-readable summary. The wording can change; do not branch on it.

string
code
required

The error class. Mostly one per HTTP status, with two exceptions to know: quota_exceeded is a 429 for the monthly request quota and a 403 for a plan cap (watchlist size, webhook endpoints). A 409 carries conflict (it carried invalid_query before 1.24.0). Branch on the HTTP status and details.reason. forbidden is only ever sent to a signed-in MCP connection, never to an API key.

string
Allowed values: invalid_query invalid_slug invalid_license_id invalid_jurisdiction_code invalid_pagination auth_required auth_invalid auth_revoked payment_required forbidden not_found method_not_allowed conflict quota_exceeded rate_limited server_error
details
required

Always present. reason is always set; field and suggestion when they apply; limit errors add the numbers below.

object
reason
required

Machine-readable refinement of the top-level code — branch on this. Values: invalid_input, missing_required_parameter, conflicting_parameters, not_a_valid_hostname, hostname_too_long, invalid_pagination, invalid_cursor, since_exceeds_retention_window, invalid_event_type, invalid_jurisdiction, as_of_not_supported, api_key_missing, malformed_header, api_key_invalid, api_key_revoked, plan_inactive, plan_ended, export_requires_pro, geo_checks_require_business, watchlist_quota_exceeded, webhook_quota_exceeded, operator_not_found, license_not_found, jurisdiction_not_found, webhook_not_found, dataset_not_found, route_not_found, method_not_allowed, watchlist_duplicate, no_active_secret, quota_exceeded, monthly_request_limit_reached, per_second_limit_exceeded, watchlist_events_poll_limit, export_daily_limit_reached, geo_check_quota_exceeded, internal_error. A rejected webhook URL carries the SSRF check’s reason (invalid_url, invalid_scheme, empty_host, blocked_hostname, unresolvable_host, private_ip_blocked). New values can be added.

string
field

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

string
suggestion

A hint a person or an agent can act on. Present on every error today.

string
limit

On a limit error (429, and the 403 plan caps): the ceiling that was reached.

integer
current_usage

On a keyed limit error: how much of limit is used. Not on the keyless per-IP 429 or the watchlist-poll 429.

integer
reset_at

When the counter starts again — on the keyless per-IP 429, the monthly quota, the watchlist-poll limit and the export daily limit. Not on the per-second limit (retry after one second).

string format: date-time
plan_tier

The key’s plan, on plan-scoped limit errors and on export_requires_pro.

string
required_plan

On export_requires_pro: the lowest plan that includes the feature.

string
window

On watchlist_events_poll_limit: always hour.

string
key
additional properties
any

Example

{
"error": "Internal server error",
"code": "server_error",
"details": {
"reason": "internal_error",
"suggestion": "Retry with exponential backoff (1s / 2s / 4s). If the error persists past 4 seconds, surface failure state to the user instead of looping."
}
}