Docs
Errors
Errors use a consistent JSON envelope so you can handle them generically.
Error format
{
"error": {
"type": "invalid_request",
"message": "Query parameter 'ip' is not a valid IP address."
}
} Error types
| HTTP | type | Meaning | What to do |
|---|---|---|---|
400 | invalid_request | The IP is missing/malformed or a parameter is invalid. | Fix the request; don't retry unchanged. |
401 | unauthorized | Missing, invalid or revoked API key. | Check the Authorization header / rotate the key. |
403 | forbidden | The key is valid but not permitted for this resource. | Check plan / key scope. |
429 | rate_limited | Daily quota or burst limit exceeded. | Back off to X-RateLimit-Reset; upgrade if persistent. |
500 | server_error | Unexpected server error. | Retry with exponential backoff. |
503 | unavailable | Temporary maintenance / overload. | Retry with backoff. |
Retry guidance
- Don't retry
400/401/403unchanged — fix the request. - Do retry
5xxwith exponential backoff and jitter. - On
429, wait untilX-RateLimit-Reset(see rate limits).
async function check(ip, tries = 3) { for (let i = 0; i < tries; i++) { const url = `https://api.geoq.io/v1/check?ip=${ip}`; const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.GEOQ_API_KEY}` }, }); if (res.ok) return res.json(); if (res.status < 500 && res.status !== 429) break; // client error await new Promise((r) => setTimeout(r, 2 ** i * 250)); } throw new Error("geoq check failed"); }