{"openapi":"3.1.0","info":{"title":"IP Address Today API","version":"1.0.0","summary":"IP geolocation, ASN, and timezone data as JSON.","description":"Look up any IPv4 or IPv6 address. Keyless requests are limited to 45/minute; an API key raises this to your plan\u0027s monthly quota. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers.","contact":{"name":"IP Address Today support","email":"support@ipaddresstoday.com","url":"https://www.ipaddresstoday.com/contact"},"termsOfService":"https://www.ipaddresstoday.com/legal/terms"},"servers":[{"url":"https://api.ipaddresstoday.com","description":"This server"},{"url":"https://api.ipaddresstoday.com","description":"Production"}],"security":[{},{"ApiKeyHeader":[]}],"tags":[{"name":"Lookup","description":"IP geolocation lookups."},{"name":"Service","description":"Health and status."}],"paths":{"/api/v1/ip":{"get":{"tags":["Lookup"],"summary":"Look up the caller\u0027s IP","description":"Returns the full record for the address the request came from.","operationId":"getOwnIp","parameters":[{"name":"fields","in":"query","description":"Comma-separated dotted paths to keep, e.g. ip,location.country.name. Everything else is omitted.","schema":{"type":"string"}},{"name":"lang","in":"query","description":"Language for place names.","schema":{"type":"string","enum":["en","de","es","fr","ja","pt-BR","ru","zh-CN"],"default":"en"}},{"name":"format","in":"query","description":"Response format.","schema":{"type":"string","enum":["json","text","jsonp"],"default":"json"}}],"responses":{"200":{"description":"The lookup result.","headers":{"X-RateLimit-Limit":{"description":"Requests allowed in the current window or billing period.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix timestamp when the window or period resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Lookup"}}}},"400":{"description":"Invalid address, non-routable address, or unsupported language.","content":{"application/problem\u002Bjson":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The address or network is blocked for abuse.","content":{"application/problem\u002Bjson":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit or monthly quota exceeded.","content":{"application/problem\u002Bjson":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"503":{"description":"Geolocation databases are not loaded yet.","content":{"application/problem\u002Bjson":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/{ip}":{"get":{"tags":["Lookup"],"summary":"Look up any IP","description":"Returns the full record for an IPv4 or IPv6 address.","operationId":"getIp","parameters":[{"name":"ip","in":"path","required":true,"description":"IPv4 or IPv6 address, e.g. 8.8.8.8 or 2001:4860:4860::8888.","schema":{"type":"string"}},{"name":"fields","in":"query","description":"Comma-separated dotted paths to keep, e.g. ip,location.country.name. Everything else is omitted.","schema":{"type":"string"}},{"name":"lang","in":"query","description":"Language for place names.","schema":{"type":"string","enum":["en","de","es","fr","ja","pt-BR","ru","zh-CN"],"default":"en"}}],"responses":{"200":{"description":"The lookup result.","headers":{"X-RateLimit-Limit":{"description":"Requests allowed in the current window or billing period.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix timestamp when the window or period resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Lookup"}}}},"400":{"description":"Invalid address, non-routable address, or unsupported language.","content":{"application/problem\u002Bjson":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"The address or network is blocked for abuse.","content":{"application/problem\u002Bjson":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit or monthly quota exceeded.","content":{"application/problem\u002Bjson":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"503":{"description":"Geolocation databases are not loaded yet.","content":{"application/problem\u002Bjson":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/batch":{"post":{"tags":["Lookup"],"summary":"Look up many addresses","description":"Paid plans only, and the key must carry the batch.lookup scope. Up to 100 addresses per request; each address consumes one unit of the monthly quota. A bad address fails only its own entry.","operationId":"batchLookup","security":[{"ApiKeyHeader":[]}],"parameters":[{"name":"fields","in":"query","description":"Comma-separated dotted paths to keep, e.g. ip,location.country.name. Everything else is omitted.","schema":{"type":"string"}},{"name":"lang","in":"query","description":"Language for place names.","schema":{"type":"string","enum":["en","de","es","fr","ja","pt-BR","ru","zh-CN"],"default":"en"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchRequest"}}}},"responses":{"200":{"description":"Per-address results, in request order.","headers":{"X-RateLimit-Limit":{"description":"Requests allowed in the current window or billing period.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix timestamp when the window or period resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchResponse"}}}},"400":{"description":"Empty batch, more than 100 addresses, or an unsupported language.","content":{"application/problem\u002Bjson":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"No API key supplied.","content":{"application/problem\u002Bjson":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Free plan, or the key lacks the batch.lookup scope.","content":{"application/problem\u002Bjson":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Monthly quota would be exceeded.","content":{"application/problem\u002Bjson":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/ip":{"get":{"tags":["Lookup"],"summary":"The caller\u0027s IP only","description":"Permanent ipify-compatible alias. The response shape is frozen and will never change. Supports format=json (default), text, and jsonp.","operationId":"getOwnIpPlain","parameters":[{"name":"format","in":"query","description":"Response format.","schema":{"type":"string","enum":["json","text","jsonp"],"default":"json"}},{"name":"callback","in":"query","description":"JavaScript function name; required when format=jsonp.","schema":{"type":"string"}}],"responses":{"200":{"description":"The caller\u0027s IP address.","content":{"application/json":{"schema":{"type":"object","properties":{"ip":{"type":"string"}}}},"text/plain":{"schema":{"type":"string"}}}}}}},"/api/v1/health":{"get":{"tags":["Service"],"summary":"Service health","description":"Always 200 while the process is alive; dependency state is reported in the body.","operationId":"getHealth","responses":{"200":{"description":"Service status.","headers":{"X-RateLimit-Limit":{"description":"Requests allowed in the current window or billing period.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests remaining.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix timestamp when the window or period resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Health"}}}}}}}},"components":{"securitySchemes":{"ApiKeyHeader":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Your API key, e.g. ipt_live_\u2026 . Also accepted as an Authorization: Bearer header or a ?key= query parameter."}},"schemas":{"Lookup":{"type":"object","properties":{"ip":{"type":"string","description":"The address that was looked up, normalised."},"type":{"type":"string","enum":["IPv4","IPv6"]},"location":{"$ref":"#/components/schemas/Location"},"connection":{"$ref":"#/components/schemas/Connection"},"privacy":{"$ref":"#/components/schemas/Privacy"},"ipInfo":{"$ref":"#/components/schemas/IpInfo"},"hostname":{"type":"string","description":"Reverse DNS name, when one resolves."},"meta":{"$ref":"#/components/schemas/Meta"}}},"Location":{"type":"object","properties":{"continent":{"type":"string","description":"Continent name."},"country":{"$ref":"#/components/schemas/Country"},"region":{"type":"object","properties":{"name":{"type":"string","description":"Subdivision name, e.g. New South Wales."},"code":{"type":"string","description":"ISO subdivision code, e.g. NSW."}}},"city":{"type":"string","description":"City name."},"postalCode":{"type":"string","description":"Postal or ZIP code."},"latitude":{"type":"number","description":"Approximate latitude."},"longitude":{"type":"number","description":"Approximate longitude."},"accuracyRadius":{"type":"integer","description":"Radius in km the coordinates are accurate to."},"timezone":{"type":"object","properties":{"id":{"type":"string","description":"IANA timezone id, e.g. Australia/Sydney."},"abbreviation":{"type":"string","description":"Short name in effect now, e.g. AEST."},"utcOffset":{"type":"string","description":"Current offset, e.g. \u002B10:00."},"currentTime":{"type":"string","description":"Current local time, ISO 8601."}}}}},"Country":{"type":"object","properties":{"name":{"type":"string","description":"Country name."},"code":{"type":"string","description":"ISO 3166-1 alpha-2, e.g. AU."},"code3":{"type":"string","description":"ISO 3166-1 alpha-3, e.g. AUS."},"capital":{"type":"string","description":"Capital city."},"phoneCode":{"type":"string","description":"International dialling prefix, e.g. \u002B61."},"currency":{"type":"object","properties":{"code":{"type":"string","description":"ISO 4217 code, e.g. AUD."},"symbol":{"type":"string","description":"Currency symbol."}}},"flag":{"type":"string","description":"Flag emoji."}}},"Connection":{"type":"object","properties":{"asn":{"type":"integer","description":"Autonomous system number."},"as":{"type":"string","description":"Autonomous system, e.g. AS15169."},"network":{"type":"string","description":"Announced CIDR block containing the address."},"isp":{"type":"string","description":"Network operator."},"org":{"type":"string","description":"Organisation that owns the AS."},"type":{"type":"string","description":"\u0022Hosting\u0022 when the address belongs to a datacenter; otherwise absent."}}},"Privacy":{"type":"object","properties":{"vpn":{"type":"boolean","description":"Reserved; currently always false."},"proxy":{"type":"boolean","description":"Reserved; currently always false."},"tor":{"type":"boolean","description":"Reserved; currently always false."},"hosting":{"type":"boolean","description":"True when the address belongs to a known hosting provider."}},"description":"VPN, proxy, and Tor detection require a commercial anonymity database and are not yet populated."},"IpInfo":{"type":"object","properties":{"isPublic":{"type":"boolean","description":"Publicly routable."},"isPrivate":{"type":"boolean","description":"RFC 1918, loopback, or link-local."},"isReserved":{"type":"boolean","description":"Reserved or special-use, e.g. TEST-NET or CGNAT."}}},"Meta":{"type":"object","properties":{"databaseVersion":{"type":"string","description":"GeoLite2 build date, e.g. 2026-07-24."},"lookupTimeMs":{"type":"integer","description":"Server-side lookup time in milliseconds."}}},"BatchRequest":{"type":"object","required":["ips"],"properties":{"ips":{"type":"array","maxItems":100,"items":{"type":"string"},"description":"Between 1 and 100 IPv4 or IPv6 addresses."}}},"BatchResponse":{"type":"object","properties":{"count":{"type":"integer","description":"Number of entries returned."},"results":{"type":"array","items":{"$ref":"#/components/schemas/BatchItem"}}}},"BatchItem":{"type":"object","properties":{"ip":{"type":"string","description":"The address as supplied."},"result":{"$ref":"#/components/schemas/Lookup"},"error":{"type":"string","description":"Error slug when this entry failed, e.g. invalid-ip."},"message":{"type":"string","description":"Human-readable reason when this entry failed."}},"description":"Either result, or the error/message pair \u2014 never both."},"Health":{"type":"object","properties":{"status":{"type":"string","description":"\u0022healthy\u0022 while the process is alive."},"version":{"type":"string","description":"API version."},"geoData":{"type":"string","description":"\u0022ready\u0022 or \u0022unavailable\u0022."},"database":{"type":"string","description":"\u0022connected\u0022 or \u0022unreachable\u0022."},"redis":{"type":"string","description":"\u0022connected\u0022, \u0022unreachable\u0022, or \u0022not configured\u0022."}}},"Problem":{"type":"object","properties":{"type":{"type":"string","description":"Stable URL identifying the error, e.g. \u2026/docs/errors#invalid-ip."},"title":{"type":"string","description":"Short summary."},"status":{"type":"integer","description":"HTTP status code."},"detail":{"type":"string","description":"Human-readable explanation."}},"description":"RFC 7807 problem details. Every error uses this shape."}}}}