Integrate DNSai DNS intelligence into your systems with the REST API
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:
All API endpoints are under https://app.dnsai.com/api/v1/ and return JSON responses in a consistent envelope format.
The API uses Bearer token authentication with API keys. Each API key is a long random string prefixed with dnsai_live_.
API access is available on Enterprise plans. Create an account or log in, then:
You can have up to 3 active API keys at a time.
Include your API key in the Authorization header of every request:
Authorization: Bearer dnsai_live_YOUR_API_KEY_HERE
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.
# Store your key in an environment variable — never hardcode it
export DNSAI_API_KEY="dnsai_live_YOUR_KEY_HERE"
curl -H "Authorization: Bearer $DNSAI_API_KEY" \
https://app.dnsai.com/api/v1/domains/
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"])
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));
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.
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")
curl -H "Authorization: Bearer $DNSAI_API_KEY" \
https://app.dnsai.com/api/v1/domains/123/
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 -H "Authorization: Bearer $DNSAI_API_KEY" \
https://app.dnsai.com/api/v1/dashboard/summary/
curl -H "Authorization: Bearer $DNSAI_API_KEY" \
"https://app.dnsai.com/api/v1/domains/?email_gateway=Google+Workspace&limit=5000"
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.
Machine-readable API specification with all endpoints, fields, types, and parameters. Ideal for AI code generation tools and IDE extensions.
Download JSON ReferenceComprehensive markdown document with complete field tables, code examples, and integration patterns. Paste it into any AI chat to get expert help.
Download Markdown ReferenceComplete, runnable Python client demonstrating all API operations — authentication, pagination, rate limiting, and every endpoint.
Download Python ClientAll endpoints are relative to https://app.dnsai.com/api/v1/
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/ | API root with links to all available resources |
| Method | Endpoint | Description |
|---|---|---|
| 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. |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/dashboard/summary/ | Aggregated stats: email gateway distribution, DMARC/SPF status, scan freshness, domains needing attention. |
| Method | Endpoint | Description |
|---|---|---|
| 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. |
| Method | Endpoint | Description |
|---|---|---|
| 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. |
All responses are wrapped in a consistent JSON envelope:
{
"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:
{
"status": "error",
"data": null,
"meta": {},
"errors": [
{
"code": "authentication_required",
"detail": "Authentication credentials were not provided."
}
]
}
List endpoints use limit/offset pagination designed for programmatic access. The default limit is 250, maximum 5,000 results per request.
| Parameter | Default | Max | Description |
|---|---|---|---|
limit | 250 | 5,000 | Number of results to return |
offset | 0 | — | Starting 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.
# 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")
# 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']})")
API access is rate-limited per API key (per minute) and quota-limited per user (per day).
| Plan | Rate Limit | Daily Quota |
|---|---|---|
| Enterprise | 100 requests/min | 10,000 calls/day |
| Enterprise Max | 500 requests/min | 50,000 calls/day |
| Enterprise Max Premium | 2,000 requests/min | 200,000 calls/day |
Every API response includes these headers:
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests per minute for your plan |
X-RateLimit-Remaining | Requests remaining in the current minute window |
X-RateLimit-Reset | Unix timestamp when the rate limit window resets |
X-API-Quota-Limit | Maximum API calls per day for your plan |
X-API-Quota-Used | API calls used today |
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.
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")
The API uses standard HTTP status codes and returns errors in the envelope format.
| Status | Meaning | Common Causes |
|---|---|---|
400 | Bad Request | Invalid request body, validation errors |
401 | Unauthorized | Missing or invalid API key |
403 | Forbidden | Plan does not include API access |
404 | Not Found | Domain not in your account, invalid endpoint |
429 | Too Many Requests | Rate limit or daily quota exceeded |
500 | Server Error | Internal server error (contact support) |
{
"status": "error",
"data": null,
"meta": {},
"errors": [
{
"code": "rate_limit_exceeded",
"detail": "Rate limit exceeded (100 requests per minute). Please retry after 45 seconds."
}
]
}
Authorization: Bearer dnsai_live_...Retry-After header..gitignore or .env files# .env file (never commit this)
DNSAI_API_KEY=dnsai_live_YOUR_KEY_HERE
# Python usage
import os
API_KEY = os.environ["DNSAI_API_KEY"]
Every field available from the DNSai API, organized by endpoint. Use this reference when building integrations to know exactly what data is available.
Returned by GET /api/v1/domains/ for each domain in the data array.
| Field | Type | Description |
|---|---|---|
id | integer | Domain ID in your account (use this for detail/changes/whois lookups) |
domain | string | The domain name (e.g., example.com) |
email_gateway | string | null | Detected email gateway vendor (e.g., Google Workspace, Microsoft 365, Mimecast) |
dmarc_policy_p | string | null | DMARC policy: reject, quarantine, none, or null if missing |
spf | string | null | SPF record content |
scanned_at | datetime | null | When the domain was last scanned (ISO 8601) |
added_at | datetime | When you added this domain to your account |
folder_id | integer | null | Folder ID if organized into a folder |
is_favorite | boolean | Whether the domain is favorited |
tags | array of strings | User-assigned tags |
Returned by GET /api/v1/domains/{id}/ — includes all list fields plus:
| Field | Type | Description |
|---|---|---|
tld | string | Top-level domain (e.g., com, org, co.uk) |
status | string | Domain status: active, inactive, or removed |
first_seen | datetime | When the domain first appeared in DNSai |
last_scanned | datetime | null | Last scan timestamp |
scan_count | integer | Total number of scans performed |
notes | string | null | Your notes about this domain |
custom_label | string | null | Your custom label for this domain |
scan_result | object | null | Full scan result (see Scan Result Fields below) |
change_history | array | Recent DNS changes (see Change History Fields below) |
whois | object | null | WHOIS data (see WHOIS Fields below) |
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.
| Field | Type | Description |
|---|---|---|
scanned_at | datetime | When this scan was performed |
mx | string | null | MX (mail exchange) records |
spf | string | null | SPF record content (v=spf1 ...) |
dmarc | string | null | Full DMARC record (v=DMARC1; p=...) |
dmarc_policy_p | string | null | DMARC policy value: reject, quarantine, none |
dmarc_rua | string | null | DMARC aggregate report email address |
dmarc_ruf | string | null | DMARC forensic report email address |
txt | string | null | TXT records (verification tokens, etc.) |
a_records | string | null | A records (IPv4 addresses) |
aaaa_records | string | null | AAAA records (IPv6 addresses) |
ns | string | null | Nameserver records |
soa | string | null | SOA (start of authority) record |
bimi | string | null | BIMI (Brand Indicators for Message Identification) record |
srv | string | null | SRV (service) records |
ptr | string | null | PTR (reverse DNS) records |
| Field | Type | Description |
|---|---|---|
email_gateway | string | null | Detected email gateway vendor (e.g., Google Workspace, Microsoft 365, Mimecast, Proofpoint) |
tech_in_dns | string | null | Other technologies detected via DNS records (e.g., Salesforce, HubSpot, Zendesk) |
| Field | Type | Description |
|---|---|---|
mx_server_ipv4 | string | null | IPv4 address of primary MX server |
mx_server_ipv6 | string | null | IPv6 address of primary MX server |
mx_server_country | string | null | Country where MX server is hosted |
mx_server_region | string | null | Region/state of MX server |
mx_server_city | string | null | City of MX server |
mx_server_lat | decimal | null | Latitude of MX server |
mx_server_lon | decimal | null | Longitude of MX server |
mx_server_asn | string | null | ASN number of MX server hosting provider |
mx_server_asn_name | string | null | ASN name / hosting provider of MX server (e.g., Google LLC, Microsoft Corporation) |
| Field | Type | Description |
|---|---|---|
a_server_country | string | null | Country where web server is hosted |
a_server_region | string | null | Region/state of web server |
a_server_city | string | null | City of web server |
a_server_lat | decimal | null | Latitude of web server |
a_server_lon | decimal | null | Longitude of web server |
a_server_asn | string | null | ASN number of web hosting provider |
a_server_asn_name | string | null | ASN name / web hosting provider (e.g., Cloudflare, Amazon, DigitalOcean) |
| Field | Type | Description |
|---|---|---|
dkim_hosts | string | null | DKIM host records found in DNS |
dkim_selectors | string | null | DKIM selector names discovered (e.g., google, selector1) |
dkim_vendors | string | null | Vendors identified from DKIM selectors |
dkim | string | null | DKIM record content (public key data) |
| Field | Type | Description |
|---|---|---|
spf_main_lookups | integer | null | Number of DNS lookups in the top-level SPF record |
spf_nested_lookups | integer | null | Number of DNS lookups in nested SPF includes |
spf_total_lookups | integer | null | Total DNS lookups (RFC 7208 limit is 10) |
spf_email_senders | string | null | Email sending services found in SPF record (e.g., Mailchimp, SendGrid) |
spf_limit | string | null | SPF lookup limit status |
| Field | Type | Description |
|---|---|---|
previous_mx | string | null | Previous MX records before last change |
mx_changed_date | datetime | null | When MX records last changed |
previous_email_gateway | string | null | Previous email gateway before last change |
gateway_changed_date | datetime | null | When email gateway last changed |
previous_dmarc_p | string | null | Previous DMARC policy before last change |
dmarc_p_changed_date | datetime | null | When DMARC policy last changed |
Returned by GET /api/v1/domains/{id}/changes/ and nested as change_history in the domain detail response.
| Field | Type | Description |
|---|---|---|
id | integer | Change record ID |
domain_name | string | The domain name |
field_name | string | Which DNS field changed (e.g., mx, email_gateway, dmarc_policy_p, spf) |
old_value | string | null | Previous value |
new_value | string | null | New value after the change |
detected_at | datetime | When DNSai detected the change (ISO 8601) |
Returned by GET /api/v1/domains/{id}/whois/ and nested as whois in the domain detail response.
| Field | Type | Description |
|---|---|---|
domain_name | string | The domain name |
registrar | string | null | Domain registrar (e.g., GoDaddy, Namecheap, Cloudflare) |
registration_date | datetime | null | When the domain was first registered |
expiry_date | datetime | null | When the domain registration expires |
updated_date | datetime | null | When the WHOIS record was last updated |
name_servers | string | null | Authoritative nameservers for the domain |
registrant_name | string | null | Registrant contact name (may be redacted for privacy) |
registrant_org | string | null | Registrant organization |
registrant_country | string | null | Registrant country |
registrant_state | string | null | Registrant state/province |
contact_email | string | null | Registrant contact email |
registrar_abuse_email | string | null | Registrar abuse contact email |
registrar_abuse_phone | string | null | Registrar abuse contact phone |
privacy_enabled | boolean | Whether WHOIS privacy/proxy service is enabled |
dnssec_status | string | null | DNSSEC signing status |
domain_statuses | array | EPP domain status codes (e.g., clientTransferProhibited) |
whois_status | string | null | WHOIS lookup result status |
whois_server | string | null | WHOIS server used for the lookup |
ip_geolocation | object | IP geolocation data associated with the domain |
fetched_at | datetime | When the WHOIS data was last retrieved |
Returned by GET /api/v1/dashboard/summary/ — aggregated statistics across your domain portfolio.
| Field | Type | Description |
|---|---|---|
total_domains | integer | Total domains in your account |
email_gateway_distribution | array | List of {gateway_name, count, percentage} objects |
dmarc_distribution | object | Object with reject, quarantine, none, missing keys, each containing {count, percentage} |
spf_status | object | {valid, over_limit, missing} — counts of SPF record status |
scan_freshness | object | {scanned_last_24h, scanned_last_7d, percentage_24h, percentage_7d} |
recent_changes | array | Last 20 DNS changes across your portfolio (last 7 days) |
needs_attention_count | integer | Domains with DMARC or SPF issues |
Returned by GET /api/v1/exports/ and POST /api/v1/exports/.
| Field | Type | Description |
|---|---|---|
id | integer | Export job ID |
export_type | string | Export format: csv, pdf, zip, or diff |
status | string | Job status: queued, processing, completed, or failed |
task_id | string | Unique task identifier for tracking |
file_url | string | null | Download URL (available when status is completed) |
row_count | integer | Number of rows in the export |
file_size | integer | File size in bytes |
parameters | object | Export parameters (columns, filters, folder_id) |
created_at | datetime | When the export was requested |
completed_at | datetime | null | When the export finished |
Returned by GET /api/v1/keys/ and POST /api/v1/keys/.
| Field | Type | Description |
|---|---|---|
id | integer | API key ID |
key_prefix | string | First 12 characters of the key (for identification) |
name | string | Your name for this key (e.g., “Production Server”) |
created_at | datetime | When the key was created |
last_used_at | datetime | null | When the key was last used for an API call |
is_active | boolean | Whether the key is active |
expires_at | datetime | null | Optional expiration date |
Step-by-step guides for integrating DNSai with your existing platforms. Each guide includes setup instructions, code examples, and field mapping references.
Enrich Account and Lead records with DNS intelligence using Apex callouts and scheduled jobs. Includes Named Credentials setup, bulk ingestion, and complete field mapping.
Enrich company records using Operations Hub custom coded actions. Includes workflow setup, bulk domain ingestion from HubSpot, and scheduled enrichment.
Feed DNS intelligence into your SIEM for security monitoring and alerting. Includes collector scripts, saved searches, UDM mapping, and data field references.