API REFERENCE · GET · STABLE

Subdomain Finder API — /api/v1/security/subdomains

Runs two discovery pipelines in parallel — passive Certificate Transparency lookup via crt.sh and active DNS brute-force against a curated top-200 wordlist — then enriches every hit with DNS resolve, HTTP HEAD, TLS peek, and a CNAME cross-check against 15 cloud-provider takeover fingerprints (S3, CloudFront, Heroku, Azure Blob / Websites, GitHub Pages, Cloudflare Pages, Netlify, Vercel, ReadTheDocs, Zendesk, HelpScoutDocs, Tumblr). Non-apex inputs are normalized to their registrable apex via PSL. `sync=true` (default) returns one JSON body; `sync=false` streams SSE (start, host, done events).

01 · OVERVIEW

What Subdomain Finder does

Runs two discovery pipelines in parallel — passive Certificate Transparency lookup via crt.sh and active DNS brute-force against a curated top-200 wordlist — then enriches every hit with DNS resolve, HTTP HEAD, TLS peek, and a CNAME cross-check against 15 cloud-provider takeover fingerprints (S3, CloudFront, Heroku, Azure Blob / Websites, GitHub Pages, Cloudflare Pages, Netlify, Vercel, ReadTheDocs, Zendesk, HelpScoutDocs, Tumblr). Non-apex inputs are normalized to their registrable apex via PSL. `sync=true` (default) returns one JSON body; `sync=false` streams SSE (start, host, done events).

  • Method GET
  • Path /api/v1/security/subdomains
  • Stability STABLE
  • Version v2026-09-03
  • Summary Enumerate subdomains via Certificate Transparency logs + DNS brute-force with liveness + takeover-risk enrichment.
02 · PARAMETERS

Request parameters

Pass these as query-string parameters (or, where indicated, in the request headers). Required params marked required.

  • domain (required) — string Apex domain to enumerate (e.g. github.com). Non-apex inputs normalized via PSL.
  • sources — string Comma-separated subset of `ct`, `brute`, `passive`. Free tier: `ct,brute`. `passive` requires BIZ tier.
  • limit — integer, default 25 Cap total returned hosts. Free 25, PRO 200, BIZ 500.
  • liveness — boolean, default true Per-host DNS + HTTP + TLS enrichment. Set false for metadata-only scan.
  • sync — boolean, default true `true` returns full JSON body. `false` streams SSE with `start`, `host`, `done` events.
  • refresh — boolean, default false Bypass the 6h scan cache and re-run.
03 · RESPONSE

Response schema

All successful responses follow the standard `{ success: true, data: {...} }` envelope. Notable fields on the data object for this endpoint:

  • data.apex — string Normalized apex (registrable domain).
  • data.scannedAt — string ISO timestamp of the scan.
  • data.sources — object Per-source stats: `{ct:{count,ms,ok?}, brute:{count,ms,checked}, passive:{count,skipped,reason?}}`.
  • data.counts — object `{total, alive, dead}` — aggregate host counts.
  • data.subdomains — array One entry per host — see host object shape below.
  • data.subdomains[].host — string Fully-qualified hostname.
  • data.subdomains[].sources — array Which sources surfaced this host: `ct`, `brute`, `passive`.
  • data.subdomains[].firstSeen — string Earliest known timestamp (CT log `min_entry_timestamp` when available).
  • data.subdomains[].ips — array A-record IPs.
  • data.subdomains[].cname — string Primary CNAME target (nullable).
  • data.subdomains[].http — object `{scheme, status, server}` from HEAD probe.
  • data.subdomains[].tls — object `{issuer, notAfter, subjectCN}` from TLS peek.
  • data.subdomains[].alive — boolean True when DNS resolves AND (HTTP<500 OR TLS handshake succeeded).
  • data.subdomains[].takeoverRisk — boolean True when CNAME matches a cloud-provider fingerprint AND the target has no A record.
  • data.tier — string Effective tier: `free`, `pro`, or `biz`.
  • data.tierProfile — object Applied caps: `{sources, bruteLimit, limit, liveness}`.
  • data.degraded — boolean True when every requested source failed (e.g. crt.sh timeout). Not cached.
  • data.elapsedMs — integer Wall-clock scan duration.
  • data.cached — boolean True when result was served from the 6h scan cache.
04 · EXAMPLE

Example response

Truncated but representative example for a real lookup:

Sample response
{
  "success": true,
  "data": {
    "apex": "github.com",
    "scannedAt": "2026-09-03T…",
    "sources": {
      "ct": {
        "count": 38,
        "ms": 2102
      },
      "brute": {
        "count": 7,
        "ms": 360,
        "checked": 200
      },
      "passive": {
        "count": 0,
        "skipped": true
      }
    },
    "counts": {
      "total": 42,
      "alive": 31,
      "dead": 11
    },
    "subdomains": [
      {
        "host": "api.github.com",
        "sources": [
          "ct",
          "brute"
        ],
        "firstSeen": "2018-11-04T…",
        "ips": [
          "140.82.121.5"
        ],
        "cname": null,
        "http": {
          "scheme": "https",
          "status": 200,
          "server": "GitHub.com"
        },
        "tls": {
          "issuer": "DigiCert",
          "notAfter": "2026-11-30T…",
          "subjectCN": "*.github.com"
        },
        "alive": true,
        "takeoverRisk": false,
        "lastSeenAlive": "2026-09-03T…"
      }
    ],
    "tier": "free",
    "tierProfile": {
      "sources": [
        "ct",
        "brute"
      ],
      "bruteLimit": 25,
      "limit": 25,
      "liveness": true
    },
    "elapsedMs": 5843,
    "cached": false,
    "degraded": false
  }
}
05 · ERRORS

Error codes

Errors return HTTP status codes paired with stable machine-readable codes. Match on the code field rather than the human-readable message.

  • 400 INVALID_DOMAIN `domain` failed PSL apex extraction (bad TLD, malformed input).
  • 402 TIER_GATED Requested `passive` source but plan tier does not include it.
  • 504 UPSTREAM_TIMEOUT crt.sh timed out and no other source produced hosts. Degraded response is returned but not cached.
06 · BEST PRACTICES

Implementation tips

Patterns we recommend when integrating this endpoint:

  • Prefer `sync=true` for scripts under 500 hosts — it's cheaper on your side than framing SSE.
  • Use `sync=false` (SSE) for progressive UI updates on large enumerations.
  • Passive CT results are cached shared across all callers for 6h — repeat scans of the same apex from different clients return instantly.
  • Cross-reference `takeoverRisk` hits with your CNAME source-of-truth (Terraform / Route 53 / DNSControl) before filing bug-bounty reports.
  • For continuous monitoring instead of ad-hoc scans, use the DomainScan platform — daily re-discovery and `NEW_SUBDOMAIN` alerts are wired in automatically.
07 · FAQ

Frequently asked questions

  • Does this hit the target's servers? Passive CT is a query against crt.sh only. Active brute-force sends one DNS query per prefix. Liveness enrichment sends one HEAD + one TLS handshake per hit — no page fetches, no JavaScript execution.
  • Why do I see hosts marked `dead`? CT-only hosts that no longer resolve. Useful for spotting abandoned staging tiers still referenced in code or docs.
  • How is `takeoverRisk` computed? CNAME matches one of 15 cloud-provider suffixes AND the CNAME target has no A record. Same fingerprints as Detectify's subdomain-takeover scanner.
  • What counts as apex? The registrable domain via the Public Suffix List. `api.staging.example.com` normalizes to `example.com`. `example.co.uk` stays intact.