Newly Observed Hostnames (NOH)
The NOH feed offers a more granular view by listing fully qualified domain names (FQDNs) the first time they are observed on our global passive DNS sensor network. This is crucial for detecting threats like phishing and domain shadowing that often use unique subdomains on legitimate-looking domains to evade detection. The NOH feed typically has a much higher volume than the NOD feed, identifying about ninety new hostnames per second.
Overview
Section titled “Overview”This feed tracks fully qualified domain names (FQDNs) (for example, www.example.com or mail.subdomain.example.com) as they’re observed.
Use this feed when you need to:
- Detect phishing attempts that utilize unique subdomains on legitimate-looking domains
- Identify domain shadowing tactics where attackers create malicious subdomains on compromised legitimate domains
- Enhance real-time threat detection with high-volume hostname data
- Monitor subdomain creation patterns for security analysis
Inclusion criteria: Fully qualified domain names (FQDNs) observed in passive DNS for the first time.
Requirements
Section titled “Requirements”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.
Authentication
Section titled “Authentication”You can authenticate to the NOH APIs using three different methods. Choose the method that best fits your security requirements and technical environment.
API key (header) authentication
Section titled “API key (header) authentication”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:
# Feed API requestcurl -H 'X-Api-Key: YOUR_API_KEY' \ 'https://api.domaintools.com/v1/feed/noh/?sessionID=myPhishDetector'# Download API requestcurl -H 'X-Api-Key: YOUR_API_KEY' \ 'https://api.domaintools.com/v1/download/noh/'HMAC authentication
Section titled “HMAC authentication”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 usernamesignature: HMAC-SHA256 signature ofapi_username + timestamp + uri_pathtimestamp: Current UTC timestamp in ISO 8601 format (for example,2025-06-01T15:30:00Z)
Constructing the HMAC signature:
signature = HMAC-SHA256(api_key, api_username + timestamp + uri_path)Example Python signing function:
import hmacimport 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:
# Feed API request with HMACcurl 'https://api.domaintools.com/v1/feed/noh/?api_username=YOUR_USERNAME&signature=HMAC_SIGNATURE×tamp=2025-01-06T15:30:00Z&sessionID=myPhishDetector'# Download API request with HMACcurl 'https://api.domaintools.com/v1/download/noh/?api_username=YOUR_USERNAME&signature=HMAC_SIGNATURE×tamp=2025-01-06T15:30:00Z'Open key authentication
Section titled “Open key authentication”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 usernameapi_key: Your API key
Examples:
# Feed API requestcurl 'https://api.domaintools.com/v1/feed/noh/?api_username=YOUR_USERNAME&api_key=YOUR_API_KEY&sessionID=myPhishDetector'# Download API requestcurl 'https://api.domaintools.com/v1/download/noh/?api_username=YOUR_USERNAME&api_key=YOUR_API_KEY'Real-time Feed API
Section titled “Real-time Feed API”The Feed API provides real-time access to current NOH 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. Due to the high volume of this feed (~90 hostnames per second), consider using appropriate filtering and polling strategies.
Base URL
Section titled “Base URL”https://api.domaintools.com/v1/feed/noh/Rate limits
Section titled “Rate limits”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.
Response formats
Section titled “Response formats”The API supports two response formats:
NDJSON (Newline-Delimited JSON)
- Default format when no
Acceptheader is specified - Also known as JSON Lines (JSONL)
- One JSON object per line
- Efficient for streaming and processing large datasets
- Set
Accept: application/x-ndjsonto explicitly request this format
CSV (Comma-Separated Values)
- Set
Accept: text/csvto request CSV format - Add
&headers=1to 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
Section titled “Session management”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
sessionIDparameter of your choosing. By default, the API returns the past hour of results. - Resume a session: Use the same
sessionIDin 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
206response code. Repeat the same request with the samesessionIDto receive the next batch of data until you receive an HTTP200response code. - One request at a time: Do not send simultaneous requests with the same
sessionIDfor the same feed. Wait for each request to complete before sending the next one. Concurrent requests with the samesessionIDcan produce errors or incomplete results. - Delete a session: Use an HTTP
DELETErequest with yoursessionIDto 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
Quick start
Section titled “Quick start”The standard access pattern is to periodically request the most recent feed data, as often as every 60 seconds.
curl -H 'X-Api-Key: YOUR_API_KEY' \ 'https://api.domaintools.com/v1/feed/noh/?sessionID=myPhishDetector'This starts a new session and returns the last hour of data. Subsequent calls with the same sessionID return data since the last request.
Feed API parameters
Section titled “Feed API parameters”sessionID
Section titled “sessionID”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
before
Section titled “before”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
domain
Section titled “domain”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
fromBeginning
Section titled “fromBeginning”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
headers
Section titled “headers”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
Feed API response structure
Section titled “Feed API response structure”The API returns responses in NDJSON (Newline-Delimited JSON), with each response containing one domain entry per line. Each entry contains a timestamp in ISO 8601 UTC format, and the domain.
Response fields:
timestamp (string): The observation timestamp in ISO 8601 UTC format.
- Example:
"timestamp":"2024-11-15T16:14:39Z"
domain (string): The domain name without the trailing dot. Domain character set restricted by the DNS specification (letters, digits, hyphens).
- Example:
"domain":"example.com"
Example NDJSON response:
{"timestamp":"2024-11-15T16:14:39Z","domain":"domiantools.com"}{"timestamp":"2024-11-15T16:14:38Z","domain":"domsintools.com"}{"timestamp":"2024-11-15T16:14:36Z","domain":"edomaintools.com"}{"timestamp":"2024-11-15T16:14:35Z","domain":"omaintools.com"}{"timestamp":"2024-11-15T16:14:35Z","domain":"v-domaintools.com"}Example CSV response:
timestamp,domain2024-11-15T16:14:39Z,domiantools.com2024-11-15T16:14:38Z,domsintools.com2024-11-15T16:14:36Z,edomaintools.comFeed API response codes
Section titled “Feed API response codes”| Code | Status | Description |
|---|---|---|
200 | OK | The request was successful and all data has been delivered |
206 | Partial content | The 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 |
400 | Bad request | The request is malformed |
403 | Forbidden | Missing or invalid API credentials |
404 | Not found | The requested resource (such as a sessionID) doesn’t exist |
406 | Not acceptable | The specified Accept header value isn’t supported. Only application/x-ndjson and text/csv are accepted |
422 | Unprocessable entity | The request is syntactically valid but violates semantic or domain-specific rules (for example, invalid query parameter values) |
Feed API examples
Section titled “Feed API examples”Basic session polling:
# Start a new sessioncurl -H 'X-Api-Key: YOUR_API_KEY' \ 'https://api.domaintools.com/v1/feed/noh/?sessionID=myPhishDetector'# Resume the session (returns data since last request)curl -H 'X-Api-Key: YOUR_API_KEY' \ 'https://api.domaintools.com/v1/feed/noh/?sessionID=myPhishDetector'Time window filtering:
# Get data from a specific time rangecurl -H 'X-Api-Key: YOUR_API_KEY' \ 'https://api.domaintools.com/v1/feed/noh/?after=2025-01-06T10:00:00Z&before=2025-01-06T11:00:00Z'Domain filtering:
# Filter for specific hostname patterns (useful for monitoring specific domains)curl -H 'X-Api-Key: YOUR_API_KEY' \ 'https://api.domaintools.com/v1/feed/noh/?domain=*.example.com&sessionID=myPhishDetector'CSV format:
# Request CSV format with headerscurl -H 'Accept: text/csv' -H 'X-Api-Key: YOUR_API_KEY' \ 'https://api.domaintools.com/v1/feed/noh/?headers=1&sessionID=myPhishDetector'# Request CSV format without headerscurl -H 'Accept: text/csv' -H 'X-Api-Key: YOUR_API_KEY' \ 'https://api.domaintools.com/v1/feed/noh/?sessionID=myPhishDetector'Handling large result sets:
# If you receive HTTP 206, repeat the request to get the next batchcurl -H 'X-Api-Key: YOUR_API_KEY' \ 'https://api.domaintools.com/v1/feed/noh/?sessionID=myPhishDetector'# Repeat until you receive HTTP 200curl -H 'X-Api-Key: YOUR_API_KEY' \ 'https://api.domaintools.com/v1/feed/noh/?sessionID=myPhishDetector'Delete a session:
# Clear the saved offset and start freshcurl -X DELETE -H 'X-Api-Key: YOUR_API_KEY' \ 'https://api.domaintools.com/v1/feed/noh/?sessionID=myPhishDetector'Download API
Section titled “Download API”The Download API provides access to historical NOH 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.
Base URL
Section titled “Base URL”https://api.domaintools.com/v1/download/noh/Download API parameters
Section titled “Download API parameters”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
Download API response structure
Section titled “Download API response structure”The API returns a JSON response containing an array of downloadable files. Each file entry includes:
download_name (string): The feed identifier (noh)
files (array): List of downloadable file entries
Each file object contains:
name(string): Path and filename of the downloadable filelast_modified(string): Timestamp of last modification in ISO 8601 UTC formatetag(string): ETag (hash) used to verify file identity and versioningsize(integer): File size in bytesurl(string): Temporary signed URL to download the file from AWS
File naming convention:
- Data file:
noh/{YYYY-MM-DD}/noh-{YYYYMMDD}.{HH00}-{HH00}.json.gz - Checksum file:
noh/{YYYY-MM-DD}/noh-{YYYYMMDD}.{HH00}-{HH00}.json.gz.sha256
Example response:
{ "response": { "download_name": "noh", "files": [ { "name": "noh/2024-11-19/noh-20241119.1900-2000.json.gz.sha256", "last_modified": "2024-11-19T20:00:11+00:00", "etag": "\"67a6d9b0973b2d31ffb779dc8f7f8cfa\"", "size": 64, "url": "https://download.example.com/noh/2024-11-19/noh-20241119.1900-2000.json.gz.sha256?Expires=..." }, { "name": "noh/2024-11-19/noh-20241119.1900-2000.json.gz", "last_modified": "2024-11-19T20:00:11+00:00", "etag": "\"67a6d9b0973b2d31ffb779dc8f7f8cfa\"", "size": 324850, "url": "https://download.example.com/noh/2024-11-19/noh-20241119.1900-2000.json.gz?Expires=..." } ] }}Download API response codes
Section titled “Download API response codes”| Code | Status | Description |
|---|---|---|
200 | OK | The request was successful |
400 | Bad request | The request is malformed |
401 | Unauthorized | Missing or invalid API credentials |
403 | Forbidden | Missing or invalid API credentials |
404 | Not found | No data to download |
422 | Unprocessable entity | The request is syntactically valid but violates semantic or domain-specific rules (for example, invalid query parameter values) |
Download API file contents
Section titled “Download API file contents”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 and domain fields, where domain contains the full hostname).
Download API examples
Section titled “Download API examples”List available files:
# Get the most recent filescurl -H 'X-Api-Key: YOUR_API_KEY' \ 'https://api.domaintools.com/v1/download/noh/?limit=10'Download and verify a file:
# Get the file listcurl -H 'X-Api-Key: YOUR_API_KEY' \ 'https://api.domaintools.com/v1/download/noh/?limit=2' > files.json
# Extract the URL and download the data filecurl -o noh-data.json.gz "$(jq -r '.response.files[1].url' files.json)"
# Download the checksum filecurl -o noh-data.json.gz.sha256 "$(jq -r '.response.files[0].url' files.json)"
# Verify the integritysha256sum -c noh-data.json.gz.sha256Batch processing:
# Download multiple files in a loopfor url in $(curl -H 'X-Api-Key: YOUR_API_KEY' \ 'https://api.domaintools.com/v1/download/noh/?limit=24' | \ jq -r '.response.files[].url' | grep '\.json\.gz$'); do curl -O "$url"done