API reference

A small REST API over HTTPS. Every response is JSON; every error carries a stable code.

Authentication

Send your key as a bearer token. X-API-Key is accepted too, for clients that cannot set an Authorization header.

curl https://geopass.site/api/v1/lookup/1.1.1.1 \
  -H "Authorization: Bearer gp_live_…"

# equivalent
curl https://geopass.site/api/v1/lookup/1.1.1.1 \
  -H "X-API-Key: gp_live_…"

Keys are stored hashed and shown once at creation. Revoking a key takes effect on the next request.

Endpoints

GEThttps://geopass.site/api/v1/lookup/{ip}Resolve one address.
GEThttps://geopass.site/api/v1/lookup/meResolve the caller’s address.
POSThttps://geopass.site/api/v1/lookup/batchResolve many at once.
GEThttps://geopass.site/api/v1/usageCheck what is left. Free.

A batch takes a JSON body and bills one lookup per valid address:

curl -X POST https://geopass.site/api/v1/lookup/batch \
  -H "Authorization: Bearer gp_live_…" \
  -H "Content-Type: application/json" \
  -d '{"ips": ["1.1.1.1", "8.8.8.8"]}'

Checking your usage

/v1/usage reports where you stand without drawing on the allowance, so a client can poll it or show a meter without spending a lookup to ask. It is rate limited like any other call.

curl https://geopass.site/api/v1/usage -H "Authorization: Bearer gp_live_…"

{
  "plan": { "id": "pro", "name": "Pro" },
  "quota": {
    "limit": 50000,
    "used": 1234,
    "remaining": 48766,
    "resetsAt": "2026-10-01T00:00:00.000Z"
  },
  "rateLimit": { "limit": 50, "window": "1s" },
  "batchLimit": 100
}

Response

meta.sources names the upstream behind each half of the answer, and meta.cached tells you whether it was served from our cache. A null source means nothing answered that half, so its fields are defaults rather than findings.

On the privacy block: hosting and anonymous are reported by our upstream. vpn, proxy, tor and relay are not yet broken out and stay false; use anonymous as the signal that an origin is being hidden.

Fields a source does not supply come back null, never invented. Booleans that were never checked are null too, so false always means an actual answer.

{
  "ip": "1.1.1.1",
  "type": "ipv4",
  "location": {
    "country": "AU",              // ISO 3166-1 alpha-2
    "countryName": "Australia",
    "region": "Queensland",
    "regionCode": "QLD",
    "city": "Brisbane",
    "postalCode": "9010",
    "latitude": -27.4679,
    "longitude": 153.0281,
    "timezone": "Australia/Brisbane",
    "continent": "Oceania",
    "continentCode": "OC",
    "publicPlace": false          // airport, hotel, campus
  },
  "network": {
    "asn": 13335,
    "organization": "Cloudflare, Inc.",
    "isp": "Cloudflare, Inc.",
    "domain": "cloudflare.com",
    "hostname": "one.one.one.one",
    "route": null,
    "type": "hosting",            // hosting, isp, business, education
    "mobile": false,              // cellular carrier rather than fixed line
    "satellite": false,
    "anycast": true               // announced from many locations
  },
  "privacy": {
    "hosting": true,              // datacentre address
    "anonymous": false,           // origin is obscured
    "proxy": false,
    "vpn": false,
    "tor": false,
    "relay": false
  },
  "meta": {
    "sources": { "geo": "ipinfo:core", "privacy": "ipinfo:core" },
    "cached":  { "geo": true,          "privacy": true }
  }
}

Rate limits and quota

Four headers ride along on every successful response, so a client can back off before it is throttled.

x-ratelimit-limit: 50
x-ratelimit-remaining: 49
x-quota-limit: 500000
x-quota-remaining: 499999
PlanMonthlyPer secondBatch
Trial500210
Starter10,000525
Pro50,00050100
Business100,000250500

Quotas reset at 00:00 UTC on the first of the month. Rate limits are a fixed one-second window per key.

A new account starts on Trial, which is there to let you check the data against addresses you already know before paying for anything. It is not sized for production traffic.

Errors

{ "error": { "code": "reserved_address", "message": "…" } }
StatusCodeWhen
400invalid_requestThe address could not be parsed, or the batch body was malformed.
401unauthorizedThe API key is missing, malformed, revoked, or unknown.
422reserved_addressA private, loopback, link-local or documentation address.
429rate_limitedToo many requests this second. Retry after the Retry-After header.
429quota_exceededThe monthly allowance is spent. Retry-After gives the reset time.
502upstream_unavailableNo provider could resolve the address. Not billed.

Nothing you cannot use is billed. Malformed and reserved addresses never draw on the quota, and a lookup that fails upstream is refunded.