Public REST API
Every diagnostic tool on the site is also a JSON endpoint. Same data the UI shows, but scriptable.
Quickstart
Three steps from zero to a JSON response.
- Get a key. Sign in or create a free account, then provision a key in My Account. Free tier is 100 calls/day — no billing required. Paid plans raise it; see pricing.
-
Call any endpoint.
$ curl https://internettimes.com/api/v1/dns/google.com \ -H "Authorization: Bearer YOUR_KEY" -
Get JSON back. Every endpoint returns
application/jsonwith consistent error shape.
Authentication
Two ways to pass a key. Header is preferred for production; the query parameter is OK for ad-hoc testing.
Bearer header (preferred)
Authorization: Bearer YOUR_API_KEY
Query parameter (testing only)
https://internettimes.com/api/v1/dns/google.com?key=YOUR_API_KEY
Get a key
Endpoints (v1)
All endpoints share the same base: https://internettimes.com/api/v1
Response envelope
Every successful response wraps the result in data and adds a meta block with your current rate-limit state. Errors replace both with a single error object.
{
"data": "…endpoint-specific result…",
"meta": {
"rate_limit": 100,
"rate_limit_used": 13,
"tool": "domain-age",
"subject": "example.com"
}
}
?format=md — or send Accept: text/markdown — to any endpoint and you get the same result as a Markdown document instead of JSON. Handy for piping into an LLM prompt or a runbook.
Diagnostics
The subject goes in the path: /dns/example.com, /ip-lookup/8.8.8.8. Results are served from the shared cache and refreshed in the background, so data.cached tells you whether you got a stored answer.
| Method | Path | What it returns | Status |
|---|---|---|---|
| GET | /dns/{domain} | A, AAAA, CNAME, MX, NS, TXT and SOA records. | stable |
| GET | /whois/{domain} | Parsed registrar and date fields, plus the raw record with contact details redacted. | stable |
| GET | /domain-age/{domain} | Registration date and the domain’s age. | stable |
| GET | /mx/{domain} | Mail servers with SPF and DMARC posture. | stable |
| GET | /dns-propagation/{domain} | The same query across global resolvers, with an agreement percentage. | stable |
| GET | /reverse-dns/{ip} | PTR record plus forward-confirmed (FCrDNS) verification. | stable |
| GET | /ip-lookup/{ip} | Geolocation, ASN and owning organisation. | stable |
| GET | /ip-blacklist/{ip} | Listing status across 29 active public RBLs. | stable |
| GET | /ssl/{host} | Certificate subject, issuer, SAN list, validity window and chain. | stable |
| GET | /http-headers/{url} | Response headers with a security-headers audit. | stable |
| GET | /http2-http3-test/{host} | Whether the host negotiates HTTP/2 and HTTP/3. | stable |
| GET | /email-validator/{email} | Syntax, MX presence, and role-address / disposable-domain checks. | stable |
| GET | /dkim-lookup/{domain} | DKIM public key for a selector. Append :selector to choose one — example.com:google. Defaults to default and tries common alternates. | stable |
| GET | /dmarc-analyzer/{domain} | DMARC policy with each tag parsed out. | stable |
| GET | /robots-validator/{domain} | robots.txt rules, sitemap references and warnings. | stable |
| GET | /sitemap-validator/{url} | Sitemap structure, URL count and lastmod range. | stable |
| GET | /aeo-checker/{domain} | Answer-engine readiness score (llms.txt, schema, AI-bot posture). | stable |
| GET | /ai-crawler-validator/{domain} | Which AI crawlers robots.txt allows or blocks. | stable |
| GET | /tech-detector/{url} | Detected CMS, framework, CDN and analytics. | stable |
| GET | /subdomain-enum/{domain} | Subdomains discovered from certificate transparency logs. | stable |
| GET | /cloud-region/{ip} | Cloud provider and region an IP belongs to. | stable |
| GET | /audit/{domain} | Every check above rolled into one scored report. | stable |
Account & metadata
| Method | Path | What it returns | Status |
|---|---|---|---|
| GET | /health |
Liveness check. The only endpoint that needs no API key. | stable |
| GET | /me |
The calling key’s owner, plan, subscription and rate-limit state. | stable |
| GET | /tools |
Machine-readable catalogue of every tool and its endpoint. | stable |
| GET | /glossary, /glossary/{slug} |
Networking term definitions — the whole list, or one term. | stable |
| GET | /changelog |
Product changelog entries. | stable |
| GET | /audit-history/{domain} |
What changed on a domain over time, as from→to events. Optional ?days=, capped by your plan's retention. |
pro |
| GET | /monitors |
Domains you have under monitoring, with cadence, next due time and open alert count. | stable |
| POST | /monitors |
Put a domain on a monitoring schedule. JSON body: {"domain": "example.com"}. The domain must already be verified — see below. Capped by your plan. |
stable |
| DELETE | /monitors/{domain_id} |
Stop monitoring a domain. Collected history is kept until it ages out. | stable |
POST /monitors
returns 403 not_verified until that is done. It keeps sweep
budget on domains someone actually owns, and keeps alerts about your
infrastructure from reaching a stranger.
GET /dns/{domain}
Every common record type for a domain.
$ curl https://internettimes.com/api/v1/dns/cloudflare.com \
-H "Authorization: Bearer YOUR_KEY"
{
"data": {
"domain": "cloudflare.com",
"records": {
"A": [
{
"host": "cloudflare.com",
"ip": "104.16.132.229",
"ttl": 300
}
],
"AAAA": [
{
"host": "cloudflare.com",
"ipv6": "2606:4700::6810:84e5",
"ttl": 300
}
],
"MX": [
{
"host": "cloudflare.com",
"target": "mailstream-east.mxrecord.io",
"pri": 10,
"ttl": 300
}
],
"NS": [
{
"host": "cloudflare.com",
"target": "ns3.cloudflare.com",
"ttl": 86400
}
],
"TXT": [
{
"host": "cloudflare.com",
"txt": "v=spf1 include:_spf.mx.cloudflare.net ~all",
"ttl": 300
}
]
},
"queried_at": "2026-08-18T09:41:02+00:00",
"cached": true
},
"meta": {
"rate_limit": 100,
"rate_limit_used": 14
}
}
Record arrays carry whatever fields the record type defines, so A entries have ip while MX entries have target and pri. An empty array means no records of that type.
GET /whois/{domain}
Registrar, dates and status codes parsed into fields, alongside the record they came from.
raw before it is cached or returned — each removed block becomes [contact details redacted]. Technical fields and the registrar’s abuse address are left intact. Do not build against personal data being present; it will not be.
{
"data": {
"domain": "google.com",
"fields": {
"domain_name": [
"GOOGLE.COM"
],
"registrar": [
"MarkMonitor Inc."
],
"created": [
"1997-09-15T04:00:00Z"
],
"updated": [
"2019-09-09T15:39:04Z"
],
"expires": [
"2028-09-14T04:00:00Z"
],
"status": [
"clientTransferProhibited"
],
"name_servers": [
"ns1.google.com",
"ns2.google.com"
]
},
"raw": "Domain Name: GOOGLE.COM\nRegistrar: MarkMonitor Inc.\n[contact details redacted]\nName Server: NS1.GOOGLE.COM",
"queried_at": "2026-08-18T09:41:02+00:00",
"cached": true
},
"meta": {
"rate_limit": 100,
"rate_limit_used": 15
}
}
GET /me
Check which key you are using and how much of today’s allowance is left.
{
"data": {
"user": {
"id": 42,
"email": "[email protected]",
"plan": "free"
},
"plan": {
"slug": "free",
"name": "Free",
"api_calls_per_day": 100,
"max_monitors": 1
},
"subscription": null,
"rate_limit": {
"limit": 100,
"used": 16,
"reset_at": "2026-08-19T00:00:00+00:00"
}
},
"meta": {
"rate_limit": 100,
"rate_limit_used": 16,
"tool": "me",
"subject": null
}
}
Rate limits
Limits are per API key, counted per UTC day and reset at midnight UTC.
| Plan | Calls/day | Monitors | Cost |
|---|---|---|---|
| Free | 100 | 3 | $0 |
| Pro | 50,000 | 50 | $29/mo |
Headers on every authenticated response
X-RateLimit-Limit: 100
X-RateLimit-Used: 14
The same two numbers appear in the response body under meta.rate_limit and meta.rate_limit_used. GET /me additionally returns rate_limit.reset_at.
When you hit a limit
Exhausting the daily allowance returns 429 with Retry-After and the error code rate_limited.
Requests with no key at all are separately throttled to 30 per minute per IP, so an unauthenticated caller can’t probe for valid endpoints. That throttle also answers 429; the fix is to send a key, not to slow down.
Errors
All errors share the same shape. Status codes follow standard HTTP semantics.
{
"error": {
"code": "invalid_domain",
"message": "Provide a domain in the path: /api/v1/dns/example.com"
}
}
message is present on most errors but not all — branch on code, which is always there.
| HTTP | Code | When |
|---|---|---|
| 400 | missing_subject | The path segment after the endpoint was empty. |
| 400 | invalid_domain | The supplied domain is not a valid hostname. |
| 400 | invalid_ip | The supplied IP is malformed. |
| 400 | invalid_subject | The supplied URL or host could not be parsed. |
| 400 | invalid_id | Monitor id missing or not a positive integer. |
| 401 | missing_key | No Authorization: Bearer header and no ?key=. |
| 401 | invalid_key | The key is unknown or has been revoked. |
| 403 | pro_required | The endpoint needs a paid plan (for example /audit-history). |
| 403 | not_verified | Monitoring was requested for a domain whose ownership has not been verified. |
| 403 | plan_limit | Creating this monitor would exceed your plan’s cap. |
| 404 | unknown_route | The path is not /api/v1/…. |
| 404 | unknown_endpoint | No endpoint exists with that name. |
| 404 | not_found | The requested item (such as a glossary term) does not exist. |
| 429 | rate_limited | Daily key allowance exhausted, or the unauthenticated per-IP throttle tripped. |
| 500 | audit_failed | The audit could not be completed. |
| 502 | lookup_failed | The DNS lookup did not return a usable answer. |
| 502 | whois_unreachable | The registry WHOIS server could not be reached. |
SDKs & clients
The API is small enough to call with anything that speaks HTTP. Drop-in snippets:
Node.js (fetch)
const r = await fetch("https://internettimes.com/api/v1/dns/example.com", {
headers: { "Authorization": "Bearer " + process.env.IT_KEY }
});
const data = await r.json();
Python (requests)
import os, requests
r = requests.get(
"https://internettimes.com/api/v1/whois/example.com",
headers={"Authorization": f"Bearer {os.environ['IT_KEY']}"},
timeout=10,
)
data = r.json()
Go (net/http)
req, _ := http.NewRequest("GET", "https://internettimes.com/api/v1/dns/example.com", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("IT_KEY"))
resp, err := http.DefaultClient.Do(req)
An official Node SDK is on the roadmap. Track it on the blog.
Changelog
- 2026-08 WHOIS contact redaction. Registrant, admin and technical contact blocks are stripped from
rawbefore caching./healthnow answers instead of 404ing. - 2026-07 Full tool coverage. Every diagnostic tool is now an endpoint, all served from the shared results engine behind one
data/metaenvelope. Added?format=md,/me,/toolsand/monitors. - 2026-04 v1 stable. /dns and /whois GA. Bearer + query auth.
- 2026-03 v1 beta. Public preview with a free tier.
The same entries are available as JSON from GET https://internettimes.com/api/v1/changelog.
Bug reports and feature requests welcome at /contact.