Request demo

Domain Search API

Query the Whole Domain Index by Any Field.

Send one JSON body. Filter on names, WHOIS, DNS, certificates and web data, and get back full domain records, a page at a time or as an export.

Use it when the question crosses fields. The finder APIs start from one indicator; Domain Search describes a set of domains by everything you know about them.

QueryPOST /discovery/domain-searchall applied

  1. must dns.mx.mail_servers eq "mail.hosting.example"
  2. must domain.whois.create_date gte 2026-01-01T00:00:00Z
  3. must webdata.connection_status eq "success"
  4. sort domain.whois.create_date desc
Each condition thins the set; the results follow.

Results2

  1. harbor-cafe.example2026-09-14 · mail.hosting.example
  2. oak-studio.example2026-08-30 · mail.hosting.example

Put All Conditions in One Body.

One question across three layers: every domain whose mail goes to one server, registered since the start of 2026, that answers on the web. Newest registrations first.

POST https://api.deepinfo.com/v1/discovery/domain-search Reference
ParameterTypeDescription
filtersobjectOptionalIn the body. Arrays of conditions under must, should and must_not, each {name, type, value}.
sortarrayOptionalIn the body. One or more {field, order} pairs, order is asc or desc.
pageintegerOptionalPage number, from 1.
page_sizeintegerOptionalResults per page.
exportbooleanOptionalReturn the matches as an export instead of a page. Default false.
export_formatstringOptionaljson or csv.
export_scopestringOptionalHow much of each record to include: basic, default or extended.

Request

curl -X POST "https://api.deepinfo.com/v1/discovery/domain-search?page_size=25" \
  -H "apikey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "filters": {
      "must": [
        { "name": "dns.mx.mail_servers", "type": "eq", "value": "mail.hosting.example" },
        { "name": "domain.whois.create_date", "type": "gte", "value": "2026-01-01T00:00:00Z" },
        { "name": "webdata.connection_status", "type": "eq", "value": "success" }
      ]
    },
    "sort": [ { "field": "domain.whois.create_date", "order": "desc" } ]
  }'

Response

200 OK · application/json
{
  "page": 1,
  "page_size": 25,
  "result_count": 2,
  "results": [
    {
      "punycode": "harbor-cafe.example",
      "unicode": "harbor-cafe.example",
      "is_idn": false,
      "domain": {
        "name": { "punycode": "harbor-cafe", "length": 11 },
        "whois": {
          "create_date": "2026-09-14T08:12:40Z",
          "registrar": "…",
          "name_servers": ["ns1.hosting.example"]
        }
      },
      "dns": {
        "a": { "ip_addresses": ["198.51.100.23"] },
        "mx": { "mail_servers": ["mail.hosting.example"] }
      },
      "webdata": { "connection_status": "success", "…": "…" }
    },
    {
      "punycode": "oak-studio.example",
      "unicode": "oak-studio.example",
      "is_idn": false,
      "domain": {
        "whois": { "create_date": "2026-08-30T17:41:02Z" }
      },
      "dns": {
        "mx": { "mail_servers": ["mail.hosting.example"] }
      },
      "webdata": { "connection_status": "success", "…": "…" }
    }
  ]
}

Operators That Share One Filter Shape.

Each condition is {name, type, value}: a field, an operator and a value. The operator decides what kind of value it expects.

OperatorMatches when the fieldExample condition
eqEquals the valuedomain.extension · "com"
inEquals any value in an arraydomain.whois.registrant.country · ["tr", "fr"]
startswithStarts with the stringfqdn · "login."
endswithEnds with the stringfqdn · ".acme.example"
wildcardMatches a pattern, ? for one character and * for any rundns.mx.mail_servers · "mx?.acme.example"
fuzzyApproximately matches the string, a few characters apartdomain.name · "acme"
contains_anyIs an array holding at least one of the valuesdomain.name.keywords · ["login", "verify"]
contains_allIs an array holding every one of the valuesdomain.name.keywords · ["acme", "pay"]
gteIs greater than or equal to a number or datedomain.whois.create_date · "2025-01-01T00:00:00Z"
lteIs less than or equal to a number or datedomain.whois.expiry_date · "2026-12-31T23:59:59Z"
existsHas a value (true) or has none (false)dns.mx.mail_servers · true

Operators are defined once for the whole API, in the search and filters guide.

Where a Condition Sits Decides How It Combines.

All conditions under must have to match. At least one under should has to match. Nothing under must_not may match.

The example on the right takes every domain on one name server, keeps the ones already in use, those that accept mail or answer on the web, and leaves out the domains you own.

must + should + must_not
{
  "filters": {
    "must": [
      { "name": "dns.ns.name_servers", "type": "eq", "value": "ns1.hosting.example" }
    ],
    "should": [
      { "name": "dns.mx.mail_servers", "type": "exists", "value": true },
      { "name": "webdata.connection_status", "type": "eq", "value": "success" }
    ],
    "must_not": [
      { "name": "domain", "type": "in", "value": ["acme.example", "acme-group.example"] }
    ]
  }
}
  1. Every one has to match (must)
  2. At least one has to match (should)
  3. None may match (must_not)

Before You Send a Query.

Searchable fieldsGrouped by family: name and extension, subdomain, WHOIS, DNS, IP history, SSL, and web data with HTTP headers. The full list is in the reference.
Totalsresult_count is the total number of matches across all pages. See pagination.
Empty bodyAn empty body {} matches all records in the dataset. Send at least one condition.
Exportexport=true returns the matches as JSON or CSV instead of a page. Large exports can time out, so filter first.
In the platformEASM custom discovery rules are written in this filter language over Deepinfo’s domain data. A query you test here can become a rule that proposes new assets. See Asset Discovery.
Rate limitsPlan-dependent. The default is one request per second per key and endpoint. See rate limits.

Questions About Domain Search API

Are subdomains in the results as well?

Yes. Each record is a host name, filtered as fqdn, and a filter on domain matches a registered domain together with its subdomains. subdomain_root and subdomain_last filter on the subdomain labels themselves.

Which fields can results be sorted on?

The name and extension (punycode, domain.extension.punycode), the WHOIS create, expiry, update and last-change dates, and dns_last_change_date and ssl_last_change_date. Pass them in sort as {field, order} pairs.

Can we find every host that serves one certificate?

Yes. Filter ssl.fingerprint.sha256 on the certificate’s SHA-256 fingerprint. A fingerprint identifies one certificate, so the result is each host in the index that serves it.

Can we find domains that pointed to an IP in the past?

Yes. ip_history and domain.ip_history keep each address a host or domain has resolved to over time, so a filter on them also matches names that have moved since.

How is the Domain Search API priced?

As part of an API services plan, priced by volume and frequency, separately from the platform. See Data & API pricing, or talk to us about the queries you plan to run.

Does the filter syntax work on other Deepinfo endpoints?

Yes, with two exceptions. The EASM, CTI and BRP searches and their bulk actions take this filters body and these operators, each with its own list of searchable fields. Darkweb Search and Report Search use their own formats.

What happens if a field name is wrong?

The request fails with a 400 application error, and its parameters list points to what was rejected. See errors.

Bring the Question. We’ll Write the Filter With You.

Tell us what you want to find in the dataset. We set up access and walk through the fields with your team on a short call.