Copied to clipboard
REST API

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.

No API key required Free for fair use CORS enabled JSON responses IPv4 & IPv6
Base URLhttps://ipaddress.to/api
Quick start
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.

Base URL
https://ipaddress.to/api
Format
JSON (UTF-8). /api/dns streams NDJSON — one JSON object per line.
Auth
None — no API key required.
CORS
Access-Control-Allow-Origin: * — call it straight from the browser.
IPv4 / IPv6
Both fully supported on every endpoint.

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.

GET /api/lookup/{ip_or_hostname} Geolocation, ASN & connection flags
ip_or_hostname required
string
IPv4/IPv6 address or hostname (e.g. 8.8.8.8, google.com). Use my for your own IP.
cURL
curl "https://ipaddress.to/api/lookup/8.8.8.8"
JavaScript
const res = await fetch('https://ipaddress.to/api/lookup/8.8.8.8');
const data = await res.json();
console.log(data);
Python
import requests

data = requests.get('https://ipaddress.to/api/lookup/8.8.8.8').json()
print(data)
PHP
$data = json_decode(
    file_get_contents('https://ipaddress.to/api/lookup/8.8.8.8'),
    true
);
print_r($data);
C#
using var client = new HttpClient();
var json = await client.GetStringAsync("https://ipaddress.to/api/lookup/8.8.8.8");
Console.WriteLine(json);
Go
resp, _ := http.Get("https://ipaddress.to/api/lookup/8.8.8.8")
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
Ruby
require 'net/http'
require 'json'

data = JSON.parse(Net::HTTP.get(URI('https://ipaddress.to/api/lookup/8.8.8.8')))
puts data
Java
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);
Perl
use LWP::Simple;
use JSON;

my $data = decode_json(get('https://ipaddress.to/api/lookup/8.8.8.8'));
print $data;
Rust
let body = reqwest::get("https://ipaddress.to/api/lookup/8.8.8.8")
    .await?.text().await?;
println!("{}", body);
Response
{
  "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.

GET /api/whois/{ip_or_domain} WHOIS / RDAP registration data
ip_or_domain required
string
Domain name or IPv4/IPv6 address (e.g. google.com, 1.1.1.1).
cURL
curl "https://ipaddress.to/api/whois/google.com"
JavaScript
const res = await fetch('https://ipaddress.to/api/whois/google.com');
const data = await res.json();
console.log(data);
Python
import requests

data = requests.get('https://ipaddress.to/api/whois/google.com').json()
print(data)
PHP
$data = json_decode(
    file_get_contents('https://ipaddress.to/api/whois/google.com'),
    true
);
print_r($data);
C#
using var client = new HttpClient();
var json = await client.GetStringAsync("https://ipaddress.to/api/whois/google.com");
Console.WriteLine(json);
Go
resp, _ := http.Get("https://ipaddress.to/api/whois/google.com")
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
Ruby
require 'net/http'
require 'json'

data = JSON.parse(Net::HTTP.get(URI('https://ipaddress.to/api/whois/google.com')))
puts data
Java
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);
Perl
use LWP::Simple;
use JSON;

my $data = decode_json(get('https://ipaddress.to/api/whois/google.com'));
print $data;
Rust
let body = reqwest::get("https://ipaddress.to/api/whois/google.com")
    .await?.text().await?;
println!("{}", body);
Response (domain, trimmed)
{
  "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.

GET /api/resolve/{hostname} A / AAAA / CNAME + reverse DNS
hostname required
string
Hostname to resolve (e.g. github.com).
cURL
curl "https://ipaddress.to/api/resolve/github.com"
JavaScript
const res = await fetch('https://ipaddress.to/api/resolve/github.com');
const data = await res.json();
console.log(data);
Python
import requests

data = requests.get('https://ipaddress.to/api/resolve/github.com').json()
print(data)
PHP
$data = json_decode(
    file_get_contents('https://ipaddress.to/api/resolve/github.com'),
    true
);
print_r($data);
C#
using var client = new HttpClient();
var json = await client.GetStringAsync("https://ipaddress.to/api/resolve/github.com");
Console.WriteLine(json);
Go
resp, _ := http.Get("https://ipaddress.to/api/resolve/github.com")
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
Ruby
require 'net/http'
require 'json'

data = JSON.parse(Net::HTTP.get(URI('https://ipaddress.to/api/resolve/github.com')))
puts data
Java
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);
Perl
use LWP::Simple;
use JSON;

my $data = decode_json(get('https://ipaddress.to/api/resolve/github.com'));
print $data;
Rust
let body = reqwest::get("https://ipaddress.to/api/resolve/github.com")
    .await?.text().await?;
println!("{}", body);
Response
{
  "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.

GET /api/dns/{type}/{domain} Propagation check across 32 global servers (NDJSON stream)
type required
string
Record type: A, AAAA, CNAME, MX, NS, TXT, SOA, PTR, SRV, CAA (case-insensitive).
domain required
string
Domain to query (e.g. example.com).
server optional
string
Query one resolver only, e.g. ?server=8.8.8.8. Returns a single JSON object instead of a stream.
cURL
curl -N "https://ipaddress.to/api/dns/a/example.com"
JavaScript
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
Python
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))
Response — NDJSON stream (trimmed)
{"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.

Response with ?server=8.8.8.8 (single JSON object)
{
  "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.

GET /api/score/{ip_or_hostname} 0–100 fraud / abuse risk score
ip_or_hostname required
string
IPv4/IPv6 address or hostname to score. Use my for your own IP.
cURL
curl "https://ipaddress.to/api/score/8.8.8.8"
JavaScript
const res = await fetch('https://ipaddress.to/api/score/8.8.8.8');
const data = await res.json();
console.log(data);
Python
import requests

data = requests.get('https://ipaddress.to/api/score/8.8.8.8').json()
print(data)
PHP
$data = json_decode(
    file_get_contents('https://ipaddress.to/api/score/8.8.8.8'),
    true
);
print_r($data);
C#
using var client = new HttpClient();
var json = await client.GetStringAsync("https://ipaddress.to/api/score/8.8.8.8");
Console.WriteLine(json);
Go
resp, _ := http.Get("https://ipaddress.to/api/score/8.8.8.8")
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
Ruby
require 'net/http'
require 'json'

data = JSON.parse(Net::HTTP.get(URI('https://ipaddress.to/api/score/8.8.8.8')))
puts data
Java
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);
Perl
use LWP::Simple;
use JSON;

my $data = decode_json(get('https://ipaddress.to/api/score/8.8.8.8'));
print $data;
Rust
let body = reqwest::get("https://ipaddress.to/api/score/8.8.8.8")
    .await?.text().await?;
println!("{}", body);
Response (trimmed)
{
  "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.

GET /api/email/{email_or_domain} MX / SPF / DMARC / disposable score
email_or_domain required
string
Email address (e.g. [email protected]) or domain (e.g. mailinator.com). Omit entirely to get a random sample of known disposable domains.
cURL
curl "https://ipaddress.to/api/email/[email protected]"
JavaScript
const res = await fetch('https://ipaddress.to/api/email/[email protected]');
const data = await res.json();
console.log(data);
Python
import requests

data = requests.get('https://ipaddress.to/api/email/[email protected]').json()
print(data)
PHP
$data = json_decode(
    file_get_contents('https://ipaddress.to/api/email/[email protected]'),
    true
);
print_r($data);
C#
using var client = new HttpClient();
var json = await client.GetStringAsync("https://ipaddress.to/api/email/[email protected]");
Console.WriteLine(json);
Go
resp, _ := http.Get("https://ipaddress.to/api/email/[email protected]")
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
Ruby
require 'net/http'
require 'json'

data = JSON.parse(Net::HTTP.get(URI('https://ipaddress.to/api/email/[email protected]')))
puts data
Java
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);
Perl
use LWP::Simple;
use JSON;

my $data = decode_json(get('https://ipaddress.to/api/email/[email protected]'));
print $data;
Rust
let body = reqwest::get("https://ipaddress.to/api/email/[email protected]")
    .await?.text().await?;
println!("{}", body);
Response (trimmed)
{
  "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.)

GET /api/ (trimmed)
{
  "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.

Error response
{
  "success": false,
  "error": "Invalid IP or unresolvable hostname",
  "query": "999.1.1.1"
}
Responses are cached server-side for a short window (about a minute for lookups) and carry matching 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.