Tutorial · Learning-oriented

Tutorial

Start here: a learning-oriented guide to making your first DETEQTIVE DNS API queries.

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:

  1. Understand what Passive DNS is and why it’s useful
  2. Make your first API query
  3. Understand the response format
  4. Search for domains and IP addresses
  5. Filter results by record type
  6. 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 eof status 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: true if query completed successfully, false on error
  • count: Total number of records returned
  • elapsed: Query execution time in seconds (e.g. 0.102)
  • error: Error message, or null if 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 addresses
  • AAAA - IPv6 addresses
  • CNAME - Canonical names (aliases)
  • MX - Mail servers
  • NS - Name servers
  • TXT - Text records
  • SOA - 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.com
  • www.google.com
  • mail.google.com
  • api.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.com
  • google.com
  • com

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.com
  • google-analytics.com
  • maps-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/24 becomes 192.0.2.0%2F24
  • 10.0.0.0/8 becomes 10.0.0.0%2F8
  • 2001:db8::/32 becomes 2001: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: Always false for errors
  • count: 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

  1. Find all A and AAAA records for your favorite website
  2. Discover all subdomains of a domain using right match
  3. Search for domains on a specific IP address
  4. Use time filters to find recently added records
  5. Search a CIDR block to map network infrastructure

Continue Learning

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