Skip to content

Request a geo-check of a domain in one or more countries

POST
/v1/geo-checks

Queues a check of domain from each of countries (all ten when left out). One request is ONE against the monthly allowance whatever the number of countries — Business: 10 per UTC month, Enterprise: no cap. A definite result (not unknown) for the same domain and country from the last 7 days answers that country at once (from_cache, with its date); a request answered entirely so is done and is NOT counted against the allowance. Results arrive within about two business days: a “reachable” is confirmed on a screenshot first. Follow them with GET /v1/geo-check-requests. Who requested a check is never shown to anyone else.

Media type application/json
object
domain
required

A hostname. A scheme, a path and a leading www. are dropped; case does not matter.

string
countries

ISO 3166-1 alpha-2, case-insensitive; duplicates collapse. Leave out for all. CA is Ontario.

Array<string>
>= 1 items <= 10 items
Allowed values: GB SE NL DE ES IT FR BR CA AU

Example

{
"domain": "example-casino.com",
"countries": [
"GB",
"SE",
"NL"
]
}

Queued — or done, when recent checks answered every country.

Media type application/json
object
request_id
required
string format: uuid
domain
required
string
countries
required
Array<string>
status
required

done when recent checks answered every country (not counted).

string
Allowed values: queued done
requested_at
required
string format: date-time
from_cache
required

Countries a recent definite check answered at once, with that check’s date.

Array<object>
object
country
required
string
checked_at
required
string format: date-time
expected_within
required
string | null
monthly_usage
required

Domains requested this UTC month and the plan allowance; null on a plan with no cap.

object
used
required
integer
limit
required
integer

Example

{
"request_id": "0b9c2a6e-1f3d-4c1a-9f0e-7d1c2b3a4e5f",
"domain": "example-casino.com",
"countries": [
"GB",
"SE",
"NL"
],
"status": "queued",
"requested_at": "2026-11-03T09:12:00.000Z",
"from_cache": [
{
"country": "GB",
"checked_at": "2026-11-01T14:02:00.000Z"
}
],
"expected_within": "two business days",
"monthly_usage": {
"used": 3,
"limit": 10
}
}
X-RateLimit-Limit
integer

Your plan’s monthly request quota (not the per-second limit). Not sent on a plan with no monthly quota (Business, Enterprise).

X-RateLimit-Remaining
integer

What is left of the monthly quota, this request counted. Not sent on a plan with no monthly quota.

X-RateLimit-Reset
integer

Unix epoch seconds of the start of the next UTC month. Not sent on a plan with no monthly quota.

X-RateLimit-Policy
string

tier=unlimited on a plan with no monthly quota; otherwise not sent.

X-Upgrade-URL
string format: uri

Always https://igregulator.io/pricing.

X-Monthly-Quota-Limit
string

The monthly request quota of your plan, or unlimited.

X-Monthly-Quota-Used
integer

Requests counted this UTC month, this one included (a request that ends in 4xx / 5xx is not counted). Not sent when the limit is unlimited.

X-Monthly-Quota-Remaining
integer

What is left of the monthly quota. Not sent when unlimited.

X-Monthly-Quota-Reset
string format: date-time

When the monthly counter starts again: the first of next month, 00:00 UTC, ISO-8601. Not sent when unlimited.

X-Monthly-Quota-Warning
string

80% of monthly limit used — sent from 80% of the quota on, absent before.

The body is not JSON, domain is not a hostname, or a country is not one we check from.

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": "domain and country required",
"code": "invalid_query",
"details": {
"reason": "invalid_input",
"suggestion": "POST body must be { \"domain\": \"example.com\", \"countries\": [...] } — countries from GB, SE, NL, DE, ES, IT, FR, BR, CA, AU; leave it out for all of them."
}
}

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."
}
}

The plan has no geo-checks (Business and Enterprise do).

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": "This endpoint is available on the Business and Enterprise plans",
"code": "payment_required",
"details": {
"reason": "geo_checks_require_business",
"required_plan": "business",
"available_on": [
"business",
"enterprise"
],
"plan_tier": "pro",
"suggestion": "Geo-check endpoints come with Business (10 domains a month) and Enterprise (bulk). See https://igregulator.io/pricing or email founder@igregulator.io."
}
}

The month’s geo-check allowance is used — or one of the key’s own limits, as on every keyed endpoint.

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": "Monthly geo-check allowance used",
"code": "quota_exceeded",
"details": {
"reason": "geo_check_quota_exceeded",
"current_usage": 10,
"limit": 10,
"plan_tier": "business",
"suggestion": "Plan \"business\" allows 10 geo-checks per UTC month. Bulk checks are part of Enterprise — email founder@igregulator.io."
}
}

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."
}
}