Public REST API

Every diagnostic tool on the site is also a JSON endpoint. Same data the UI shows, but scriptable.

live v1 · stable 29 endpoints 100 calls/day · free tier

Quickstart

Three steps from zero to a JSON response.

  1. 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.
  2. Call any endpoint.
    bash
    $ curl https://internettimes.com/api/v1/dns/google.com \
        -H "Authorization: Bearer YOUR_KEY"
  3. Get JSON back. Every endpoint returns application/json with 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)

bash
Authorization: Bearer YOUR_API_KEY

Query parameter (testing only)

bash
https://internettimes.com/api/v1/dns/google.com?key=YOUR_API_KEY
Don't put real keys in URLs in production. They end up in server logs, browser history, and referrer headers. Use the Bearer header.

Get a key

Open key dashboard  Create account

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.

shape
{
    "data": "…endpoint-specific result…",
    "meta": {
        "rate_limit": 100,
        "rate_limit_used": 13,
        "tool": "domain-age",
        "subject": "example.com"
    }
}
Markdown output. Add ?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.

MethodPathWhat it returnsStatus
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

MethodPathWhat it returnsStatus
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
Monitoring requires verified ownership. Anyone can audit any domain — that data is public. Scheduling repeat sweeps and receiving alerts requires proving you control the domain, via DNS TXT, an HTML file, or a meta tag at /account/domains. 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.

request
$ curl https://internettimes.com/api/v1/dns/cloudflare.com \
    -H "Authorization: Bearer YOUR_KEY"
200 OK
{
    "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.

Contact details are redacted. Registrant, admin and technical contact blocks are stripped 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.
200 OK
{
    "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.

200 OK
{
    "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.

PlanCalls/dayMonitorsCost
Free 100 3 $0
Pro 50,000 50 $29/mo

Full plan comparison →

Headers on every authenticated response

headers
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
{
    "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.

HTTPCodeWhen
400missing_subjectThe path segment after the endpoint was empty.
400invalid_domainThe supplied domain is not a valid hostname.
400invalid_ipThe supplied IP is malformed.
400invalid_subjectThe supplied URL or host could not be parsed.
400invalid_idMonitor id missing or not a positive integer.
401missing_keyNo Authorization: Bearer header and no ?key=.
401invalid_keyThe key is unknown or has been revoked.
403pro_requiredThe endpoint needs a paid plan (for example /audit-history).
403not_verifiedMonitoring was requested for a domain whose ownership has not been verified.
403plan_limitCreating this monitor would exceed your plan’s cap.
404unknown_routeThe path is not /api/v1/….
404unknown_endpointNo endpoint exists with that name.
404not_foundThe requested item (such as a glossary term) does not exist.
429rate_limitedDaily key allowance exhausted, or the unauthenticated per-IP throttle tripped.
500audit_failedThe audit could not be completed.
502lookup_failedThe DNS lookup did not return a usable answer.
502whois_unreachableThe 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)

javascript
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)

python
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)

go
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 raw before caching. /health now 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/meta envelope. Added ?format=md, /me, /tools and /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.