Open, unauthenticated REST API. CORS is enabled for any origin. Responses are JSON, cached for one hour per domain. A single request returns WHOIS/RDAP, DNS, mail, TLS, web security headers, technology fingerprinting, exposure scanning and a unified Security Posture score.
DomainIntel aggregates a passive, read-only view of a domain's public surface. It calls reputable upstream sources (Cloudflare DNS-over-HTTPS, RDAP, crt.sh, Mozilla Observatory, Shodan InternetDB, HackerTarget, dns.google) and merges them into a single, additive JSON payload.
meta.errors.meta.cached indicates a hit)./api/public/domain-intel?domain=example.com/api/public/domain-intel · body: { "domain": "example.com" }GET and POST return the exact same payload. Use POST if your client can't percent-encode the domain or you want to avoid query-string logging.
| Name | Location | Type | Required | Description |
|---|---|---|---|---|
| domain | query / body | string | yes | Domain to analyze. Sanitized server-side (lowercased, no http(s)://, no path, Punycode preserved). |
| Code | Meaning |
|---|---|
200 | Successful analysis of the domain. |
400 | Missing domain parameter or invalid format. |
429 | Rate limit exceeded. Retry after the seconds listed in Retry-After. |
500 | Unexpected server error. |
30 requests per minute per IP. Exceeding the limit returns 429 with body { "error": "rate_limit_exceeded", "retryAfter": N }.
Headers present on every response:
Cached responses (meta.cached: true) still count toward your quota but skip upstream calls entirely.
curl "https://domainintel.michaelpickman.com/api/public/domain-intel?domain=stripe.com"GET /api/public/domain-intel?domain=stripe.comClick Run to fetch a real response.
Trimmed for readability; arrays such as posture.findingsand technology.all are usually longer.
{
"domain": "stripe.com",
"summary": {
"ageYears": 15,
"ageDays": 5630,
"status": "active",
"daysUntilExpiry": 412,
"healthScore": 92,
"grade": "A",
"recommendations": [],
"posture": {
"score": 88,
"grade": "A",
"categories": {
"email": {
"key": "email",
"label": "Email",
"score": 100,
"grade": "A",
"weight": 20
},
"tls": {
"key": "tls",
"label": "TLS / Certificate",
"score": 95,
"grade": "A",
"weight": 15
},
"headers": {
"key": "headers",
"label": "Web Headers",
"score": 85,
"grade": "B",
"weight": 20
},
"dns": {
"key": "dns",
"label": "DNS",
"score": 70,
"grade": "C",
"weight": 10
},
"exposure": {
"key": "exposure",
"label": "Exposure",
"score": 90,
"grade": "A",
"weight": 25
},
"hygiene": {
"key": "hygiene",
"label": "Domain Hygiene",
"score": 100,
"grade": "A",
"weight": 10
}
},
"findings": [
{
"id": "dns.caa",
"severity": "medium",
"category": "dns",
"title": "No CAA records",
"description": "Any Certificate Authority can issue certificates for your domain.",
"recommendation": "Publish CAA records limiting which CAs may issue certificates for you."
}
]
}
},
"registration": {
"createdDate": "2009-09-10T00:00:00Z",
"updatedDate": "2024-08-12T00:00:00Z",
"expiryDate": "2027-09-10T00:00:00Z",
"registrar": "MarkMonitor Inc.",
"statuses": [
"clientTransferProhibited"
],
"dnssec": true
},
"whois": {
"registrantOrg": "Stripe, Inc.",
"country": "US",
"exposedContacts": []
},
"dns": {
"provider": "AWS Route 53",
"nameservers": [
"ns-1471.awsdns-55.org",
"ns-2049.awsdns-67.co.uk"
],
"a": [
"52.84.150.39"
],
"aaaa": []
},
"mail": {
"provider": "Google Workspace",
"mx": [
{
"priority": 1,
"host": "aspmx.l.google.com"
}
]
},
"emailSecurity": {
"spf": {
"present": true,
"record": "v=spf1 include:_spf.google.com ~all"
},
"dmarc": {
"present": true,
"policy": "reject",
"record": "v=DMARC1; p=reject;"
}
},
"hosting": {
"provider": "Amazon Web Services",
"ip": "52.84.150.39",
"asn": "AS16509",
"country": "US"
},
"ssl": {
"issuer": "Let's Encrypt",
"validFrom": "2026-04-01T00:00:00Z",
"validTo": "2026-07-01T00:00:00Z",
"daysUntilExpiry": 16,
"expired": false,
"sans": [
"stripe.com",
"*.stripe.com"
],
"certificatesFound": 124
},
"reputation": {
"ip": "52.84.150.39",
"listed": false,
"lists": [],
"checked": [
"zen.spamhaus.org",
"bl.spamcop.net"
]
},
"subdomains": {
"checked": [
"www",
"api",
"mail"
],
"found": [
{
"name": "api.stripe.com",
"ips": [
"52.84.150.40"
]
}
]
},
"technology": {
"server": "nginx",
"language": null,
"cms": null,
"cdn": "Cloudflare",
"ecommerce": null,
"frameworks": [
"React"
],
"analytics": [
"Google Analytics"
],
"all": [
{
"name": "Cloudflare",
"category": "cdn",
"confidence": 100,
"evidence": "server: cloudflare"
}
]
},
"security": {
"headers": {
"score": 85,
"grade": "B",
"checks": [
{
"id": "hsts",
"label": "Strict-Transport-Security",
"status": "pass",
"detail": "max-age=63072000; includeSubDomains",
"why": "Forces HTTPS in browsers and prevents SSL downgrade attacks."
}
],
"missing": [],
"raw": {
"strict-transport-security": "max-age=63072000; includeSubDomains"
}
},
"cookies": {
"total": 1,
"insecure": []
},
"httpsRedirect": {
"redirects": true,
"finalUrl": "https://stripe.com/",
"chain": []
},
"tls": {
"source": "mozilla-observatory",
"grade": "A+",
"score": 110,
"protocols": [
"TLSv1.2",
"TLSv1.3"
],
"weakProtocols": [],
"vulnerabilities": [],
"raw": null
},
"dnsSecurity": {
"dnssec": true,
"caa": {
"present": false,
"records": []
},
"dkim": {
"present": true,
"selectorsTested": [
"google",
"default"
],
"selectorsFound": [
"google"
]
},
"mtaSts": {
"dnsPresent": true,
"policyPresent": true,
"mode": "enforce"
},
"bimi": {
"present": false,
"record": null
},
"spf": {
"present": true
},
"dmarc": {
"present": true,
"policy": "reject"
}
}
},
"exposure": {
"publicFiles": {
"securityTxt": {
"present": true,
"contact": [
"mailto:security@stripe.com"
],
"policy": [],
"expires": null
},
"robotsTxt": {
"present": true,
"sitemaps": [
"https://stripe.com/sitemap.xml"
]
},
"sitemapXml": {
"present": true
},
"humansTxt": {
"present": false
}
},
"sensitiveFiles": [],
"directoryListing": {
"found": false,
"urls": []
},
"subdomains": {
"source": "crt.sh",
"total": 1240,
"alive": [
{
"name": "api.stripe.com",
"ips": [
"52.84.150.40"
],
"cname": null
}
],
"sample": [
"api.stripe.com",
"dashboard.stripe.com"
]
},
"takeoverRisks": [],
"ports": {
"ip": "52.84.150.39",
"ports": [
80,
443
],
"cves": [],
"tags": [
"cdn"
],
"hostnames": [
"stripe.com"
]
}
},
"meta": {
"queriedAt": "2026-06-15T10:00:00.000Z",
"sources": [
"cloudflare-dns",
"rdap.org",
"crt.sh",
"hackertarget",
"mozilla-observatory",
"internetdb.shodan.io"
],
"cached": false,
"errors": []
}
}summary.posture is the unified verdict. Each of six categories produces a 0-100 sub-score and an A-F grade. The global score is the weighted average; the global grade is derived from the global score using the same thresholds (A ≥ 90, B ≥ 75, C ≥ 60, D ≥ 40, F < 40).
| Category | Weight | What it measures |
|---|---|---|
| 20% | SPF, DMARC policy strength, DKIM selectors, MTA-STS. | |
| tls | 15% | CT log presence, expiry windows, obsolete TLS protocols. |
| headers | 20% | HSTS, CSP quality, XFO/XCTO, Referrer-Policy, Permissions-Policy, cookie flags, HTTPS redirect. |
| dns | 10% | DNSSEC enabled and CAA records published. |
| exposure | 25% | Sensitive files, directory listing, takeover risks, Shodan CVEs, DNSBL listings. |
| hygiene | 10% | Domain expiry runway, WHOIS privacy, registrar visibility. |
Sub-scores start at 100 and are decremented per finding. Findings are sorted by severity in the API response, so a UI can render them as a prioritized to-do list.
| Severity | When it's used |
|---|---|
| critical | Active exposure or guaranteed breakage (expired cert, exposed .env, takeover ready). |
| high | Significant risk with a clear short-term fix (no DMARC, missing HSTS, cert expiring in <30d). |
| medium | Hardening gap that lets attacks succeed when paired with other weaknesses. |
| low | Best-practice nice-to-have; safe to defer. |
| info | Contextual note, no action required. |
| Source | Used for |
|---|---|
| cloudflare-dns / dns.google | DNS resolution over HTTPS (A, AAAA, MX, TXT, CAA, CNAME, DNSSEC AD bit). |
| rdap.org | WHOIS/RDAP registration data: dates, registrar, statuses, secureDNS. |
| crt.sh | Certificate Transparency logs for SSL/TLS history and CT-based subdomain discovery. |
| mozilla-observatory | Holistic TLS and security-header grade. |
| internetdb.shodan.io | Open ports, tags and known CVEs for the primary IP. No API key required. |
| hackertarget | Hosting/ASN lookups and supplementary DNS data. |
| DNSBL queries | Reputation checks (Spamhaus, SpamCop, etc.). |
| Live HTTP fetch | Homepage retrieval for headers, cookies, redirects and technology rules. |
| Field | Type | Description |
|---|---|---|
| domain | string | Sanitized domain that was analyzed. |
| summary.ageYears | number | null | Domain age in whole years. |
| summary.ageDays | number | null | Total domain age in days. |
| summary.status | "active" | "expiring_soon" | "expired" | "unknown" | Derived lifecycle status of the domain. |
| summary.daysUntilExpiry | number | null | Days until expiry (negative if expired). |
| summary.healthScore | number (0-100) | Legacy health score (kept for compatibility). |
| summary.grade | "A" | "B" | "C" | "D" | "F" | Legacy health grade. |
| summary.recommendations | string[] | Legacy plain-text recommendations list. |
| summary.posture | Posture | Unified Security Posture report (categories + findings). |
| summary.posture.score | number (0-100) | Weighted global posture score. |
| summary.posture.grade | "A"–"F" | Posture grade derived from the score. |
| summary.posture.categories | Record<6 keys, PostureCategory> | Per-category sub-score, grade and weight: email, tls, headers, dns, exposure, hygiene. |
| summary.posture.findings | PostureFinding[] | Findings sorted by severity (critical → info), each with id, category, title, description and recommendation. |
| registration.createdDate | ISO string | null | Original registration date. |
| registration.updatedDate | ISO string | null | Last registry update. |
| registration.expiryDate | ISO string | null | Domain expiry date. |
| registration.registrar | string | null | Registrar detected via RDAP. |
| registration.statuses | string[] | EPP domain statuses. |
| registration.dnssec | boolean | DNSSEC enabled flag from RDAP secureDNS. |
| whois.registrantOrg | string | null | Registrant organization. |
| whois.country | string | null | Registrant country code. |
| whois.exposedContacts | { kind, value }[] | Public contact addresses found in registration data. |
| dns.provider | string | null | DNS provider inferred from nameservers. |
| dns.nameservers | string[] | Authoritative nameservers. |
| dns.a / dns.aaaa | string[] | A / AAAA records. |
| mail.provider | string | null | Mail provider inferred from MX hosts. |
| mail.mx | { priority, host }[] | MX records ordered by priority. |
| emailSecurity.spf | { present, record } | SPF status and TXT record. |
| emailSecurity.dmarc | { present, policy, record } | DMARC status, policy (p=) and raw record. |
| hosting.provider | string | null | Hosting provider inferred from ASN. |
| hosting.ip | string | null | Primary IP address. |
| hosting.asn | string | null | Provider ASN. |
| hosting.country | string | null | Server country code. |
| ssl.issuer | string | null | Latest certificate issuer (CT logs / crt.sh). |
| ssl.validFrom / validTo | ISO | null | Validity window of the latest certificate. |
| ssl.daysUntilExpiry | number | null | Days until the latest cert expires. |
| ssl.expired | boolean | Whether the latest cert has expired. |
| ssl.sans | string[] | Subject Alternative Names on the latest cert. |
| ssl.certificatesFound | number | Total certificates seen in Certificate Transparency logs. |
| reputation.listed | boolean | Whether the primary IP appears on a checked DNSBL. |
| reputation.lists | string[] | DNSBLs that listed the IP. |
| reputation.checked | string[] | DNSBLs that were queried. |
| subdomains.checked / found | string[] / { name, ips }[] | Probed common subdomains and those that resolved. |
| technology | Technology | null | Detected tech stack (null if homepage unreachable). |
| technology.server / language / cms / cdn / ecommerce | string | null | Best-match labels per category. |
| technology.frameworks / analytics | string[] | Lists of matched frameworks and analytics tools. |
| technology.all | { name, category, confidence, evidence }[] | Every match with category, 0-100 confidence and the rule that fired. |
| security.headers | { score, grade, checks[], missing[], raw } | null | Per-header analysis, 0-100 score and grade. |
| security.cookies | { total, insecure[] } | null | Cookies from the homepage with missing flags. |
| security.httpsRedirect | { redirects, finalUrl, chain } | HTTP→HTTPS redirect trace. |
| security.tls | { source, grade, score, protocols[], weakProtocols[], vulnerabilities[], raw } | TLS grade and vulnerabilities from Mozilla Observatory. |
| security.dnsSecurity | { dnssec, caa, dkim, mtaSts, bimi, spf, dmarc } | DNS-level security controls: DNSSEC, CAA, DKIM (selector probes), MTA-STS, BIMI. |
| exposure.publicFiles | { securityTxt, robotsTxt, sitemapXml, humansTxt } | Informational public files. security.txt is parsed for contact/policy. |
| exposure.sensitiveFiles | { path, url, status, severity, evidence }[] | Sensitive files detected (.env, .git/config, backup.zip…) with content validation. |
| exposure.directoryListing | { found, urls[] } | Open 'Index of /' directories found on common paths. |
| exposure.subdomains | { source, total, alive[], sample[] } | null | Certificate Transparency subdomain discovery with DNS liveness probes. |
| exposure.takeoverRisks | { subdomain, cname, service, reason }[] | Dangling CNAMEs that match known takeover-prone services. |
| exposure.ports | { ip, ports, cves, tags, hostnames } | null | Shodan InternetDB summary for the primary IP (ports, known CVEs, tags). |
| meta.queriedAt | ISO string | Server-side timestamp of the analysis. |
| meta.sources | string[] | Upstream sources that were queried (cloudflare-dns, rdap.org, crt.sh, mozilla-observatory, internetdb.shodan.io…). |
| meta.cached | boolean | true when the response was served from the 1-hour cache. |
| meta.errors | { source, message }[] | Per-source partial failures. Never break the whole response. |
Responses are cached at the edge for 1 hour per sanitized domain. When a response is served from cache, meta.cached is true.
Upstream sources fail independently. If RDAP times out, the response still contains DNS, mail, technology, security and exposure — only registration will be null and a record will be appended to meta.errors:
{
"meta": {
"errors": [
{ "source": "rdap.org", "message": "fetch timeout after 6s" }
]
}
}Always check meta.errors when building dashboards — missing fields signal a partial failure rather than "no data".
DomainIntel only queries public sources and the homepage of the analyzed domain. It does not perform port scans, vulnerability exploitation, or authenticated requests.
You are responsible for complying with the terms of service of upstream providers and with local laws when using this API on domains you do not own.