Tutorial: Getting Started with DETEQTIVE DNS API
Learning-oriented: This tutorial will guide you through your first steps with the DETEQTIVE DNS API, from understanding what passive DNS is to making your first successful queries.
Authentication
All API requests require a Bearer token. Set it once in your shell and all examples will work:
export DETEQTIVE_TOKEN="your-api-token-here"
What You’ll Learn
By the end of this tutorial, you’ll be able to:
- Understand what Passive DNS is and why it’s useful
- Make your first API query
- Understand the response format
- Search for domains and IP addresses
- Filter results by record type
- Use time-based filtering
Prerequisites
curl -H "Authorization: Bearer $DETEQTIVE_TOKEN"command-line tool (or any HTTP client)- Access to a DETEQTIVE DNS API server
- Basic understanding of DNS concepts
Step 1: Understanding Passive DNS
Passive DNS is a database of historical DNS records collected over time. Unlike active DNS queries (where you ask a DNS server “what is the IP for google.com right now?”), passive DNS lets you ask:
- “What IP addresses has google.com used historically?”
- “What domains have pointed to IP 142.250.185.46?”
- “When was this DNS record first seen?”
- “How many times was this record observed?”
This is invaluable for:
- Security research and threat intelligence
- Infrastructure change tracking
- Domain validation and verification
- Historical data analysis
Step 2: Your First Query
Let’s start with the simplest possible query: looking up all A records for google.com.
curl -H "Authorization: Bearer $DETEQTIVE_TOKEN" https://api.deteqtive.com/api/v3/rrset/em/google.com/A
Let’s break down this URL:
https://api.deteqtive.com- The API server/api/v3- API version/rrset- Forward search (search by domain name)/em- Exact Match search type/google.com- The domain to search for/A- Filter for A records only
Understanding the Response
You’ll see output like this (newline-delimited JSON):
{"rrname":"google.com","rrtype":"A","rdata":"142.250.185.46","first_seen":"2023-01-01T12:00:00Z","last_seen":"2023-12-31T23:59:59Z","sightings":1542}
ins
{"eof":true,"count":2,"elapsed":0.102,"error":null}
Each line is a separate JSON object:
- Lines 1-2: DNS records with their data
- Line 3: Status message indicating completion
- Important: If the final
eofstatus line is missing, the response was truncated (connection lost, timeout, etc.) - Note: Results are not sorted - repeated queries may return the same records in different order
DNS Record Fields
Each DNS record contains:
rrname: Resource Record Name (the domain)rrtype: Record Type (A, AAAA, CNAME, MX, etc.)rdata: Record Data (the IP address, hostname, etc.)first_seen: When this record was first observed (ISO 8601 timestamp)last_seen: When this record was last observed (ISO 8601 timestamp)sightings: Number of times this record was seen
Status Message Fields
The final line contains:
eof:trueif query completed successfully,falseon errorcount: Total number of records returnedelapsed: Query execution time in seconds (e.g.0.102)error: Error message, ornullif no error
Step 3: Search by IP Address (Reverse DNS)
Now let’s search the other direction: find all domains that have pointed to a specific IP address.
curl -H "Authorization: Bearer $DETEQTIVE_TOKEN" https://api.deteqtive.com/api/v3/rdata/142.250.185.46
Let’s break down this URL:
/rdata- Reverse search (search by RDATA field, which contains IPs)/142.250.185.46- The IP address to search for
This returns all DNS records where this IP appears in the RDATA field.
Example response:
{"rrname":"google.com","rrtype":"A","rdata":"142.250.185.46","first_seen":"2023-01-01T12:00:00Z","last_seen":"2023-12-31T23:59:59Z","sightings":1542}
{"rrname":"www.google.com","rrtype":"A","rdata":"142.250.185.46","first_seen":"2023-01-10T14:20:00Z","last_seen":"2023-12-28T19:30:00Z","sightings":845}
{"eof":true,"count":2,"elapsed":0.102,"error":null}
Step 4: Exploring Different DNS Record Types
DNS has many record types beyond just A records. Let’s look up MX (Mail Exchange) records:
curl -H "Authorization: Bearer $DETEQTIVE_TOKEN" https://api.deteqtive.com/api/v3/rrset/em/google.com/MX
Example response:
{"rrname":"google.com","rrtype":"MX","rdata":"10 smtp.google.com","first_seen":"2023-01-01T00:00:00Z","last_seen":"2023-12-31T23:59:59Z","sightings":2500}
{"eof":true,"count":1,"elapsed":0.102,"error":null}
Common Record Types
Try these different record types:
A- IPv4 addressesAAAA- IPv6 addressesCNAME- Canonical names (aliases)MX- Mail serversNS- Name serversTXT- Text recordsSOA- Start of Authority
Tip: Omit the record type to get ALL record types:
curl -H "Authorization: Bearer $DETEQTIVE_TOKEN" https://api.deteqtive.com/api/v3/rrset/em/google.com
Step 5: Limiting Results
Some queries might return thousands of results. Use the limit parameter to control this:
curl -H "Authorization: Bearer $DETEQTIVE_TOKEN" "https://api.deteqtive.com/api/v3/rrset/em/google.com?limit=10"
Important: When using query parameters, wrap the URL in quotes!
The limit parameter:
- Minimum: 1
- Maximum: 50,000
- Default: 1,000
Step 6: Different Search Types
So far we’ve used em (Exact Match). Let’s explore other search types.
Right Match (Subdomains)
Find a domain AND all its subdomains:
curl -H "Authorization: Bearer $DETEQTIVE_TOKEN" "https://api.deteqtive.com/api/v3/rrset/rm/google.com?limit=5"
This returns:
google.comwww.google.commail.google.comapi.google.com- etc.
Use case: Discovering infrastructure and subdomains
Left Match (Parent Domains)
Find a domain AND all its parent domains:
curl -H "Authorization: Bearer $DETEQTIVE_TOKEN" "https://api.deteqtive.com/api/v3/rrset/lm/www.google.com?limit=5"
This returns:
www.google.comgoogle.comcom
Use case: Understanding domain hierarchy
Fuzzy Match (Similar Domains)
Find domains similar to your search term:
curl -H "Authorization: Bearer $DETEQTIVE_TOKEN" "https://api.deteqtive.com/api/v3/rrset/fm/gogle.com?fuzziness=2&limit=5"
This might return:
google.com(1 character different)goggle.com(1 character different)- etc.
Use case: Typosquatting detection, finding similar domains
Word Match (Contains Token)
Find domains containing a specific word:
curl -H "Authorization: Bearer $DETEQTIVE_TOKEN" "https://api.deteqtive.com/api/v3/rrset/wm/google?limit=5"
This might return:
google.comgoogle-analytics.commaps-google-apis.com- etc.
Use case: Brand monitoring, finding related domains
Step 7: Time-Based Filtering
Filter results by when they were observed:
Records first seen after January 1, 2024
curl -H "Authorization: Bearer $DETEQTIVE_TOKEN" "https://api.deteqtive.com/api/v3/rrset/em/google.com/A?first_seen_after=1704067200"
Note: Use Unix timestamps (seconds since 1970-01-01)
Records seen in a specific time window
curl -H "Authorization: Bearer $DETEQTIVE_TOKEN" "https://api.deteqtive.com/api/v3/rrset/em/google.com/A?first_seen_after=1704067200&first_seen_before=1735689599"
Time filter parameters
first_seen_after- Records first observed after this timestamp (default: none)first_seen_before- Records first observed before this timestamp (default: none)last_seen_after- Records last observed after this timestamp (default: 14 days ago)last_seen_before- Records last observed before this timestamp (default: now)
Important: By default, queries return only records seen in the last 14 days. To search all historical data, set last_seen_after=0.
Tip: Combine filters for precise time ranges!
Step 8: Searching CIDR Blocks
Search for all domains pointing to IPs in a network range:
curl -H "Authorization: Bearer $DETEQTIVE_TOKEN" "https://api.deteqtive.com/api/v3/rdata/8.8.8.0%2F24/A?limit=10"
Important: The / in CIDR notation must be URL-encoded as %2F!
Examples:
192.0.2.0/24becomes192.0.2.0%2F2410.0.0.0/8becomes10.0.0.0%2F82001:db8::/32becomes2001:db8::%2F32
Step 9: Including Bailiwick Information
Bailiwick is the DNS zone where a record was observed. To include it:
curl -H "Authorization: Bearer $DETEQTIVE_TOKEN" "https://api.deteqtive.com/api/v3/rrset/em/google.com/SOA?withbailiwick"
Response with bailiwick:
{"bailiwick":"google.com","rrname":"google.com","rrtype":"SOA","rdata":"ns1.google.com. dns-admin.google.com. 2023120100 900 900 1800 60","first_seen":"2023-01-01T00:00:00Z","last_seen":"2023-12-31T23:59:59Z","sightings":3000}
{"eof":true,"count":1,"elapsed":0.102,"error":null}
Notice the bailiwick field is now included.
Note: Boolean parameters like withbailiwick are flags - just include them, no value needed!
Step 10: Handling Errors
Sometimes queries fail. Here’s what error responses look like:
{"eof":false,"count":0,"elapsed":0.002,"error":"query timeout - please refine your search or try again later"}
Error response structure:
eof: Alwaysfalsefor errorscount: Number of records returned before error (usually 0)error: User-friendly error message
Common Error Messages
“query timeout - please refine your search or try again later”
- Your query took too long (>120 seconds)
- Solution: Add more filters, reduce limit, or be more specific
“a temporary error occurred - please try again later”
- Temporary issue on our side
- Solution: Retry your request
“the request could not be completed - please check your search parameters”
- Problem with your query
- Solution: Check your parameters and syntax
“an error occurred while processing your request”
- Generic error
- Solution: Check your query and try again
Step 11: Processing Responses with jq
The response format (NDJSON) works great with jq:
Note: Results are not sorted - if you need consistent ordering, sort them yourself.
Extract only DNS records (skip status message)
curl -H "Authorization: Bearer $DETEQTIVE_TOKEN" https://api.deteqtive.com/api/v3/rrset/em/google.com/A | jq -c 'select(.rrname)'
Extract only status message
curl -H "Authorization: Bearer $DETEQTIVE_TOKEN" https://api.deteqtive.com/api/v3/rrset/em/google.com/A | jq -c 'select(.eof)'
Pretty print each record
curl -H "Authorization: Bearer $DETEQTIVE_TOKEN" https://api.deteqtive.com/api/v3/rrset/em/google.com/A | jq 'select(.rrname)'
Extract specific fields
curl -H "Authorization: Bearer $DETEQTIVE_TOKEN" https://api.deteqtive.com/api/v3/rrset/em/google.com/A | jq -r 'select(.rrname) | "\(.rrname) -> \(.rdata)"'
Output:
google.com -> 142.250.185.46
google.com -> 142.250.185.78
Note: Order may vary between queries - add | sort if you need consistent ordering.
What’s Next?
Congratulations! You now know the basics of using the DETEQTIVE DNS API. Here’s where to go next:
Practice Exercises
- Find all A and AAAA records for your favorite website
- Discover all subdomains of a domain using right match
- Search for domains on a specific IP address
- Use time filters to find recently added records
- Search a CIDR block to map network infrastructure
Continue Learning
- How-To Guides - Specific tasks and solutions
- Reference - Complete API documentation
- Explanation - Deep dive into concepts
Generate a Client Library
Instead of using curl -H “Authorization: Bearer $DETEQTIVE_TOKEN”, generate a client library in your favorite language.
Step 1: Download the OpenAPI specification
curl -H "Authorization: Bearer $DETEQTIVE_TOKEN" https://api.deteqtive.com/api/v3/openapi/pdns.yaml > deteqtive-api-spec.yaml
Step 2: Generate the client (example: Python)
# Install generator (one time)
npm install -g @openapitools/openapi-generator-cli
# Generate Python client
npx @openapitools/openapi-generator-cli generate \
-i deteqtive-api-spec.yaml \
-g python \
-o ./deteqtive-python-client \
--package-name deteqtive_client
# Install the client
cd deteqtive-python-client
pip install -e .
Step 3: Use the client
import deteqtive_client
from deteqtive_client.api import default_api
configuration = deteqtive_client.Configuration()
configuration.host = "https://api.deteqtive.com/api/v3"
configuration.verify_ssl = False
with deteqtive_client.ApiClient(configuration) as api_client:
api = default_api.DefaultApi(api_client)
result = api.search_rr_set_with_type("em", "google.com", "A", limit=10)
print(result)
See How-To: Generate API Clients for complete examples in Python, Go, TypeScript, and other languages.
Quick Reference Card
# Forward search (by domain)
curl -H "Authorization: Bearer $DETEQTIVE_TOKEN" https://api.deteqtive.com/api/v3/rrset/{type}/{domain}/{rrtype}
# Reverse search (by IP)
curl -H "Authorization: Bearer $DETEQTIVE_TOKEN" https://api.deteqtive.com/api/v3/rdata/{ip}/{rrtype}
# Search types
em = exact match
rm = right match (subdomains)
lm = left match (parent domains)
fm = fuzzy match (similar)
wm = word match (contains)
# Common parameters
?limit=100 # Limit results
?withbailiwick # Include bailiwick
?first_seen_after=1704067200 # Time filter
?fuzziness=2 # Fuzzy match threshold
Troubleshooting
Q: I’m getting SSL certificate errors
A: Use the -k flag with curl -H “Authorization: Bearer $DETEQTIVE_TOKEN” to skip certificate verification (for development)
Q: I’m getting timeout errors A: Your query is too broad. Add filters: limit, record type, time range
Q: How do I know how many results I got?
A: Check the count field in the final status message
Q: Can I combine multiple filters?
A: Yes! Use & to combine: ?limit=10&withbailiwick&first_seen_after=1704067200
Q: Why do I get different order when running the same query twice?
A: Results are not sorted for performance reasons. If you need consistent ordering, sort them yourself: | jq -s 'sort_by(.rdata)'
Ready for specific tasks? Continue to How-To Guides