API Documentation

Integrate DNSai DNS intelligence into your systems with the REST API

Overview Authentication Getting Started AI-Assisted Dev Endpoints Reference Field Reference Rate Limits & Quotas Error Handling Security Best Practices Integrations
Salesforce Integration HubSpot Integration SIEM Integration

Overview

The DNSai REST API provides programmatic access to your DNS intelligence data. Use it to integrate domain monitoring, scan results, WHOIS data, and change history into your existing tools and workflows.

The API is available on Enterprise plans and above:

  • Enterprise ($99/mo) — 100 requests/min, 10,000 calls/day
  • Enterprise Max ($2,500/mo) — 500 requests/min, 50,000 calls/day
  • Enterprise Max Premium ($5,000/mo) — 2,000 requests/min, 200,000 calls/day

All API endpoints are under https://app.dnsai.com/api/v1/ and return JSON responses in a consistent envelope format.

Create a free account   or log in →

Authentication

The API uses Bearer token authentication with API keys. Each API key is a long random string prefixed with dnsai_live_.

Creating an API Key

API access is available on Enterprise plans. Create an account or log in, then:

  1. Go to Settings > API Keys
  2. Click Create New API Key
  3. Give your key a descriptive name (e.g., "Production Server")
  4. Copy the key immediately — it is shown only once and cannot be retrieved later

You can have up to 3 active API keys at a time.

Using Your API Key

Include your API key in the Authorization header of every request:

HTTP Header
Authorization: Bearer dnsai_live_YOUR_API_KEY_HERE
Important: Never share your API key or commit it to source control. If a key is compromised, revoke it immediately from Settings and create a new one.

Getting Started

Get up and running in minutes. The examples below cover the most common operations. All responses use a consistent JSON envelope with data, meta, and errors fields.

1. Set Up Your API Key

Environment Variable (recommended)
# Store your key in an environment variable — never hardcode it
export DNSAI_API_KEY="dnsai_live_YOUR_KEY_HERE"

2. Make Your First Request

curl
curl -H "Authorization: Bearer $DNSAI_API_KEY" \
     https://app.dnsai.com/api/v1/domains/
Python
import os, requests

API_KEY = os.environ["DNSAI_API_KEY"]
headers = {"Authorization": f"Bearer {API_KEY}"}

# List your domains (default: 250 per request, max: 5000)
response = requests.get(
    "https://app.dnsai.com/api/v1/domains/",
    headers=headers,
    params={"limit": 1000},  # fetch up to 1000
)
result = response.json()
print(f"Got {len(result['data'])} of {result['meta']['total_count']} domains")

for domain in result["data"]:
    print(domain["domain"], domain["email_gateway"])
JavaScript
const API_KEY = "dnsai_live_YOUR_KEY";

const response = await fetch("https://app.dnsai.com/api/v1/domains/?limit=1000", {
  headers: { "Authorization": `Bearer ${API_KEY}` },
});
const { data, meta } = await response.json();
console.log(`Got ${data.length} of ${meta.total_count} domains`);
data.forEach(d => console.log(d.domain, d.email_gateway));

3. Fetch All Pages

For large datasets, follow meta.next to iterate through all pages. Quotas count API calls, not rows — fetching 5,000 rows counts as 1 call.

Python — Fetch All Domains
url = "https://app.dnsai.com/api/v1/domains/?limit=5000"
all_domains = []

while url:
    response = requests.get(url, headers=headers)
    data = response.json()
    all_domains.extend(data["data"])
    url = data["meta"].get("next")  # None when no more pages

print(f"Fetched {len(all_domains)} of {data['meta']['total_count']} domains")

4. Common Operations

curl — Domain Detail (scan results + WHOIS + change history)
curl -H "Authorization: Bearer $DNSAI_API_KEY" \
     https://app.dnsai.com/api/v1/domains/123/
curl — Add Domains (up to 500 per request)
curl -X POST \
     -H "Authorization: Bearer $DNSAI_API_KEY" \
     -H "Content-Type: application/json" \
     -d '{"domains": ["example.com", "example.org"]}' \
     https://app.dnsai.com/api/v1/domains/
curl — Dashboard Summary (portfolio analytics)
curl -H "Authorization: Bearer $DNSAI_API_KEY" \
     https://app.dnsai.com/api/v1/dashboard/summary/
curl — Filter by Email Gateway
curl -H "Authorization: Bearer $DNSAI_API_KEY" \
     "https://app.dnsai.com/api/v1/domains/?email_gateway=Google+Workspace&limit=5000"

AI-Assisted Development

Use AI tools like Claude, ChatGPT, or GitHub Copilot to build your DNSai integration faster. Download the reference files below and provide them to your AI assistant for context-aware code generation.

API Reference (JSON)

Machine-readable API specification with all endpoints, fields, types, and parameters. Ideal for AI code generation tools and IDE extensions.

Download JSON Reference

API Reference (Markdown)

Comprehensive markdown document with complete field tables, code examples, and integration patterns. Paste it into any AI chat to get expert help.

Download Markdown Reference

Sample Client (Python)

Complete, runnable Python client demonstrating all API operations — authentication, pagination, rate limiting, and every endpoint.

Download Python Client
How to use: Download the JSON or Markdown file and upload it to your AI assistant along with a prompt describing what you want to build. For example:
  • "Using this API reference, build me a Python script that exports all domains with missing DMARC policies to a CSV file"
  • "Using this reference, create a Node.js integration that syncs DNSai domain data into our PostgreSQL database every hour"
  • "Help me build a dashboard widget that shows email gateway distribution from the DNSai API"

Endpoints Reference

All endpoints are relative to https://app.dnsai.com/api/v1/

API Root

MethodEndpointDescription
GET /api/v1/ API root with links to all available resources

Domains

MethodEndpointDescription
GET /api/v1/domains/ List domains with scan summary. Supports ?search=, ?email_gateway=, ?dmarc_status=, ?folder_id= filters. Paginated with ?limit= and ?offset= (default 250, max 5000).
POST /api/v1/domains/ Add domains for monitoring. Body: {"domains": ["example.com", ...]}. Max 500 per request. Validates RFC 1035, rejects IPs and URLs.
GET /api/v1/domains/{id}/ Full domain detail with latest scan result, change history, and WHOIS data.
GET /api/v1/domains/{id}/scan-results/ Latest scan result for a domain (DNS records, email gateway, SPF, DKIM, DMARC, geo).
GET /api/v1/domains/{id}/changes/ DNS change history for a domain. Paginated with ?limit= and ?offset=.
GET /api/v1/domains/{id}/whois/ WHOIS registration data for a domain.

Dashboard

MethodEndpointDescription
GET /api/v1/dashboard/summary/ Aggregated stats: email gateway distribution, DMARC/SPF status, scan freshness, domains needing attention.

Exports

MethodEndpointDescription
GET /api/v1/exports/ List export jobs. Paginated with ?limit= and ?offset=.
POST /api/v1/exports/ Trigger a CSV export. Body: {"format": "csv"}. Returns job ID for tracking.

API Keys

MethodEndpointDescription
GET /api/v1/keys/ List your API keys (key prefix only, never the full key).
POST /api/v1/keys/ Create a new API key. Body: {"name": "Key Name"}. Returns the full key once.
DELETE /api/v1/keys/{id}/ Revoke an API key. The key immediately stops working.

Response Envelope

All responses are wrapped in a consistent JSON envelope:

JSON Response
{
  "status": "ok",
  "data": [ ... ],
  "meta": {
    "total_count": 1234,
    "limit": 250,
    "offset": 0,
    "next": "https://app.dnsai.com/api/v1/domains/?limit=250&offset=250",
    "previous": null
  },
  "errors": []
}

For errors:

Error Response
{
  "status": "error",
  "data": null,
  "meta": {},
  "errors": [
    {
      "code": "authentication_required",
      "detail": "Authentication credentials were not provided."
    }
  ]
}

Pagination

List endpoints use limit/offset pagination designed for programmatic access. The default limit is 250, maximum 5,000 results per request.

ParameterDefaultMaxDescription
limit2505,000Number of results to return
offset0Starting position in the result set

The response meta object includes total_count so you know how many results exist. Follow meta.next to iterate, or calculate offsets directly.

Python — Fetch All Domains
# Pull up to 5000 domains per request — no UI pagination limits
url = "https://app.dnsai.com/api/v1/domains/?limit=5000"
all_domains = []

while url:
    response = requests.get(url, headers=headers)
    data = response.json()
    all_domains.extend(data["data"])
    url = data["meta"].get("next")

print(f"Fetched {len(all_domains)} of {data['meta']['total_count']} domains")
Python — Direct Offset Access
# Jump directly to any position in the result set
response = requests.get(
    "https://app.dnsai.com/api/v1/domains/",
    headers=headers,
    params={"limit": 1000, "offset": 2000}  # rows 2001–3000
)
data = response.json()
print(f"Got {len(data['data'])} domains (offset 2000 of {data['meta']['total_count']})")

Rate Limits & Quotas

API access is rate-limited per API key (per minute) and quota-limited per user (per day).

PlanRate LimitDaily Quota
Enterprise100 requests/min10,000 calls/day
Enterprise Max500 requests/min50,000 calls/day
Enterprise Max Premium2,000 requests/min200,000 calls/day

Rate Limit Headers

Every API response includes these headers:

HeaderDescription
X-RateLimit-LimitMaximum requests per minute for your plan
X-RateLimit-RemainingRequests remaining in the current minute window
X-RateLimit-ResetUnix timestamp when the rate limit window resets
X-API-Quota-LimitMaximum API calls per day for your plan
X-API-Quota-UsedAPI calls used today

Handling 429 Responses

When you exceed a rate limit or quota, the API returns 429 Too Many Requests with a Retry-After header indicating how many seconds to wait before retrying.

Python — Retry Logic
import time

def api_request(url, headers, max_retries=3):
    for attempt in range(max_retries):
        response = requests.get(url, headers=headers)
        if response.status_code == 429:
            retry_after = int(response.headers.get("Retry-After", 60))
            print(f"Rate limited. Waiting {retry_after}s...")
            time.sleep(retry_after)
            continue
        return response
    raise Exception("Max retries exceeded")

Error Handling

The API uses standard HTTP status codes and returns errors in the envelope format.

StatusMeaningCommon Causes
400Bad RequestInvalid request body, validation errors
401UnauthorizedMissing or invalid API key
403ForbiddenPlan does not include API access
404Not FoundDomain not in your account, invalid endpoint
429Too Many RequestsRate limit or daily quota exceeded
500Server ErrorInternal server error (contact support)

Error Response Format

Error Response
{
  "status": "error",
  "data": null,
  "meta": {},
  "errors": [
    {
      "code": "rate_limit_exceeded",
      "detail": "Rate limit exceeded (100 requests per minute). Please retry after 45 seconds."
    }
  ]
}

Troubleshooting

  • 401 errors: Verify your API key is correct and has not been revoked. Check that the header format is exactly Authorization: Bearer dnsai_live_...
  • 403 errors: Your plan may not include API access. Upgrade to an Enterprise plan.
  • 404 errors: The domain ID must belong to your account. Use the list endpoint to find valid IDs.
  • 429 errors: Implement exponential backoff and respect the Retry-After header.

Security Best Practices

Key Storage

  • Store API keys in environment variables, never in source code
  • Use a secrets manager (AWS Secrets Manager, HashiCorp Vault, etc.) for production deployments
  • Never commit API keys to version control — add them to .gitignore or .env files
Environment Variable
# .env file (never commit this)
DNSAI_API_KEY=dnsai_live_YOUR_KEY_HERE

# Python usage
import os
API_KEY = os.environ["DNSAI_API_KEY"]

Key Rotation

  • Rotate API keys periodically (every 90 days recommended)
  • Create a new key before revoking the old one to avoid downtime
  • Update all systems using the old key before revoking it
  • You can have up to 3 active keys to facilitate zero-downtime rotation

Network Security

  • Always use HTTPS — the API does not accept HTTP connections
  • Consider restricting API access to specific IP addresses using your firewall
  • Monitor the "Last Used" timestamp in Settings to detect unauthorized usage

Monitoring

  • Check the API Keys tab in Settings for usage stats
  • Monitor rate limit headers to stay within your plan limits
  • Set up alerts if your daily quota usage exceeds 80%
  • Revoke keys immediately if you suspect unauthorized access
Need help? Contact support at [email protected] for API integration assistance or to discuss custom rate limits for your use case.

Complete Field Reference

Every field available from the DNSai API, organized by endpoint. Use this reference when building integrations to know exactly what data is available.

Domain List Fields

Returned by GET /api/v1/domains/ for each domain in the data array.

FieldTypeDescription
idintegerDomain ID in your account (use this for detail/changes/whois lookups)
domainstringThe domain name (e.g., example.com)
email_gatewaystring | nullDetected email gateway vendor (e.g., Google Workspace, Microsoft 365, Mimecast)
dmarc_policy_pstring | nullDMARC policy: reject, quarantine, none, or null if missing
spfstring | nullSPF record content
scanned_atdatetime | nullWhen the domain was last scanned (ISO 8601)
added_atdatetimeWhen you added this domain to your account
folder_idinteger | nullFolder ID if organized into a folder
is_favoritebooleanWhether the domain is favorited
tagsarray of stringsUser-assigned tags

Domain Detail Fields

Returned by GET /api/v1/domains/{id}/ — includes all list fields plus:

FieldTypeDescription
tldstringTop-level domain (e.g., com, org, co.uk)
statusstringDomain status: active, inactive, or removed
first_seendatetimeWhen the domain first appeared in DNSai
last_scanneddatetime | nullLast scan timestamp
scan_countintegerTotal number of scans performed
notesstring | nullYour notes about this domain
custom_labelstring | nullYour custom label for this domain
scan_resultobject | nullFull scan result (see Scan Result Fields below)
change_historyarrayRecent DNS changes (see Change History Fields below)
whoisobject | nullWHOIS data (see WHOIS Fields below)

Scan Result Fields

Returned by GET /api/v1/domains/{id}/scan-results/ and nested as scan_result in the domain detail response. This is the complete DNS intelligence dataset for a domain.

Core DNS Records

FieldTypeDescription
scanned_atdatetimeWhen this scan was performed
mxstring | nullMX (mail exchange) records
spfstring | nullSPF record content (v=spf1 ...)
dmarcstring | nullFull DMARC record (v=DMARC1; p=...)
dmarc_policy_pstring | nullDMARC policy value: reject, quarantine, none
dmarc_ruastring | nullDMARC aggregate report email address
dmarc_rufstring | nullDMARC forensic report email address
txtstring | nullTXT records (verification tokens, etc.)
a_recordsstring | nullA records (IPv4 addresses)
aaaa_recordsstring | nullAAAA records (IPv6 addresses)
nsstring | nullNameserver records
soastring | nullSOA (start of authority) record
bimistring | nullBIMI (Brand Indicators for Message Identification) record
srvstring | nullSRV (service) records
ptrstring | nullPTR (reverse DNS) records

Email Detection

FieldTypeDescription
email_gatewaystring | nullDetected email gateway vendor (e.g., Google Workspace, Microsoft 365, Mimecast, Proofpoint)
tech_in_dnsstring | nullOther technologies detected via DNS records (e.g., Salesforce, HubSpot, Zendesk)

MX Server Geolocation

FieldTypeDescription
mx_server_ipv4string | nullIPv4 address of primary MX server
mx_server_ipv6string | nullIPv6 address of primary MX server
mx_server_countrystring | nullCountry where MX server is hosted
mx_server_regionstring | nullRegion/state of MX server
mx_server_citystring | nullCity of MX server
mx_server_latdecimal | nullLatitude of MX server
mx_server_londecimal | nullLongitude of MX server
mx_server_asnstring | nullASN number of MX server hosting provider
mx_server_asn_namestring | nullASN name / hosting provider of MX server (e.g., Google LLC, Microsoft Corporation)

A Record Server Geolocation

FieldTypeDescription
a_server_countrystring | nullCountry where web server is hosted
a_server_regionstring | nullRegion/state of web server
a_server_citystring | nullCity of web server
a_server_latdecimal | nullLatitude of web server
a_server_londecimal | nullLongitude of web server
a_server_asnstring | nullASN number of web hosting provider
a_server_asn_namestring | nullASN name / web hosting provider (e.g., Cloudflare, Amazon, DigitalOcean)

DKIM

FieldTypeDescription
dkim_hostsstring | nullDKIM host records found in DNS
dkim_selectorsstring | nullDKIM selector names discovered (e.g., google, selector1)
dkim_vendorsstring | nullVendors identified from DKIM selectors
dkimstring | nullDKIM record content (public key data)

SPF Analysis

FieldTypeDescription
spf_main_lookupsinteger | nullNumber of DNS lookups in the top-level SPF record
spf_nested_lookupsinteger | nullNumber of DNS lookups in nested SPF includes
spf_total_lookupsinteger | nullTotal DNS lookups (RFC 7208 limit is 10)
spf_email_sendersstring | nullEmail sending services found in SPF record (e.g., Mailchimp, SendGrid)
spf_limitstring | nullSPF lookup limit status

Change Tracking (Built into Scan Result)

FieldTypeDescription
previous_mxstring | nullPrevious MX records before last change
mx_changed_datedatetime | nullWhen MX records last changed
previous_email_gatewaystring | nullPrevious email gateway before last change
gateway_changed_datedatetime | nullWhen email gateway last changed
previous_dmarc_pstring | nullPrevious DMARC policy before last change
dmarc_p_changed_datedatetime | nullWhen DMARC policy last changed

Change History Fields

Returned by GET /api/v1/domains/{id}/changes/ and nested as change_history in the domain detail response.

FieldTypeDescription
idintegerChange record ID
domain_namestringThe domain name
field_namestringWhich DNS field changed (e.g., mx, email_gateway, dmarc_policy_p, spf)
old_valuestring | nullPrevious value
new_valuestring | nullNew value after the change
detected_atdatetimeWhen DNSai detected the change (ISO 8601)

WHOIS Fields

Returned by GET /api/v1/domains/{id}/whois/ and nested as whois in the domain detail response.

FieldTypeDescription
domain_namestringThe domain name
registrarstring | nullDomain registrar (e.g., GoDaddy, Namecheap, Cloudflare)
registration_datedatetime | nullWhen the domain was first registered
expiry_datedatetime | nullWhen the domain registration expires
updated_datedatetime | nullWhen the WHOIS record was last updated
name_serversstring | nullAuthoritative nameservers for the domain
registrant_namestring | nullRegistrant contact name (may be redacted for privacy)
registrant_orgstring | nullRegistrant organization
registrant_countrystring | nullRegistrant country
registrant_statestring | nullRegistrant state/province
contact_emailstring | nullRegistrant contact email
registrar_abuse_emailstring | nullRegistrar abuse contact email
registrar_abuse_phonestring | nullRegistrar abuse contact phone
privacy_enabledbooleanWhether WHOIS privacy/proxy service is enabled
dnssec_statusstring | nullDNSSEC signing status
domain_statusesarrayEPP domain status codes (e.g., clientTransferProhibited)
whois_statusstring | nullWHOIS lookup result status
whois_serverstring | nullWHOIS server used for the lookup
ip_geolocationobjectIP geolocation data associated with the domain
fetched_atdatetimeWhen the WHOIS data was last retrieved

Dashboard Summary Fields

Returned by GET /api/v1/dashboard/summary/ — aggregated statistics across your domain portfolio.

FieldTypeDescription
total_domainsintegerTotal domains in your account
email_gateway_distributionarrayList of {gateway_name, count, percentage} objects
dmarc_distributionobjectObject with reject, quarantine, none, missing keys, each containing {count, percentage}
spf_statusobject{valid, over_limit, missing} — counts of SPF record status
scan_freshnessobject{scanned_last_24h, scanned_last_7d, percentage_24h, percentage_7d}
recent_changesarrayLast 20 DNS changes across your portfolio (last 7 days)
needs_attention_countintegerDomains with DMARC or SPF issues

Export Job Fields

Returned by GET /api/v1/exports/ and POST /api/v1/exports/.

FieldTypeDescription
idintegerExport job ID
export_typestringExport format: csv, pdf, zip, or diff
statusstringJob status: queued, processing, completed, or failed
task_idstringUnique task identifier for tracking
file_urlstring | nullDownload URL (available when status is completed)
row_countintegerNumber of rows in the export
file_sizeintegerFile size in bytes
parametersobjectExport parameters (columns, filters, folder_id)
created_atdatetimeWhen the export was requested
completed_atdatetime | nullWhen the export finished

API Key Fields

Returned by GET /api/v1/keys/ and POST /api/v1/keys/.

FieldTypeDescription
idintegerAPI key ID
key_prefixstringFirst 12 characters of the key (for identification)
namestringYour name for this key (e.g., “Production Server”)
created_atdatetimeWhen the key was created
last_used_atdatetime | nullWhen the key was last used for an API call
is_activebooleanWhether the key is active
expires_atdatetime | nullOptional expiration date