Error handling
Errors always return JSON with a stable code field. Use code for
branching in clients, not the HTTP status or the human message (the
human message can change).
Response shape
Section titled “Response shape”{ "error": "Human-readable explanation.", "code": "rate_limited", "details": { "limit": 10, "window_seconds": 3600 }}Code reference
Section titled “Code reference”| HTTP | code | When | Retry? |
|---|---|---|---|
| 400 | invalid_query | Missing / malformed query params. | No — fix the request. |
| 400 | invalid_slug | Slug path param failed validation. | No. |
| 401 | auth_required | No Authorization header on a gated endpoint. | No — attach the header. |
| 401 | auth_invalid | Header malformed or key not recognised. | No. |
| 401 | auth_revoked | Key has been revoked. | No — provision a new key. |
| 404 | not_found | Slug / id not in the registry. | No. |
| 429 | rate_limited | Hit the public 10/hr or per-plan ceiling. | Yes — wait until X-RateLimit-Reset. |
| 500 | server_error | Unhandled upstream failure. | Yes — exponential backoff, 3 attempts. |
Retry strategy
Section titled “Retry strategy”- 4xx — fix the request, don’t retry. The same bad input will always 4xx.
- 429 — sleep until
X-RateLimit-Reset(Unix epoch seconds), retry once. If you hit 429 again, you’re under-provisioned — upgrade or authenticate, don’t loop. - 5xx — exponential backoff up to 3 attempts (1s, 2s, 4s). If a 5xx persists past 4 seconds, you’re better off surfacing a failure state than holding the UI hostage.
Reference implementation (JavaScript)
Section titled “Reference implementation (JavaScript)”async function igRequest(path, init = {}, attempt = 0) { const r = await fetch('https://api.igregulator.io' + path, init); if (r.ok) return r.json();
const body = await r.json().catch(() => ({ code: 'parse_error' })); const code = body.code ?? 'unknown';
if (r.status === 429) { const reset = Number(r.headers.get('X-RateLimit-Reset')) * 1000; const sleepFor = Math.max(0, reset - Date.now()); if (sleepFor < 5 * 60_000) { await new Promise((res) => setTimeout(res, sleepFor + 1_000)); return igRequest(path, init, attempt + 1); } }
if (r.status >= 500 && attempt < 3) { await new Promise((res) => setTimeout(res, 2 ** attempt * 1_000)); return igRequest(path, init, attempt + 1); }
const err = new Error(body.error ?? r.statusText); err.status = r.status; err.code = code; err.details = body.details; throw err;}