Build on My IP Address
A plain-text IP for scripts, a JSON API for apps, and an OpenAPI spec for everything in between. No account needed for anonymous use.
Quickstart
curl-friendly by default — a plain user agent like curl or PowerShell hitting the homepage gets the bare IP back, no flags needed.
curl https://my-ip-address.in/ipcurl https://my-ip-address.in/ip.jsoncurl "https://my-ip-address.in/api/v1/lookup?q=1.1.1.1"Examples in your language#
Every example asks for the same thing: the network and country behind 1.1.1.1. The response is JSON, so the calls differ only in how each language makes a request and checks the result.
cURL
curl https://my-ip-address.in/ip
curl https://my-ip-address.in/ip.json
curl "https://my-ip-address.in/api/v1/lookup?q=1.1.1.1"
curl -H "x-api-key: YOUR_KEY" "https://my-ip-address.in/api/v1/lookup?q=1.1.1.1&whois=1"JavaScript
const res = await fetch("https://my-ip-address.in/api/v1/lookup?q=1.1.1.1");
const body = await res.json();
if (!res.ok) throw new Error(body.error.message);
console.log(body.intel.network.asn, body.intel.location.country);Python
import requests
r = requests.get("https://my-ip-address.in/api/v1/lookup", params={"q": "1.1.1.1"}, timeout=10)
r.raise_for_status()
intel = r.json()["intel"]
print(intel["network"]["asn"], intel["location"]["country"])PHP
<?php
$ch = curl_init("https://my-ip-address.in/api/v1/lookup?q=1.1.1.1");
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 10]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
$data = json_decode($body, true);
if ($status !== 200) {
exit($data["error"]["message"]);
}
echo $data["intel"]["network"]["asn"], " ", $data["intel"]["location"]["country"], "\n";Rate limits
Anonymous requests are limited per hashed IP: 60 a minute, 10 a minute for the heaviest endpoints (bulk lookup and the full blocklist scan), and 5 for the breach check. Send an x-api-key header for a limit of 600. Self-serve keys are on the way; ask in the meantime.
Every response carries
Endpoints
/ipYour IP as plain text/ip.jsonYour IP as JSON/api/v1/ipFull intel for the caller's IP/api/v1/lookupLook up an IP, domain or URL/api/v1/lookup/bulkBulk lookup (up to 100 IPs)/api/v1/blacklistDNSBL check (quick ≈ 12 lists, full = 50+ lists)/api/v1/dnsDNS records or reverse DNS/api/v1/headersEcho the request headers your client sent/api/v1/breach/emailEmail breach lookup (Have I Been Pwned)Responses#
Everything under /api/v1 returns JSON in UTF-8 with cache-control: no-store, and allows requests from any origin (GET, POST and OPTIONS). Field names are stable within v1. New fields can appear, so ignore ones you do not know.
GET https://my-ip-address.in/api/v1/ip?basic=1
{ "ip": "203.0.113.42", "version": 4 }GET https://my-ip-address.in/api/v1/lookup?q=1.1.1.1
{
"query": { "kind": "ipv4", "value": "1.1.1.1", "original": "1.1.1.1" },
"intel": {
"ip": "1.1.1.1",
"version": 4,
"scope": "public",
"hostname": "one.one.one.one",
"location": {
"city": "Brisbane", "region": "Queensland", "country": "Australia",
"countryCode": "AU", "latitude": -27.4679, "longitude": 153.0281,
"timezone": "Australia/Brisbane", "accuracyKm": 50
},
"network": { "asn": 13335, "isp": "Cloudflare, Inc.", "domain": "cloudflare.com" },
"flags": { "vpn": null, "proxy": null, "tor": null, "hosting": null, "mobile": null, "anycast": null },
"connectionType": "unknown",
"threatScore": 0,
"provider": "ipwhois.io",
"cached": true
},
"whois": null
}query- What was asked, and how it was read:
ipv4,ipv6,domainorurl. intel- The result for the address.
flagsvalues aretrue,falseornullwhen the provider does not report that flag:nullmeans unknown, not false. resolved- For a domain or URL: the IPv4 and IPv6 addresses it resolved to. Only the first is looked up.
whois- Registry data for the address when you pass
whois=1, otherwisenull. cached- Whether the lookup was served from a server-side cache. Results are cached for an hour.
GET https://my-ip-address.in/api/v1/dns?name=example.com&type=A
{ "name": "example.com", "records": { "A": { "records": [ { "value": "104.20.23.154", "ttl": 300 } ] } } }
GET https://my-ip-address.in/api/v1/dns?ip=8.8.8.8
{ "ip": "8.8.8.8", "ptr": "dns.google" }A lookup for a domain with no A or AAAA records returns status 404 with "intel": null in a normal response body, not an error object. Your code should handle it as an ordinary outcome.
Errors#
Every failure is a JSON object with a stable machine-readable code and a human-readable message, with a matching HTTP status. Branch on the code, and show the message to people.
HTTP/1.1 400 Bad Request
content-type: application/json; charset=utf-8
{ "error": { "code": "invalid_query", "message": "That doesn't look like an IP, domain, or URL." } }| Status | Code | When it happens |
|---|---|---|
| 400 | invalid_query, invalid_ip, invalid_name, invalid_type, invalid_body, invalid_email, no_ips | A parameter is missing or malformed. The message says which |
| 400 | not_public | The blocklist check was given a private or reserved address |
| 403 | bot_check_failed | Bot protection is switched on for this endpoint, and the token was missing or wrong |
| 422 | no_client_ip | A call that answers for the caller could not determine the caller's address |
| 429 | rate_limited | The limit for this endpoint was reached. See Retry-After |
| 500 | internal_error | Something failed on our side. Retry later |
| 501 | not_configured | The endpoint needs a feature this deployment does not have enabled |
| 502, 503 | upstream_error, upstream_busy | A third-party service we depend on failed or is busy. Retry after a few seconds |
Rate limits in detail#
| Caller | Limit | Applies to |
|---|---|---|
| Anonymous | 60 | Address, lookup, DNS, headers and the quick blocklist check |
| Anonymous, heavy | 10 | Bulk lookup and the full blocklist scan |
| Anonymous, breach | 5 | The email breach check |
| With an API key | 600 | Every endpoint |
Anonymous callers are counted per hashed IP address, so nothing identifying is stored. A key is sent as x-api-key: KEY or Authorization: Bearer KEY.
- Every response carries
RateLimit-Limit,RateLimit-RemainingandRateLimit-Reset, the last in seconds until the window resets. - A
429also carriesRetry-After, in seconds. Wait that long and retry once, do not loop. - Keys are not self-serve yet. To request one, get in touch with what you are building.
Usage rules#
- Be reasonable. Cache what you fetch and do not ask for the same address repeatedly. Results are already cached for an hour on our side.
- Do not attack, scan or harass anyone with the service, and do not try to get around its limits or access controls.
- Do not scrape or resell its output at scale without permission.
- Send a `User-Agent` that names your application. If something goes wrong, we can tell your client from a whole network.
- Treat every field as an estimate. Location, ISP, ASN and VPN, proxy and Tor flags come from third-party data and heuristics.
OpenAPI
Every endpoint below, typed, at /api/v1/openapi.json — import it into Postman, Insomnia, or your codegen of choice.
Open the OpenAPI specEstimates, not certainties: location, ISP, and VPN/proxy/Tor flags come from third-party data and heuristics, and can be wrong. See the Terms before building anything that depends on them being right.