Authentication
iGregulator uses Bearer tokens: a single opaque API key sent in the
Authorization header. No JWTs, no per-request signatures. Every
authenticated endpoint on api.igregulator.io uses the same scheme.
The one exception is the MCP server’s signed-in endpoint,
https://mcp.igregulator.io/mcp/account: connectors in claude.ai, ChatGPT and
Claude Code sign in with your iGregulator account there (OAuth 2.1) instead of
taking a key. See MCP server → Connect from claude.ai, ChatGPT or Claude Code.
1. Overview
Section titled “1. Overview”| Public | Authenticated | |
|---|---|---|
| Needs a key | — | ✓ |
| Rate limit | 10 req / IP / hour | per-plan quota (Starter 10k/mo, Pro 100k/mo, Business fair-use) |
| Example endpoints | /v1/check, /v1/jurisdictions, /v1/operators/search | /v1/operators/:slug, /v1/licenses/:id, /v1/jurisdictions/:code |
| Who it’s for | quick lookup, demo, embed in a landing page | production integrations, bulk jobs, compliance sweeps |
See pricing for the full plan comparison. Signup is open and free for founding members (full Starter plan); create an account at app.igregulator.io/signup. Paid plans will be billed by card; they aren’t open yet.
2. Generating keys
Section titled “2. Generating keys”- Sign in at app.igregulator.io.
- Go to API keys in the nav.
- Click + generate new key. Give it a descriptive label (“Production server”, “Local dev”, “Staging job”).
- The raw key is displayed once — copy it now. We store a SHA-256 hash only and cannot recover the plaintext. Lose it → rotate.
Key format: igk_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX (36 chars total).
3. Using keys
Section titled “3. Using keys”curl -H "Authorization: Bearer igk_yourkeyhere" \ https://api.igregulator.io/v1/operators/paddy-power-holdings-limitedconst res = await fetch( 'https://api.igregulator.io/v1/operators/paddy-power-holdings-limited', { headers: { Authorization: `Bearer ${process.env.IGREGULATOR_API_KEY}` } },);if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);const operator = await res.json();import os, requests
r = requests.get( 'https://api.igregulator.io/v1/operators/paddy-power-holdings-limited', headers={'Authorization': f'Bearer {os.environ["IGREGULATOR_API_KEY"]}'}, timeout=10,)r.raise_for_status()operator = r.json()Public endpoints work without a key too, but attaching one skips the 10/hour IP cap and uses your plan quota instead — useful when serving dashboards that can burst past the public ceiling.
4. Key rotation
Section titled “4. Key rotation”Rotation is overlap-based — create the new key, deploy it, then revoke the old one. No grace period is needed at our end; old keys stay valid until you explicitly revoke them.
- Generate a new key. Label with the rotation reason.
- Deploy the new key to every consumer (CI variables, running services,
teammates’
.envfiles). - Verify traffic shifted — check the Last used column on the API keys page; the old key should show no recent usage.
- Click Revoke on the old key in the dashboard. Confirmation is
required. Revocation is immediate — the next request carrying the
old key returns
401 auth_revoked.
5. Security
Section titled “5. Security”- Never commit keys to version control. We don’t scan public repos
for you, and don’t count on a secret scanner to catch an
igk_key; a leaked key is your risk. - Use environment variables.
process.env.IGREGULATOR_API_KEYin Node,os.environ['IGREGULATOR_API_KEY']in Python, Docker secrets in containerised deploys. - One key per client. Separate keys per environment (prod / staging / dev / CI) make revocation surgical — you kill the leaked instance without affecting every consumer.
- Keys are stored hashed. SHA-256, never plaintext. If the DB is ever read out, the keys themselves don’t leak — only their prefixes (displayed in the UI anyway).
- HTTPS only. The API doesn’t listen on port 80; HTTP would leak the key in plain text.
- Report compromises to founder@igregulator.io. We’ll help triage and can check for anomalous usage patterns on our side.
6. Rate limits and quotas
Section titled “6. Rate limits and quotas”Two independent ceilings enforced on every authenticated request, both counted per account (all your keys share them):
- Per-second rate limit — your plan’s ceiling
(Starter 5/s, Pro 20/s, Business 100/s, Enterprise unlimited).
Breach →
429 rate_limitedwithRetry-After: 1. - Monthly request quota — plan quota per calendar month, UTC
reset at the first of the month. Breach →
429 quota_exceeded.
Every successful authenticated response carries headers you can read to stay ahead of the monthly quota:
| Header | Meaning |
|---|---|
X-Monthly-Quota-Limit | Your plan’s monthly ceiling, or unlimited |
X-Monthly-Quota-Used | Count so far this month (omitted when unlimited) |
X-Monthly-Quota-Remaining | Quota minus used (omitted when unlimited) |
X-Monthly-Quota-Reset | ISO-8601 timestamp when the counter rolls over (omitted when unlimited) |
X-Monthly-Quota-Warning | Present when usage ≥ 80%: 80% of monthly limit used |
X-RateLimit-Limit | The same monthly ceiling (not the per-second one). Omitted when unlimited. |
X-RateLimit-Remaining | Monthly calls left. Omitted when unlimited. |
X-RateLimit-Reset | Unix epoch seconds of the monthly reset. Omitted when unlimited. |
X-RateLimit-Policy | Only tier=unlimited (plans with no monthly cap), or tier=authenticated when the key is used on a public endpoint. Otherwise absent. |
X-Upgrade-URL | https://igregulator.io/pricing |
The per-second limit has no header on a successful response; a per-second
429 reports it (X-RateLimit-Limit = the per-second limit,
X-RateLimit-Reset = the next second). RateLimit-Policy and the
tier=public;… policy string are sent on keyless calls only. See the
rate limits guide for the full tier table and every
kind of 429.
7. Errors
Section titled “7. Errors”Authenticated endpoints return structured JSON on every non-2xx. Branch
on code for behaviour, details.reason for refinement, and use
details.suggestion verbatim in user-facing messaging when present.
| Status | code | When |
|---|---|---|
| 401 | auth_required | No Authorization header. |
| 401 | auth_invalid | Header malformed or key not recognised. |
| 401 | auth_revoked | Key was revoked via the dashboard. |
| 402 | payment_required | details.reason: plan_inactive — the account has no plan or a canceled one. endpoint_requires_paid_plan — a legacy trial key on anything but GET /v1/check and the endpoints that work without a key. |
| 429 | rate_limited | Per-second ceiling breached (details.reason: per_second_limit_exceeded). Sleep 1 s, retry once. |
| 429 | quota_exceeded | Monthly quota exhausted (details.reason: monthly_request_limit_reached). Wait for details.reset_at, or email founder@igregulator.io. |
Full code reference lives in the error handling guide.
Example body (401):
{ "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." }}