Skip to content
Developers

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/ip
curl https://my-ip-address.in/ip.json
curl "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

The first two answer for you: your own address, as text and as JSON
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

Browser or Node 18 and later. CORS is open, so it works from a web page
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

Uses the requests library
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

Uses the curl extension
<?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

RateLimit-LimitRateLimit-RemainingRateLimit-Reset

Endpoints

get/ipYour IP as plain text
get/ip.jsonYour IP as JSON
get/api/v1/ipFull intel for the caller's IP
get/api/v1/lookupLook up an IP, domain or URL
post/api/v1/lookup/bulkBulk lookup (up to 100 IPs)
get/api/v1/blacklistDNSBL check (quick ≈ 12 lists, full = 50+ lists)
get/api/v1/dnsDNS records or reverse DNS
get/api/v1/headersEcho the request headers your client sent
post/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.

The cheapest call: just the caller's address and family
GET https://my-ip-address.in/api/v1/ip?basic=1

{ "ip": "203.0.113.42", "version": 4 }
Abridged. The values come from a third-party provider and change; the shape does not
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, domain or url.
intel
The result for the address. flags values are true, false or null when the provider does not report that flag: null means 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, otherwise null.
cached
Whether the lookup was served from a server-side cache. Results are cached for an hour.
DNS lookups: forward records, and reverse (PTR) for an address
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.

An error response
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." } }
Error codes
StatusCodeWhen it happens
400invalid_query, invalid_ip, invalid_name, invalid_type, invalid_body, invalid_email, no_ipsA parameter is missing or malformed. The message says which
400not_publicThe blocklist check was given a private or reserved address
403bot_check_failedBot protection is switched on for this endpoint, and the token was missing or wrong
422no_client_ipA call that answers for the caller could not determine the caller's address
429rate_limitedThe limit for this endpoint was reached. See Retry-After
500internal_errorSomething failed on our side. Retry later
501not_configuredThe endpoint needs a feature this deployment does not have enabled
502, 503upstream_error, upstream_busyA third-party service we depend on failed or is busy. Retry after a few seconds

Rate limits in detail#

Requests per minute
CallerLimitApplies to
Anonymous60Address, lookup, DNS, headers and the quick blocklist check
Anonymous, heavy10Bulk lookup and the full blocklist scan
Anonymous, breach5The email breach check
With an API key600Every 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-Remaining and RateLimit-Reset, the last in seconds until the window resets.
  • A 429 also carries Retry-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 spec

Estimates, 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.