Docs
Batch lookups
Need to check many IPs at once? POST /v1/check/batch takes a list of IPs and returns the same per-IP payload as single /v1/check — one round trip instead of many.
POST
https://api.geoq.io/v1/check/batch Request body
Send JSON with an ips array. Maximum 100 IPs per call. Mixed IPv4 and IPv6 is fine.
{ "ips": ["1.2.3.4", "2001:4860:4860::8888"] } Headers
| Header | Value |
|---|---|
x-api-key | <api_key> — required (see auth). |
Content-Type | application/json |
Examples
$ curl "https://api.geoq.io/v1/check/batch" \ -H "x-api-key: $GEOQ_API_KEY" \ -H "Content-Type: application/json" \ -d '{"ips":["8.8.8.8","2001:4860:4860::8888"]}'
const res = await fetch("https://api.geoq.io/v1/check/batch", { method: "POST", headers: { "x-api-key": process.env.GEOQ_API_KEY, "Content-Type": "application/json", }, body: JSON.stringify({ ips: ["8.8.8.8", "2001:4860:4860::8888"] }), }); const { count, results } = await res.json(); for (const r of results) { if (r.error) console.warn(r.ip, r.error); else console.log(r.ip, r.risk.score, r.risk.level); }
import os, requests res = requests.post( "https://api.geoq.io/v1/check/batch", headers={"x-api-key": os.environ["GEOQ_API_KEY"]}, json={"ips": ["8.8.8.8", "2001:4860:4860::8888"]}, ) body = res.json() for r in body["results"]: if "error" in r: print(r["ip"], r["error"]) else: print(r["ip"], r["risk"]["score"], r["risk"]["level"])
Response
A 200 OK returns count (number of results) and a results array. Each entry is either a full per-IP payload — identical to the single-lookup response schema — or, for an unparseable entry, an error object:
{ "ip": "not-an-ip", "error": "invalid_ip" } Invalid entries do not fail the whole request — they come back inline so you can match results to inputs by position.
{ "count": 2, "results": [ { "ip": "8.8.8.8", "version": 4, "geo": { "country": "United States", "country_code": "US", "region": "California", "city": "Mountain View", "latitude": 37.4, "longitude": -122.1, "timezone": "America/Los_Angeles" }, "network": { "asn": 15169, "as_org": "Google LLC", "is_announced": true, "is_bogon": false, "rpki": "valid", "allocation_date": "2000-03-30", "allocation_age_days": 9566, "registration_country": "US" }, "signals": { "connection_type": "datacenter", "datacenter_provider": "gcp", "relay_provider": null, "is_relay": false, "is_tor": false, "is_vpn": false, "is_proxy": false, "is_public_resolver": true, "is_drop_listed": false, "recent_abuse": false, "is_verified_bot": false, "verified_bot_name": null }, "evidence": { "connection_type": "authoritative", "tor": "authoritative", "vpn": "inferred", "proxy": "beta", "verified_bot": "authoritative", "relay": "authoritative", "routing": "authoritative", "allocation": "authoritative", "drop_listed": "authoritative", "recent_abuse": "beta", "public_resolver": "authoritative" }, "risk": { "score": 20, "level": "low", "reasons": [ "connection_type:datacenter", "benign_network_kind" ] }, "attribution": "https://geoq.io/attributions" }, { "ip": "not-an-ip", "error": "invalid_ip" } ] }
Quota & limits
- Batch lookups count toward your plan quota, metered per IP — a batch of 50 IPs counts as 50 lookups.
- Each IP in a batch counts as one lookup against your quota — a batch of 50 counts as 50. Where a count is ever ambiguous, we round in your favour.
- Up to 100 IPs per call. Send more than that and the request is rejected with
400. - When you exceed your quota, the endpoint returns
429with a quota message — see rate limits.
Status codes
| Code | Meaning |
|---|---|
200 | Success — results returned (individual entries may carry error). |
400 | Malformed body, missing ips, or more than 100 IPs. |
401 | Missing or invalid API key. |
429 | Quota / rate limit exceeded — see rate limits. |
5xx | Server error — retry with backoff. |
Full error format on the errors page.