API Documentation
One simple, fast REST API for IP geolocation, fraud scoring, WHOIS, DNS propagation, hostname resolution and email verification — all processed in-house, nothing shared with third parties.
curl "https://ipaddress.to/api/lookup/8.8.8.8"
Overview
All endpoints are plain GET requests returning JSON over HTTPS — no authentication, tokens or signup. Every response includes a success boolean; most include duration_ms (server processing time) and a cached flag when served from the short-lived server-side cache. All lookups run against our own local geolocation, ASN, VPN-provider and threat-intelligence databases, so your queries never leave our infrastructure.
/api/dns streams NDJSON — one JSON object per line.Access-Control-Allow-Origin: * — call it straight from the browser.IP Lookup
Geolocation and network intelligence for any IP address or hostname: continent, country, region, city, coordinates, timezone, currency, ASN and organisation, plus connection flags (is_vpn, is_proxy, is_tor, is_hosting). Use my as the address to look up the calling IP.
8.8.8.8, google.com). Use my for your own IP.curl "https://ipaddress.to/api/lookup/8.8.8.8"
const res = await fetch('https://ipaddress.to/api/lookup/8.8.8.8'); const data = await res.json(); console.log(data);
import requests data = requests.get('https://ipaddress.to/api/lookup/8.8.8.8').json() print(data)
$data = json_decode(
file_get_contents('https://ipaddress.to/api/lookup/8.8.8.8'),
true
);
print_r($data);using var client = new HttpClient(); var json = await client.GetStringAsync("https://ipaddress.to/api/lookup/8.8.8.8"); Console.WriteLine(json);
resp, _ := http.Get("https://ipaddress.to/api/lookup/8.8.8.8") body, _ := io.ReadAll(resp.Body) fmt.Println(string(body))
require 'net/http' require 'json' data = JSON.parse(Net::HTTP.get(URI('https://ipaddress.to/api/lookup/8.8.8.8'))) puts data
HttpClient client = HttpClient.newHttpClient();
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://ipaddress.to/api/lookup/8.8.8.8")).build();
String body = client.send(req, BodyHandlers.ofString()).body();
System.out.println(body);use LWP::Simple; use JSON; my $data = decode_json(get('https://ipaddress.to/api/lookup/8.8.8.8')); print $data;
let body = reqwest::get("https://ipaddress.to/api/lookup/8.8.8.8") .await?.text().await?; println!("{}", body);
{
"success": true,
"ip": "8.8.8.8",
"type": "IPv4",
"rdns": "dns.google",
"location": {
"continent": "NA",
"continent_name": "North America",
"country": "United States",
"country_code": "US",
"state": "California",
"city": "Mountain View",
"latitude": 37.422,
"longitude": -122.085,
"timezone": "America/Los_Angeles",
"is_eu_member": false,
"calling_code": "1",
"capital": "Washington, D.C.",
"languages": "English",
"country_tld": ".us",
"currency": { "code": "USD", "name": "US Dollar" }
},
"asn": {
"asn": 15169,
"descr": "Google LLC",
"country": "US",
"org": "Google LLC"
},
"company": { "name": "Google LLC", "domain": null, "type": null },
"is_vpn": false,
"is_proxy": false,
"is_tor": false,
"is_hosting": false,
"vpn_provider": null,
"duration_ms": 12
}WHOIS
Registration data for a domain or IP address via RDAP with classic WHOIS fallback. Domains return registrar, creation/expiry dates, status codes, nameservers and abuse contacts; IPs return network range, RIR and holder details. Subdomains are automatically stripped to the registrable root domain.
google.com, 1.1.1.1).curl "https://ipaddress.to/api/whois/google.com"
const res = await fetch('https://ipaddress.to/api/whois/google.com'); const data = await res.json(); console.log(data);
import requests data = requests.get('https://ipaddress.to/api/whois/google.com').json() print(data)
$data = json_decode(
file_get_contents('https://ipaddress.to/api/whois/google.com'),
true
);
print_r($data);using var client = new HttpClient(); var json = await client.GetStringAsync("https://ipaddress.to/api/whois/google.com"); Console.WriteLine(json);
resp, _ := http.Get("https://ipaddress.to/api/whois/google.com") body, _ := io.ReadAll(resp.Body) fmt.Println(string(body))
require 'net/http' require 'json' data = JSON.parse(Net::HTTP.get(URI('https://ipaddress.to/api/whois/google.com'))) puts data
HttpClient client = HttpClient.newHttpClient();
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://ipaddress.to/api/whois/google.com")).build();
String body = client.send(req, BodyHandlers.ofString()).body();
System.out.println(body);use LWP::Simple; use JSON; my $data = decode_json(get('https://ipaddress.to/api/whois/google.com')); print $data;
let body = reqwest::get("https://ipaddress.to/api/whois/google.com") .await?.text().await?; println!("{}", body);
{
"success": true,
"query": "google.com",
"type": "domain",
"found": true,
"parsed": {
"domain_name": "GOOGLE.COM",
"registrar": "MarkMonitor Inc.",
"registrar_url": "https://rdap.markmonitor.com/rdap/domain/GOOGLE.COM",
"registrar_iana_id": "292",
"creation_date": "1997-09-15T04:00:00Z",
"expiry_date": "2028-09-14T04:00:00Z",
"updated_date": "2026-07-01T02:29:57Z",
"status": ["client delete prohibited", "client transfer prohibited"], // … 6 in total
"nameservers": ["ns1.google.com", "ns2.google.com"], // … 4 in total
"dnssec": "unsigned",
"abuse_email": "[email protected]",
"abuse_phone": "tel:+1.2086851750"
},
"raw": "… full RDAP/WHOIS response as a string …",
"source": "rdap",
"duration_ms": 342
}The raw field contains the complete unparsed RDAP/WHOIS payload; source is rdap or whois depending on which lookup succeeded.
Hostname Resolution
Resolve a hostname to its A (IPv4), AAAA (IPv6) and CNAME records, with automatic reverse-DNS lookups for every resolved IP.
github.com).curl "https://ipaddress.to/api/resolve/github.com"
const res = await fetch('https://ipaddress.to/api/resolve/github.com'); const data = await res.json(); console.log(data);
import requests data = requests.get('https://ipaddress.to/api/resolve/github.com').json() print(data)
$data = json_decode(
file_get_contents('https://ipaddress.to/api/resolve/github.com'),
true
);
print_r($data);using var client = new HttpClient(); var json = await client.GetStringAsync("https://ipaddress.to/api/resolve/github.com"); Console.WriteLine(json);
resp, _ := http.Get("https://ipaddress.to/api/resolve/github.com") body, _ := io.ReadAll(resp.Body) fmt.Println(string(body))
require 'net/http' require 'json' data = JSON.parse(Net::HTTP.get(URI('https://ipaddress.to/api/resolve/github.com'))) puts data
HttpClient client = HttpClient.newHttpClient();
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://ipaddress.to/api/resolve/github.com")).build();
String body = client.send(req, BodyHandlers.ofString()).body();
System.out.println(body);use LWP::Simple; use JSON; my $data = decode_json(get('https://ipaddress.to/api/resolve/github.com')); print $data;
let body = reqwest::get("https://ipaddress.to/api/resolve/github.com") .await?.text().await?; println!("{}", body);
{
"success": true,
"hostname": "github.com",
"a": ["140.82.113.4"],
"aaaa": [],
"cname": [],
"reverse": {
"140.82.113.4": "lb-140-82-113-4-iad.github.com"
},
"total_ips": 1,
"has_ipv4": true,
"has_ipv6": false,
"duration_ms": 87
}DNS Propagation
Query a DNS record against 32 public resolvers around the world and watch propagation in real time. Results are streamed as NDJSON — newline-delimited JSON, one object per line — so you can render each server's answer as it arrives. Pass ?server=IP to query a single resolver and get one plain JSON object instead.
A, AAAA, CNAME, MX, NS, TXT, SOA, PTR, SRV, CAA (case-insensitive).example.com).?server=8.8.8.8. Returns a single JSON object instead of a stream.curl -N "https://ipaddress.to/api/dns/a/example.com"
const res = await fetch('https://ipaddress.to/api/dns/a/example.com'); const reader = res.body.getReader(); // read the stream — each line is one JSON object
import requests, json r = requests.get('https://ipaddress.to/api/dns/a/example.com', stream=True) for line in r.iter_lines(): print(json.loads(line))
{"type":"start","domain":"example.com","recordType":"A","total":32}
{"type":"result","index":0,"result":{"status":"ok","value":"104.20.23.154","ttl":133,"elapsed":71,"raw":[{"name":"example.com","ttl":133,"class":"IN","type":"A","value":"104.20.23.154"}]}}
// … one "result" line per server (32 total), in server-list order …
{"type":"done","summary":{"successful":29,"failed":3,"total":32}}The stream opens with a start object, emits one result object per server (with index, answer value, ttl, latency elapsed in ms and the raw record set), and closes with a done summary.
{
"success": true,
"domain": "example.com",
"type": "A",
"server": { "ip": "8.8.8.8", "name": "New York", "country": "US", "provider": "Google" },
"result": {
"status": "ok",
"value": "104.20.23.154",
"ttl": 300,
"elapsed": 41,
"raw": [
{ "name": "example.com", "ttl": 300, "class": "IN", "type": "A", "value": "104.20.23.154" },
{ "name": "example.com", "ttl": 300, "class": "IN", "type": "A", "value": "172.66.147.243" }
]
}
}IP Fraud Score
A 0–100 risk score for any IP, built from threat blocklists, VPN/proxy/Tor detection, ASN classification, reverse-DNS heuristics and bot signals. risk is one of low, medium, high or critical, and factors explains exactly which signals moved the score. Known crawler IPs (Googlebot, Ahrefs, …) are verified via forward-confirmed reverse DNS and flagged rather than penalised.
my for your own IP.curl "https://ipaddress.to/api/score/8.8.8.8"
const res = await fetch('https://ipaddress.to/api/score/8.8.8.8'); const data = await res.json(); console.log(data);
import requests data = requests.get('https://ipaddress.to/api/score/8.8.8.8').json() print(data)
$data = json_decode(
file_get_contents('https://ipaddress.to/api/score/8.8.8.8'),
true
);
print_r($data);using var client = new HttpClient(); var json = await client.GetStringAsync("https://ipaddress.to/api/score/8.8.8.8"); Console.WriteLine(json);
resp, _ := http.Get("https://ipaddress.to/api/score/8.8.8.8") body, _ := io.ReadAll(resp.Body) fmt.Println(string(body))
require 'net/http' require 'json' data = JSON.parse(Net::HTTP.get(URI('https://ipaddress.to/api/score/8.8.8.8'))) puts data
HttpClient client = HttpClient.newHttpClient();
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://ipaddress.to/api/score/8.8.8.8")).build();
String body = client.send(req, BodyHandlers.ofString()).body();
System.out.println(body);use LWP::Simple; use JSON; my $data = decode_json(get('https://ipaddress.to/api/score/8.8.8.8')); print $data;
let body = reqwest::get("https://ipaddress.to/api/score/8.8.8.8") .await?.text().await?; println!("{}", body);
{
"success": true,
"ip": "8.8.8.8",
"target_type": "ip",
"score": 3,
"risk": "low",
"score_breakdown": { "threat": 0, "anonymity": 0, "infrastructure": 25, "reputation": 0, "bot": 0 },
"vpn_provider": null,
"rdns": "dns.google",
"ip_version": 4,
"location": { "country": "United States", "country_code": "US", "city": "Mountain View" },
"asn": { "asn": 15169, "org": "Google LLC" },
"company": { "name": "Google LLC", "type": "trusted" },
"checks": {
"trusted_org": true,
"has_rdns": true,
"is_bot": false,
"vpn_detected": false,
"tor_exit": false,
"commercial_proxy": false,
"blocklist_listed": false,
"blocklist_count": 0,
"hosting_asn": true,
"asn_type": "hosting",
"high_risk_country": false
// … 24 checks in total
},
"factors": [
{ "name": "Trusted Organization", "impact": "positive", "detail": "IP belongs to Google infrastructure (verified via ASN + rDNS)" },
{ "name": "Datacenter / Hosting", "impact": "medium", "detail": "AS15169 (Google LLC) is hosting/datacenter infrastructure" }
],
"duration_ms": 60
}Email Check
A 0–100 trust score for any email address or domain: MX records, SPF and DMARC policies, disposable/throwaway detection against a database of 200k+ burner domains, role-based mailbox detection and free-provider classification. Works with a bare domain too — omit the local part to score the domain itself.
[email protected]) or domain (e.g. mailinator.com). Omit entirely to get a random sample of known disposable domains.curl "https://ipaddress.to/api/email/[email protected]"
const res = await fetch('https://ipaddress.to/api/email/[email protected]'); const data = await res.json(); console.log(data);
import requests data = requests.get('https://ipaddress.to/api/email/[email protected]').json() print(data)
$data = json_decode(
file_get_contents('https://ipaddress.to/api/email/[email protected]'),
true
);
print_r($data);using var client = new HttpClient(); var json = await client.GetStringAsync("https://ipaddress.to/api/email/[email protected]"); Console.WriteLine(json);
resp, _ := http.Get("https://ipaddress.to/api/email/[email protected]") body, _ := io.ReadAll(resp.Body) fmt.Println(string(body))
require 'net/http' require 'json' data = JSON.parse(Net::HTTP.get(URI('https://ipaddress.to/api/email/[email protected]'))) puts data
HttpClient client = HttpClient.newHttpClient();
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://ipaddress.to/api/email/[email protected]")).build();
String body = client.send(req, BodyHandlers.ofString()).body();
System.out.println(body);use LWP::Simple; use JSON; my $data = decode_json(get('https://ipaddress.to/api/email/[email protected]')); print $data;
let body = reqwest::get("https://ipaddress.to/api/email/[email protected]") .await?.text().await?; println!("{}", body);
{
"success": true,
"query": "[email protected]",
"email": "[email protected]",
"domain": "gmail.com",
"target_type": "email",
"score": 90,
"rating": "trusted",
"score_breakdown": { "deliverability": 40, "authentication": 40, "reputation": 20 },
"checks": {
"has_mx": true,
"spf": true,
"dmarc": true,
"resolves": true,
"disposable": false,
"role_based": true,
"free_provider": true
},
"is_disposable": false,
"factors": [
{ "name": "Mail Server (MX)", "impact": "positive", "detail": "Domain has 5 MX records — it can receive email" },
{ "name": "Role-based Address", "impact": "negative", "detail": "\"test@\" is a role/group mailbox, not an individual person" }
// … one entry per signal
],
"duration_ms": 168
}Discovery Endpoint
GET https://ipaddress.to/api/ returns a machine-readable index of every endpoint — handy for tooling and quick reference from the terminal. (Browsers requesting HTML are redirected to this page instead.)
{
"name": "IPAddress.to API",
"version": "1.1",
"docs": "https://ipaddress.to/api/docs/",
"endpoints": [
{
"path": "/api/lookup/{ip_or_hostname}",
"method": "GET",
"description": "Geolocation and network info for an IP address or hostname…",
"examples": ["/api/lookup/8.8.8.8", "/api/lookup/google.com", "/api/lookup/my"]
}
// … one entry per endpoint
]
}Errors & Caching
Failed lookups return a JSON body with success: false and a human-readable error message — always branch on the success field rather than the HTTP status alone.
{
"success": false,
"error": "Invalid IP or unresolvable hostname",
"query": "999.1.1.1"
}Cache-Control headers; cached responses include "cached": true. If you need the same answer repeatedly, cache it on your side too.Rate Limits & Fair Use
There are currently no hard per-key quotas — the API is free for reasonable, fair use. Please be a good citizen: cache results, avoid tight polling loops, and identify your application with a descriptive User-Agent header. Abusive traffic (bulk scraping, sustained high-volume automation) may be throttled or blocked at the edge without notice. Need sustained high volume? Get in touch.
Internal / Experimental Endpoints
The browser proxy-detection widget on the homepage is powered by three additional endpoints: POST /api/detect/fingerprint (HTTP-layer request fingerprint), GET /api/detect/latency (RTT probe) and POST /api/detect/score (combined proxy/VPN score from client + server signals). They are internal: request/response shapes are tightly coupled to the widget and may change at any time without notice — build against the stable endpoints above instead.