Skip to content

Domain Risk

The Domain Risk feed provides a continuous data stream of all newly-scored, high-risk domains (combined score of 70+), regardless of their recent activity. This offers comprehensive visibility into potentially dangerous infrastructure that may not be currently active but still poses a risk.

Domains are apex-level (for example, example.com but not www.example.com), and the feed includes all domains that reach a combined Domain Risk Score of 70 or higher, whether or not they show recent activity.

Use this feed when you need to:

  • Gain comprehensive visibility into potentially dangerous infrastructure
  • Enable proactive threat intelligence for early detection
  • Set up automated detection rules in TIPs or SIEMs
  • Trigger alerts when network devices communicate with high-risk domains
  • Create automated playbooks for domain enrichment
  • Prioritize threats more quickly

Inclusion criteria: All apex-level domains with a combined Domain Risk Score of 70 or higher, regardless of observed activity.

Important note: While Domain Risk entries don’t expire, we recommend using entries no older than 24 hours for optimal threat detection.

Get started with the Domain Risk feed in under 60 seconds using the Real-time Feed API:

Terminal window
# Start polling for high-risk domains
curl -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/feed/domainrisk/?sessionID=myThreatIntel'

This returns the last hour of data. Call again with the same sessionID to get only new data since your last request. See Real-time Feed API for complete details and Authentication for auth options.

You need the following to access Threat Feeds:

  • An Enterprise Account with DomainTools, accessible at https://account.domaintools.com/my-account/
  • Authentication credentials (API key for header authentication, or API username and key for HMAC or open key authentication)
  • A way to interact with a REST API delivered through AWS

Obtain your API credentials from your group’s API administrator. API administrators can manage their API keys at https://research.domaintools.com, selecting the drop-down account menu and choosing API admin.

For assistance, contact enterprisesupport@domaintools.com.

You can authenticate to the Domain Risk APIs using three different methods. Choose the method that best fits your security requirements and technical environment.

Authenticate your requests by including the API key in the header of each HTTP request. The API key serves as a unique identifier and authenticates your requests.

Required header:

X-Api-Key: YOUR_API_KEY

Examples:

Terminal window
# Feed API request
curl -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/feed/domainrisk/?sessionID=myThreatIntel'
Terminal window
# Download API request
curl -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/download/domainrisk/'

HMAC authentication is a secure alternative to API key-based methods. It requires signing each request with an HMAC digest derived from your API key, providing integrity and authenticity without exposing credentials directly in the request.

This method is recommended for systems where authentication credentials shouldn’t be stored in plain text or included directly in request URLs.

DomainTools supports MD5, SHA1, and SHA256 for the hashing algorithm. Use SHA256 — it’s the recommended choice and is more resistant to collision attacks than MD5 or SHA1.

Required query parameters:

  • api_username: Your DomainTools API username
  • signature: HMAC-SHA256 signature of api_username + timestamp + uri_path
  • timestamp: Current UTC timestamp in ISO 8601 format (for example, 2025-06-01T15:30:00Z)

Constructing the HMAC signature:

Terminal window
signature = HMAC-SHA256(api_key, api_username + timestamp + uri_path)

Example Python signing function:

import hmac
import hashlib
def sign(api_username, api_key, timestamp, uri):
params = f"{api_username}{timestamp}{uri}"
return hmac.new(api_key.encode("utf-8"), params.encode("utf-8"), hashlib.sha256).hexdigest()

Examples:

Terminal window
# Feed API request with HMAC
curl 'https://api.domaintools.com/v1/feed/domainrisk/?api_username=YOUR_USERNAME&signature=HMAC_SIGNATURE&timestamp=2025-01-06T15:30:00Z&sessionID=myThreatIntel'
Terminal window
# Download API request with HMAC
curl 'https://api.domaintools.com/v1/download/domainrisk/?api_username=YOUR_USERNAME&signature=HMAC_SIGNATURE&timestamp=2025-01-06T15:30:00Z'

This is the easiest authentication scheme to implement, but also the least secure. Each request contains the full API key and API username as query parameters. We recommend using API key header authentication or HMAC authentication instead.

If you’re unsure about your authentication options, contact enterprisesupport@domaintools.com.

Required query parameters:

  • api_username: Your API username
  • api_key: Your API key

Examples:

Terminal window
# Feed API request
curl 'https://api.domaintools.com/v1/feed/domainrisk/?api_username=YOUR_USERNAME&api_key=YOUR_API_KEY&sessionID=myThreatIntel'
Terminal window
# Download API request
curl 'https://api.domaintools.com/v1/download/domainrisk/?api_username=YOUR_USERNAME&api_key=YOUR_API_KEY'

The Feed API provides real-time access to current Domain Risk data. Use this API to poll for the latest feed updates at regular intervals, maintain a session to track your position in the feed, and filter results based on your specific needs.

https://api.domaintools.com/v1/feed/domainrisk/

Real-time feeds have the following rate limits:

  • 2 queries per minute
  • 120 queries per hour

If you exceed these limits, the API returns an error.

The API supports two response formats:

NDJSON (Newline-Delimited JSON)

  • Default format when no Accept header is specified
  • Also known as JSON Lines (JSONL)
  • One JSON object per line
  • Efficient for streaming and processing large datasets
  • Set Accept: application/x-ndjson to explicitly request this format

CSV (Comma-Separated Values)

  • Set Accept: text/csv to request CSV format
  • Add &headers=1 to the query parameters to include column headers as the first line
  • Not available for all feeds; check the specific feed documentation for CSV support

Session management allows you to maintain your position in the feed data stream, ensuring you don’t miss or duplicate events when polling the API.

How sessions work:

  • Start a new session: Provide a unique sessionID parameter of your choosing. By default, the API returns the past hour of results.
  • Resume a session: Use the same sessionID in subsequent requests. The API returns all data since your last request.
  • Handle large result sets: If a single request exceeds 10M results, the API returns an HTTP 206 response code. Repeat the same request with the same sessionID to receive the next batch of data until you receive an HTTP 200 response code.
  • One request at a time: Do not send simultaneous requests with the same sessionID for the same feed. Wait for each request to complete before sending the next one. Concurrent requests with the same sessionID can produce errors or incomplete results.
  • Delete a session: Use an HTTP DELETE request with your sessionID to clear the saved offset and start fresh.

Session ID requirements:

  • 1 to 64 characters in length
  • Alphanumeric characters and hyphens only ([a-zA-Z0-9-]+)
  • Case-sensitive

The standard access pattern is to periodically request the most recent feed data, as often as every 60 seconds.

Terminal window
curl -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/feed/domainrisk/?sessionID=myThreatIntel'

This starts a new session and returns the last hour of data. Subsequent calls with the same sessionID return data since the last request.

Type: String

Valid values: 1-64 alphanumeric characters and hyphens ([a-zA-Z0-9-]+)

Description: A unique identifier for the session, used for resuming data retrieval from the last point. Use a new sessionID to begin a new session, fetching the most recent hour by default. Reuse the same sessionID to return all feed data since your last request. If omitted, time window parameters (such as after/before) are required.

Example: sessionID=mySOC

Required: Yes, to continue where you left off (or use after/before instead)

Type: Integer or string

Valid values:

  • Integer: -1 to -432,000 (relative seconds before current time)
  • String: ISO 8601 datetime in UTC format (YYYY-MM-DDTHH:MM:SSZ)

Description: The start of the query window (inclusive). When using an integer, the value is in seconds relative to the current time. When using a string, provide an absolute timestamp. The timestamp must represent a point between 1 second ago and 5 days ago, relative to the current UTC time.

Example: after=-60 or after=2024-10-16T10:20:00Z

Required: Yes, if before or sessionID not provided

Type: Integer or string

Valid values:

  • Integer: -1 to -432,000 (relative seconds before current time)
  • String: ISO 8601 datetime in UTC format (YYYY-MM-DDTHH:MM:SSZ)

Description: The end of the query window (inclusive). When using an integer, the value is in seconds relative to the current time. When using a string, provide an absolute timestamp. The timestamp must represent a point between 1 second ago and 5 days ago, relative to the current UTC time.

Example: before=-120 or before=2024-10-16T10:20:00Z

Required: Yes, if after or sessionID not provided

Type: String

Valid values: Domain character set restricted by the DNS specification (letters, digits, hyphens). International characters should be specified in punycode. A trailing dot is acceptable.

Description: Filter for an exact domain or a domain substring by prefixing or suffixing your string with *. Multiple parameters are supported (for example, ?domain=*apple*&domain=*microsoft*). The URL-encoded version of * (%2A) may be required in some clients.

Example: domain=*bank* or domain=example.com

Required: No

Type: Boolean

Valid values: true

Description: Requires a sessionID. When used with a new session ID, returns the first hour of data in the time window (rather than the last). Returns an error if the session ID already exists — drop fromBeginning from subsequent requests after the first call. Only the value true is accepted; any other value (including false) is ignored.

Example: fromBeginning=true

Required: No

Type: Integer

Valid values: Positive integer, 1-1,000,000,000

Description: Limits the number of results in the response payload. Primarily intended for testing. When you apply this parameter to risk feeds, results are sorted by all_threats_combined_percent (descending).

Example: top=10

Required: No

Note: When using the top parameter with Domain Risk, results are automatically sorted by overall_risk in descending order (highest risk first).

Type: Integer

Valid values: 1

Description: Adds a header row as the first line of the response when text/csv is requested. Set headers=1 to enable. Only applies when requesting CSV format. Only the value 1 is accepted; any other value is invalid.

Example: headers=1

Required: No

Type: integer (optional)

Range: 1-99

Filter results to include only domains with risk scores greater than or equal to the specified threshold.

You can apply multiple risk score filters simultaneously. When multiple filters are used, domains must meet ALL specified thresholds to be included in the results.

Available risk score filters:

  • overall_min - Minimum overall risk score
  • malware_min - Minimum malware risk score
  • phishing_min - Minimum phishing risk score
  • spam_min - Minimum spam risk score
  • proximity_min - Minimum proximity risk score

The API returns NDJSON format with one domain per line.

About Domain Risk Scores:

Domain Risk Scores predict the likelihood that a domain was registered with malicious intent. Each score ranges from 0-100, with special meanings for 0 (zero-listed/known legitimate) and 100 (blocklisted/known-bad). Regular scores range from 1-99, with null values indicating the domain has aged out of that threat profile.

Score RangeScore ColorDescription
100RedBlocklisted. These domains can be considered known-bad, and have the highest likelihood of malicious intent. This includes sinkholed domains. DomainTools combines third party blocklists with our own scoring to determine which domains to blocklist.
90-99RedStrong confidence in near-term weaponization.
70-89OrangeA potential threshold for suggesting malicious intent, and our default recommendation for significance in an investigation. Individual mileage may vary, depending on your security context and priorities.
50-69YellowMay require attention, depending on your security posture.
1-49GreyVery little evidence of malicious intent.
0GreyZero-listed. DomainTools zero-lists a domain when we have no evidence that it was registered with malicious intent. Zero-listing guards well-known legitimate domains against accidental blocking and includes domains which are vital to the expected operation of the Internet.

See the Domain Risk Score user guide for complete details.

Response fields:

timestamp (string): ISO 8601 UTC timestamp when the domain was scored or observed

domain (string): The apex-level domain name

phishing_risk (integer, nullable): Phishing risk score (0-100), or null if not applicable

malware_risk (integer, nullable): Malware risk score (0-100), or null if not applicable

spam_risk (integer, nullable): Spam risk score (0-100), or null if not applicable

proximity_risk (integer): Proximity risk score (0-100)

overall_risk (integer): Overall combined risk score (0-100)

Example response:

{"timestamp":"2025-01-06T15:30:42Z","domain":"malicious-example.com","phishing_risk":94,"malware_risk":88,"spam_risk":93,"proximity_risk":80,"overall_risk":94}
{"timestamp":"2025-01-06T15:30:45Z","domain":"suspicious-example.net","phishing_risk":96,"malware_risk":91,"spam_risk":99,"proximity_risk":85,"overall_risk":99}
CodeStatusDescription
200OKThe request was successful and all data has been delivered
206Partial contentThe request was successful, but only a portion of the data was returned. The request exceeded 10M results or the 1-hour evaluation window. Repeat the same request with the same sessionID to receive the next batch of data until you receive an HTTP 200 response
400Bad requestThe request is malformed
403ForbiddenMissing or invalid API credentials
404Not foundThe requested resource (such as a sessionID) doesn’t exist
406Not acceptableThe specified Accept header value isn’t supported. Only application/x-ndjson and text/csv are accepted
422Unprocessable entityThe request is syntactically valid but violates semantic or domain-specific rules (for example, invalid query parameter values)

Basic session polling:

Terminal window
# Start a new session
curl -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/feed/domainrisk/?sessionID=myThreatIntel'
Terminal window
# Resume the session (returns data since last request)
curl -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/feed/domainrisk/?sessionID=myThreatIntel'

Time window filtering:

Terminal window
# Get data from a specific time range
curl -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/feed/domainrisk/?after=2025-01-06T10:00:00Z&before=2025-01-06T11:00:00Z'

Domain filtering:

Terminal window
# Filter for specific domain patterns
curl -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/feed/domainrisk/?domain=*.example.com&sessionID=myThreatIntel'

CSV format:

Terminal window
# Request CSV format with headers
curl -H 'Accept: text/csv' -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/feed/domainrisk/?headers=1&sessionID=myThreatIntel'
Terminal window
# Request CSV format without headers
curl -H 'Accept: text/csv' -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/feed/domainrisk/?sessionID=myThreatIntel'

Risk score filtering:

Terminal window
# Filter for domains with overall risk ≥ 90
curl -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/feed/domainrisk/?overall_min=90&sessionID=myThreatIntel'
Terminal window
# Filter for domains with high phishing and malware risk
curl -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/feed/domainrisk/?phishing_min=80&malware_min=80&sessionID=myThreatIntel'
Terminal window
# Get top 10 highest-risk domains (sorted by overall_risk)
curl -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/feed/domainrisk/?top=10&sessionID=myThreatIntel'

Handling large result sets:

Terminal window
# If you receive HTTP 206, repeat the request to get the next batch
curl -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/feed/domainrisk/?sessionID=myThreatIntel'
Terminal window
# Repeat until you receive HTTP 200
curl -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/feed/domainrisk/?sessionID=myThreatIntel'

Delete a session:

Terminal window
# Clear the saved offset and start fresh
curl -X DELETE -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/feed/domainrisk/?sessionID=myThreatIntel'

The Real-time Download API provides access to historical Domain Risk data through temporary AWS S3 file links. Use this API to retrieve archived data you may have missed or to backfill your systems with historical information. Files are organized by hour and available for 90 days.

https://api.domaintools.com/v1/download/domainrisk/

Type: Integer

Valid values: Positive integer

Description: Limits the number of files returned in the response, starting from the most recent. Use to control payload size or test specific cases.

Example: limit=10

Required: No

Type: Integer

Valid values: Non-negative integer (0, 1, 2, …)

Description: Selects which page of results to return. Pages begin at 0 with the latest results. Use with limit and prefix to control results. The server returns an HTTP 404 (No data to download.) message when the page request exceeds the last page of results.

Example: page=3

Required: No

Type: String

Valid values: Date/time prefix matching the feed’s filename format

Description: Filters results by date using the file prefix. Use with page and limit to control results. Filename prefixes vary by feed. For example, files for this feed begin with the date in YYYY-MM-DD format.

Example: prefix=2025-06-24

Required: No

The API returns a JSON response containing an array of downloadable files. Each file entry includes:

download_name (string): The feed identifier (domainrisk)

files (array): List of downloadable file entries

Each file object contains:

FieldTypeDescription
namestringPath and filename of the downloadable file
last_modifiedstringTimestamp of last modification in ISO 8601 UTC format
etagstringETag (hash) used to verify file identity and versioning
sizeintegerFile size in bytes
urlstringTemporary signed URL to download the file from AWS

File naming convention:

  • Data file: domainrisk/{YYYY-MM-DD}/domainrisk-{YYYYMMDD}.{HH00}-{HH00}.json.gz
  • Checksum file: domainrisk/{YYYY-MM-DD}/domainrisk-{YYYYMMDD}.{HH00}-{HH00}.json.gz.sha256

Example response:

{
"response": {
"download_name": "domainrisk",
"files": [
{
"name": "domainrisk/2024-11-19/domainrisk-20241119.1900-2000.json.gz.sha256",
"last_modified": "2024-11-19T20:00:11+00:00",
"etag": "\"67a6d9b0973b2d31ffb779dc8f7f8cfa\"",
"size": 64,
"url": "https://download.example.com/domainrisk/2024-11-19/domainrisk-20241119.1900-2000.json.gz.sha256?Expires=..."
},
{
"name": "domainrisk/2024-11-19/domainrisk-20241119.1900-2000.json.gz",
"last_modified": "2024-11-19T20:00:11+00:00",
"etag": "\"67a6d9b0973b2d31ffb779dc8f7f8cfa\"",
"size": 1850000,
"url": "https://download.example.com/domainrisk/2024-11-19/domainrisk-20241119.1900-2000.json.gz?Expires=..."
}
]
}
}
CodeStatusDescription
200OKThe request was successful
400Bad requestThe request is malformed
401UnauthorizedMissing or invalid API credentials
403ForbiddenMissing or invalid API credentials
404Not foundNo data to download
422Unprocessable entityThe request is syntactically valid but violates semantic or domain-specific rules (for example, invalid query parameter values)

The *.json.gz.sha256 file is a checksum containing a SHA-256 hash value used to verify the integrity of the downloaded file.

The *.json.gz file, when uncompressed, contains JSON data in the same format as the Feed API response (NDJSON with timestamp, domain, and risk score fields).

List available files:

Terminal window
# Get the most recent files
curl -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/download/domainrisk/?limit=10'

Download and verify a file:

Terminal window
# Get the file list
curl -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/download/domainrisk/?limit=2' > files.json
# Extract the URL and download the data file
curl -o domainrisk-data.json.gz "$(jq -r '.response.files[1].url' files.json)"
# Download the checksum file
curl -o domainrisk-data.json.gz.sha256 "$(jq -r '.response.files[0].url' files.json)"
# Verify the integrity
sha256sum -c domainrisk-data.json.gz.sha256

Batch processing:

Terminal window
# Download multiple files in a loop
for url in $(curl -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/download/domainrisk/?limit=24' | \
jq -r '.response.files[].url' | grep '\.json\.gz$'); do
curl -O "$url"
done

The Daily Download API provides daily batch summaries as an alternative to hourly real-time data. Use this when you need daily aggregated data rather than real-time updates. The Daily Domain Risk feed is significantly larger than the real-time feed, containing approximately 30 million domains.

Daily feed of high-risk domains, regardless of observed traffic.

Inclusion threshold: Combined Risk score of 70+

Format: Tab-separated text file (gzipped); one domain per line with component risk scores

Size: ~30 million domains, ~400MB compressed

https://api.domaintools.com/v1/download/daily_domain_risk/

The Daily Download API supports standard download parameters:

Type: string (required for HMAC and open key auth)

Your DomainTools API username

Type: string (required for open key auth)

Your DomainTools API key

Type: string (required for HMAC auth)

HMAC signature of your request

Type: string (required for HMAC auth)

Current timestamp for HMAC authentication in ISO 8601 format

Type: integer (optional)

Limit the list of signed files. Ordering of files is always descending, so the latest files are first.

Type: integer (optional)

Select which page of results are returned. Pages begin at 0 with latest results.

Type: string (optional)

Filter results by date using the file prefix.

The API returns a JSON response with signed URLs for downloadable files:

download_name (string): The feed identifier (daily_domain_risk)

files (array): List of downloadable file entries

Each file object contains:

FieldTypeDescription
namestringFile path (e.g., domain_risk_feed/threat_profile_proximity.gz)
last_modifiedstringLast modified date in ISO 8601 format
etagstringEntity tag (hash of the file)
sizeintegerSize in bytes
urlstringSigned AWS download URL (valid for 12 hours)
CodeStatusDescription
200OKThe request was successful
400Bad requestInvalid request parameters
401UnauthorizedMissing or invalid authentication
403ForbiddenInsufficient permissions
404No data to downloadNo files available

Daily files follow this naming pattern:

domain_risk_feed/threat_profile_proximity.gz

The tab-separated file contains one domain per line with the following fields:

  • Domain Name
  • Phishing (risk score)
  • Malware (risk score)
  • Spam (risk score)
  • Proximity (risk score)
  • Overall (combined risk score - equals highest of the component scores)

List available files:

Terminal window
curl -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/download/daily_domain_risk/'

Download a specific file:

Terminal window
# Get the file list
curl -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/download/daily_domain_risk/?limit=1' > files.json
# Download the file
curl -o daily-domain-risk.gz "$(jq -r '.response.files[0].url' files.json)"
# Decompress and view
gunzip daily-domain-risk.gz
head daily-domain-risk