Domain History API¶
Note
The Domain History API endpoint is also specified in the Lookups and Monitor OpenAPI specification.
Quick start¶
# Show ownership changes for chat.com
curl -H 'X-Api-Key: YOUR_API_KEY' 'https://api.domaintools.com/v1/domain-history/?domain=chat.com&include_fields=registrar'
Introduction¶
The Domain History API provides access to DomainTools' record of changes to a domain's infrastructure, registration, and content. Track the evolution of domains across their lifecycle and identify significant events such as infrastructure weaponization, service changes, or registration transfers.
This API delivers change events that show what changed, when it changed, and the before/after states for each modification. Use field filtering to focus on specific types of changes relevant to your investigation.
Core concepts¶
Change Events¶
Each change event in the response includes:
- timestamp: When the change was detected (ISO 8601 format, an international standard for date and time representation)
- field: The specific property that changed (e.g.,
ip,mx,registrar) - before: The complete state before the change
- after: The complete state after the change
Note: When a domain starts a new registration lifecycle, the before field may be null or empty. The API only tracks changes within a given lifecycle, so previous lifecycle data is not included in history events.
Registration Source¶
The API uses one of two data sources for registration information:
- parsed_whois: Traditional WHOIS data, parsed and normalized
- parsed_domain_rdap: RDAP (Registration Data Access Protocol) data, the modern successor to WHOIS
The registration_source field indicates which source the API used. By default, the API uses parsed_whois as the registration source. The API switches to RDAP data only when you explicitly request it or when RDAP is the only available source for the domain.
Active Registration Period¶
The active field in change events indicates whether a domain was actively registered at the time of the change (this field corresponds to the status field in the DomainTools user interface). Use this to distinguish modifications during the current registration period from changes in prior lifecycles.
Historical Coverage¶
Domain History launched in October 2021. For domains that were active before this date:
- No history event records the initial transition to active status
- History events only capture changes that occurred after October 2021
- The domain's state at launch serves as the baseline for subsequent change tracking
Field Filtering Behavior¶
Field filtering operates at the event level, not the property level:
- Filtering determines which change events appear in the response
- Each returned event includes the complete
beforeandafterobjects for that field - Filtering doesn't remove properties from the
beforeandafterobjects
Use cases¶
Detect infrastructure weaponization¶
Pinpoint when a domain's infrastructure was weaponized by isolating changes in IP addresses, name servers, or mail servers.
Example workflow:
- Filter for infrastructure changes using
include_fields=ip,nameserver_host,mailserver_host - Review the
activefield to identify changes during the current registration - Examine the timeline to determine when the domain was brought online for a campaign
Monitor service activation¶
Determine when a domain launched a functional service by identifying the first SSL certificate issuance.
Example workflow:
- Filter for SSL changes using
include_fields=ssl_hash(or other SSL-related fields) - Find the earliest timestamp where an SSL certificate appears in the
afterstate - Correlate with other infrastructure changes to understand service deployment
Identify ownership changes¶
Reveal transfers of domain ownership by comparing registrar and registrant data across distinct registration lifecycles.
Example workflow:
- Filter for registration changes using
include_fields=registrar,registrant,create_date,expiration_date - Look for changes in
registrarorregistrantfields - Use the
activefield to distinguish between registration periods
Authentication¶
The Domain History API supports three authentication methods.
Header authentication¶
Include your API key in the X-Api-Key header:
curl -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/domain-history/?domain=example.com'
HMAC authentication¶
HMAC (Hash-based Message Authentication Code) authentication provides enhanced security by signing each request with a hash derived from your API secret. See the Authentication Guide for implementation details.
Open key authentication¶
Pass your credentials as query parameters. This method is less secure and not recommended for production use. See the Authentication Guide for implementation details.
Request parameters¶
Required parameters¶
| Parameter | Description | Example |
|---|---|---|
domain |
The domain name to retrieve history for | domaintools.com |
Filtering parameters¶
| Parameter | Description | Example |
|---|---|---|
include_fields |
Comma-separated list of fields to include. Only change events matching these fields appear in results. | ip,mx,name_server |
exclude_fields |
Comma-separated list of fields to exclude. Change events matching these fields are omitted from results. | ssl_information,web_trackers_information |
Pagination parameters¶
| Parameter | Description | Default | Example |
|---|---|---|---|
page_size |
Number of results per page. Maximum is 100 entries per request. | 100 | 50 |
offset |
Starting point for results (0-indexed). Controls pagination across large result sets. Note: Real-time delays between paginated requests may result in duplicate data, as new changes can occur between requests. | 0 | 500 |
next |
Boolean flag. When set to true, includes a next URL in the response for cursor-based pagination. Authentication parameters must still be included when following the next URL. |
false |
true |
Registration data source flags¶
| Parameter | Description | Default |
|---|---|---|
parsed_whois |
Include full parsed WHOIS record in before and after objects |
false |
parsed_domain_rdap |
Include full parsed Domain RDAP record in before and after objects |
false |
Optional parameters¶
| Parameter | Description | Example |
|---|---|---|
format |
Response format (json, xml, html) |
json |
app_partner |
Your product name (for debugging) | MySecurityPlatform |
app_name |
Your appliance, module, or playbook name | ThreatIntel |
app_version |
Your integration version | 2.1.0 |
Understanding field filtering¶
How filtering works¶
Field filtering determines which change events appear in the response based on the field property of each event. When you filter:
- The API evaluates each change event's
fieldvalue - Events matching your filter criteria are included
- Events not matching are excluded
- Each included event contains its complete
beforeandafterobjects
Important: Filtering doesn't remove properties from the before and after objects. It determines which entire change events are returned.
Parameter format requirements¶
The include_fields and exclude_fields parameters accept a specific format:
Required format:
- Comma-separated list of exact field names
- No spaces before or after commas
- Field names must match exactly (case-sensitive)
Valid examples:
What is NOT supported:
- Wildcards or patterns (e.g.,
ssl_*,*_email) - Regular expressions
- Partial matches
- Ranges
- Spaces in the list (e.g.,
ip, mxis invalid) - Other delimiters besides commas
Only exact field name matches work. If you need multiple related fields, use the aggregate field categories (prefixed with all_) rather than attempting pattern matching.
Individual vs. aggregate field filtering¶
You can filter change events using either individual field names or aggregate field groups:
Individual fields target specific properties:
- Use when you need precise control over which change types to include
- Example:
include_fields=ip,registrarreturns only IP address and registrar changes
Aggregate fields (prefixed with all_) group related individual fields:
- Use when you want all changes within a category
- Example:
include_fields=all_sslreturns changes for any SSL-related field (ssl_hash, ssl_common_name, ssl_alt_names, ssl_not_before, ssl_not_after) - More efficient than listing multiple individual fields
Filtering behavior:
- When you specify an aggregate field, the API returns events for any of its included individual fields
- You can mix individual and aggregate fields in the same request
- Example:
include_fields=ip,all_sslreturns IP changes plus all SSL-related changes
Valid field names¶
Fields are organized by category. Each category shows the aggregate field (if available) that returns events for any of the individual fields in that category.
Contact Information:
- Aggregate:
all_contact_information— Returns events for any contact-related field - Individual fields:
contact_name,contact_phone,contact_street,contact_city,contact_state,contact_fax,contact_organization
Email:
- Aggregate:
all_emails— Returns events for any email field - Individual fields:
admin_contact_email,billing_contact_email,email_dns_soa,technical_contact_email,registrant_contact_email,additional_whois_email
IP & Network:
- Aggregate:
all_ip— Returns events for any IP-related field - Individual fields:
ip,asn,ip_country_code,isp_name
Mail Server:
- Aggregate:
all_mailserver— Returns events for any mail server field - Individual fields:
mailserver_host,mailserver_ip
Name Server:
- Aggregate:
all_nameserver— Returns events for any name server field - Individual fields:
nameserver_host,nameserver_ip
SSL:
- Aggregate:
all_ssl— Returns events for any SSL field - Individual fields:
ssl_hash,ssl_common_name,ssl_alt_names,ssl_not_before,ssl_not_after
Web Content:
- Aggregate:
all_web_content— Returns events for any web content field - Individual fields:
redirect,redirect_domain,screenshot_collected_timestamp,server_type,website_response,website_title
Web Trackers:
- Aggregate:
all_web_trackers— Returns events for any web tracker field - Individual fields:
adsense,baidu_analytics,facebook,google_analytics,ga4,google_tag_manager,hotjar,matomo,statcounter_project,statcounter_security,yandex_metrica
Registration:
- Individual fields:
create_date,expiration_date,registrant,registrar,registrar_status,active
Other:
- Aggregate:
all_other— Returns events for remaining uncategorized fields
Discovering available fields¶
To get a complete list of valid field names, provide an invalid field name in your request. The API returns an error message listing all valid options.
Example:
curl -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/domain-history/?domain=example.com&include_fields=invalid_field_name'
Filtering examples¶
Include only infrastructure changes:
# Returns events where field: "ip", "mx", or "name_server"
curl -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/domain-history/?domain=example.com&include_fields=ip,mailserver_host,nameserver_host'
Exclude web trackers and SSL information:
# Excludes events where field matches tracking codes or "ssl_info"
curl -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/domain-history/?domain=example.com&exclude_fields=all_web_trackers,all_ssl'
Focus on registration lifecycle events:
# Returns events where field: "create_date", "expiration_date", "registrar", "registrant", or "active"
curl -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/domain-history/?domain=example.com&include_fields=create_date,expiration_date,registrar,registrant,active'
Response structure¶
Response format¶
{
"response": {
"domain": "example.com",
"count": 1234,
"registration_source": "parsed_whois",
"changes": [
{
"timestamp": "2025-10-14T09:44:26Z",
"field": "mx",
"before": { ... },
"after": { ... }
}
]
}
}
Result ordering¶
The API returns change events in the changes array in reverse chronological order, with the most recent changes appearing first. This ordering applies to the timestamp field of each change event.
Response fields¶
| Field | Description |
|---|---|
domain |
The domain name queried |
count |
Total number of historical changes available |
registration_source |
Data source used (parsed_whois or parsed_domain_rdap) |
changes |
Array of change events |
Change event structure¶
Each change event contains:
| Field | Description |
|---|---|
timestamp |
ISO 8601 timestamp when the change was detected |
field |
The property that changed |
before |
Complete state before the change (EnrichResult object) |
after |
Complete state after the change (EnrichResult object) |
EnrichResult objects¶
The before and after objects contain comprehensive domain profile data representing the state at that point in time. Available properties include:
- Domain information:
domain,tld,first_seen,active - Infrastructure:
ip,mx,name_server,ssl_info - Registration:
create_date,expiration_date,registrar,registrant_name,registrant_org - Contacts:
admin_contact,billing_contact,registrant_contact,technical_contact - Web content:
website_title,website_response,server_type,redirect,redirect_domain - Trackers:
adsense,google_analytics,ga4,gtm_codes,fb_codes, and others - Risk:
domain_risk(withrisk_scoreandcomponents) - Enrichment:
parsed_whois,parsed_domain_rdap(when requested)
Common workflows¶
Get all changes for a domain¶
Retrieve the complete change history without filtering:
curl -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/domain-history/?domain=example.com'
Filter for infrastructure changes only¶
Focus on IP, name server, and mail server modifications:
curl -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/domain-history/?domain=example.com&include_fields=ip,nameserver_host,mailserver_host'
Track registration changes across lifecycles¶
Monitor registrar and registrant modifications:
curl -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/domain-history/?domain=example.com&include_fields=registrar,registrant,create_date,expiration_date,active'
Paginate through large result sets¶
Handle domains with extensive change history:
# First page
curl -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/domain-history/?domain=example.com&page_size=100&offset=0'
# Second page
curl -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/domain-history/?domain=example.com&page_size=100&offset=100'
Combine with parsed WHOIS data¶
Include full parsed WHOIS records in the response:
curl -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/domain-history/?domain=example.com&parsed_whois=true&include_fields=registrar,registrant'
Best practices¶
Choosing between include_fields and exclude_fields¶
Use include_fields when:
- You need a specific subset of change types
- You want to focus on a particular investigation area
- You're building targeted alerts or monitoring
Use exclude_fields when:
- You want most changes but need to filter out noise
- You're excluding large categories (e.g., web trackers)
- You need everything except a few specific types
Don't use both parameters in the same request. If both are provided, the API behavior is undefined.
Pagination strategies¶
For large result sets:
- Start with a reasonable
page_size(100-500) - Use the
offsetparameter to navigate through pages - Implement retry logic for network failures
- Consider rate limits when processing multiple domains
For targeted investigations:
- Use field filtering to reduce result volume
- Smaller page sizes (50-100) for faster initial response
- Process pages as needed rather than fetching all data upfront
Combining with other DomainTools APIs¶
Domain History complements:
- Hosting History: Domain History provides granular change events; Hosting History provides summarized infrastructure timeline
- WHOIS History: Domain History includes registration changes; WHOIS History provides raw WHOIS records
- Iris Investigate: Use Domain History to understand how a domain reached its current state shown in Iris
Workflow example:
- Use Iris Investigate to identify a suspicious domain
- Query Domain History to understand its evolution
- Filter for infrastructure changes during active registration
- Cross-reference with WHOIS History for detailed registration records
Rate limits and quotas¶
Your subscription level determines rate limits and quotas. Monitor your usage through the Account Information endpoint:
Best practices:
- Implement exponential backoff for rate limit errors (HTTP 429)
- Cache results when appropriate to reduce API calls
- Use field filtering to minimize response size and processing time
- Batch domain queries when investigating multiple domains
Troubleshooting¶
Understanding field names¶
Problem: Unsure which field names are valid for filtering.
Solution: Make a request with an invalid field name to receive a complete list:
curl -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/domain-history/?domain=example.com&include_fields=show_me_all_fields'
The error response includes all valid field names.
Handling large response sets¶
Problem: Response contains thousands of changes, making it difficult to process.
Solution: Use field filtering to focus on relevant changes:
# Instead of retrieving all changes
curl -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/domain-history/?domain=example.com'
# Filter for specific change types
curl -H 'X-Api-Key: YOUR_API_KEY' \
'https://api.domaintools.com/v1/domain-history/?domain=example.com&include_fields=ip,registrar'
Empty results¶
Problem: Query returns no changes or fewer changes than expected.
Possible causes:
- Domain has no history: Newly registered domains may not have change events yet
- Historical coverage limitation: For domains active before October 2021, no history event records the initial active status. Only changes after the October 2021 launch are captured.
- Overly restrictive filtering: Your
include_fieldsorexclude_fieldsparameters may filter out all events - Domain not found: Verify the domain name is correct and uses the apex domain (e.g.,
example.com, notwww.example.com)
Solution: Start with an unfiltered query to verify data exists, then add filtering incrementally.
Pagination issues¶
Problem: Pagination seems to skip results.
Solution: Increment the offset parameter by the page_size value for each request. For example, with page_size=100, use offset=0 for the first page, offset=100 for the second page, and offset=200 for the third page.
Authentication errors¶
Problem: Receiving 401 Unauthorized errors.
Solutions:
- Verify your API key is correct and active
- Check that the
X-Api-Keyheader is properly formatted - For HMAC authentication, ensure the timestamp is current (within 5 minutes)
- Confirm your account has access to the Domain History API
Rate limit errors¶
Problem: Receiving 429 Too Many Requests errors.
Solutions:
- Implement exponential backoff: wait before retrying
- Check your rate limits via the Account Information endpoint
- Reduce request frequency
- Contact DomainTools support to discuss quota increases
Additional resources¶
- Domain History API Reference: Complete OpenAPI specification
- Authentication Guide: Detailed authentication methods
- Hosting History API: Summarized infrastructure timeline
- WHOIS History API: Historical WHOIS records
- Iris Investigate: Comprehensive domain intelligence platform
For additional assistance, contact DomainTools Enterprise Support at enterprisesupport@domaintools.com.