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

HTTPtypeMeaningWhat to do
400invalid_requestThe IP is missing/malformed or a parameter is invalid.Fix the request; don't retry unchanged.
401unauthorizedMissing, invalid or revoked API key.Check the Authorization header / rotate the key.
403forbiddenThe key is valid but not permitted for this resource.Check plan / key scope.
429rate_limitedDaily quota or burst limit exceeded.Back off to X-RateLimit-Reset; upgrade if persistent.
500server_errorUnexpected server error.Retry with exponential backoff.
503unavailableTemporary maintenance / overload.Retry with backoff.

Retry guidance

  • Don't retry 400/401/403 unchanged — fix the request.
  • Do retry 5xx with exponential backoff and jitter.
  • On 429, wait until X-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");
}