DomainTools Python API
The DomainTools Python API Wrapper provides a unified interface to interact with DomainTools' cybersecurity and threat intelligence products, including Iris Investigate, Iris Enrich, Iris Detect, Lookups, Monitors, and Threat Feeds. It is actively maintained, currently at version 2.7.3, with frequent minor releases addressing bugs and ensuring API parity.
Common errors
-
ModuleNotFoundError: No module named 'domaintools' OR ImportError: cannot import name 'API' from 'domaintools'
cause You might have installed a different, unrelated `domaintools` package (for domain parsing) instead of `domaintools-api`, or both are installed causing conflicts.fixEnsure you explicitly install `domaintools-api` and uninstall any conflicting `domaintools` package: `pip uninstall domaintools` (if present) then `pip install domaintools-api --upgrade`. -
domaintools.exceptions.NotAuthorizedException: 401 Unauthorized
cause The provided API username or key is incorrect, expired, or missing.fixVerify your `DOMAINTOOLS_USERNAME` and `DOMAINTOOLS_API_KEY` environment variables or the credentials passed to `API()`. Double-check for typos and ensure your API key is still active in your DomainTools account portal. -
domaintools.exceptions.ForbiddenException: 403 Forbidden
cause Your DomainTools account does not have the necessary permissions or subscription level to access the requested API endpoint or product.fixContact your DomainTools account manager or support to verify that your subscription includes access to the specific API product (e.g., Iris Investigate, Iris Enrich, a particular Threat Feed) you are trying to use. -
HTTP 206 Partial Content
cause For certain large data endpoints, especially Threat Feeds, the API may return partial results with a 206 status code, indicating that more data is available.fixIf `sessionID` was used, repeat the same request with the same `sessionID` to retrieve the next tranche of data until a `200 OK` response is received. The SDK's iteration over feed results typically handles this automatically, but be aware of it if manually processing responses.
Warnings
- gotcha The SDK primarily uses HMAC-signed authentication by default, which is the most secure method. However, Threat Feeds (e.g., NOD, NAD) automatically switch to header-based authentication. The SDK handles this transparently, but it's important context for custom authentication logic or troubleshooting.
- gotcha API calls return a response object. To access the raw data returned by DomainTools, use `.data()`. To get the actionable response content (typically a dictionary or list), use `.response()`. Direct attribute access (e.g., `profile['field']`) is also possible for specific results.
- gotcha The library handles API rate limiting automatically. However, if a `503 Service Unavailable` error is received, it typically indicates a temporary service unavailability or a hard rate limit hit.
- breaking Versions prior to 2.6.1 had an issue where `Accept-Encoding` was not set to 'identity', causing decompression issues with `iter_lines` for streaming RTTF endpoints. This could lead to malformed or incomplete streaming data.
- breaking In versions prior to 2.7.3, the `iris_investigate` function would occasionally return missing `risk_score` values even when expected.
Install
-
pip install domaintools-api --upgrade
Imports
- API
import domaintools
from domaintools import API
Quickstart
import os
from domaintools import API
# Best practice: Store credentials securely in environment variables
username = os.environ.get('DOMAINTOOLS_USERNAME', 'your_username')
api_key = os.environ.get('DOMAINTOOLS_API_KEY', 'your_api_key')
# Initialize the API client
try:
api = API(username, api_key)
# Example 1: Domain Profile lookup
profile_result = api.domain_profile('example.com')
print(f"Domain Profile for example.com: {profile_result.response()['domain']}")
# Example 2: Iris Enrich
enrich_result = api.iris_enrich('domaintools.com')
for domain_data in enrich_result.response().get('results', {}):
print(f"Enriched domain: {domain_data['domain']}, Risk Score: {domain_data['domain_risk']['risk_score']}")
break # Just print one for brevity
# Example 3: Real-Time Threat Feed (New Observed Domains - NOD)
# Threat Feeds automatically use header authentication, handled by SDK
# Use sessionID for pagination or 'after' parameter for time range
nod_feed = api.nod(after=-3600) # Last hour
for record_json in nod_feed.response():
# Records are JSON strings, need to parse them
import json
record = json.loads(record_json)
print(f"New observed domain from feed: {record['domain']}")
break # Just print one for brevity
except Exception as e:
print(f"An error occurred: {e}")
if username == 'your_username' or api_key == 'your_api_key':
print("Please set DOMAINTOOLS_USERNAME and DOMAINTOOLS_API_KEY environment variables or replace placeholders.")