Status dnsafe.net ↗ Log in
Guides
Docs homeHome & PersonalMSP & BusinessAPI referenceThreatDNS
Popular
Router setupEncrypted DNSTroubleshooting
Search docsLog in
Docs / API reference

API reference

Manage tenants, networks, rules and logs from your own tools. Every request is JSON over HTTPS.

Last updated October 2026Interactive schema: api.dnsafe.net/docs

Base URL#

Base URL
https://api.dnsafe.net/api/v1

Authentication#

Create an API key in the portal under API Keys and send it as a bearer token. Keys start with dnsapi_, for example dnsapi_xxxxxxxxxxxxxxxx. The full key is shown once. Keep it in a secret manager, never in a web page or app that users can download.

cURL
curl https://api.dnsafe.net/api/v1/tenants \
  -H "Authorization: Bearer $DNSAFE_API_KEY"

A key acts as the account that created it: a partner’s key can only reach that partner’s tenants. For safety, keys can’t manage API keys, billing, logins or passwords. Those need a portal sign-in. Revoke a key any time from the API Keys page; it stops working immediately.

Rate limits#

TierRequests / minutePrice
Basic100$29/mo
Pro1,000$79/mo
EnterpriseUnlimited$199/mo

Included: Basic with Business, MSP Growth and trials; Pro with Business Enterprise and MSP Enterprise. Or buy a tier on the API keys page.

Over the limit you’ll get 429 Too Many Requests with a Retry-After header (seconds until the next minute starts).

Errors#

Errors return JSON with a detail message.

StatusMeaning
400Invalid request (e.g. nothing to update)
401Missing, invalid or revoked key, or the account is inactive
402Plan limit reached or feature not in your plan, or the key’s plan has lapsed
403Not your tenant, or an endpoint API keys can’t use
404Not found
409IP already registered
422Validation failed. detail lists the fields.
429Rate limit reached. Wait for Retry-After.
503Service unavailable. Try again shortly.

Tenants#

GET/tenantsAPI key · Portal login

List tenants

Every tenant your key can access, newest first.

Parameters

No parameters.
curl https://api.dnsafe.net/api/v1/tenants \
  -H "Authorization: Bearer $DNSAFE_API_KEY"
Response · 200
{
  "tenants": [
    {
      "id": "3007624d-68b4-475f-91dd-9f5a798e68c9",
      "name": "Harbor Logistics",
      "active": true,
      "created_at": "2026-04-26T03:44:40Z",
      "partner_name": "Acme IT",
      "ip_count": 2,
      "rule_count": 4
    }
  ]
}
POST/tenantsAPI key · Portal login

Create a tenant

Adds a new client under your partner account. New networks count toward your plan’s included networks.

Parameters

nameREQUIREDstringDisplay name for the client.
curl -X POST https://api.dnsafe.net/api/v1/tenants \
  -H "Authorization: Bearer $DNSAFE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Northwind Legal"}'
Response · 200
{
  "id": "3007624d-68b4-475f-91dd-9f5a798e68c9",
  "name": "Northwind Legal",
  "partner_id": "5f9b915d-\u2026",
  "active": true,
  "created_at": "2026-09-26T14:02:11Z"
}
GET/tenants/{tenant_id}API key · Portal login

Get a tenant

One tenant’s details.

Parameters

No parameters.
curl https://api.dnsafe.net/api/v1/tenants/$TENANT \
  -H "Authorization: Bearer $DNSAFE_API_KEY"
Response · 200
{
  "id": "3007624d-68b4-475f-91dd-9f5a798e68c9",
  "name": "Harbor Logistics",
  "active": true,
  "notes": null,
  "created_at": "2026-04-26T03:44:40Z",
  "safesearch_enforcement": false,
  "block_ads": true,
  "https_block_page": false,
  "block_proxyware": true,
  "partner_id": "5f9b915d-\u2026",
  "partner_name": "Acme IT"
}
PATCH/tenants/{tenant_id}API key · Portal login

Update a tenant

Change the name, notes or filtering switches. Send only the fields you want to change. Changes to the switches apply to the resolver right away.

Parameters

namestringNew display name.
notesstringInternal notes.
safesearch_enforcementbooleanForce SafeSearch on Google, Bing and YouTube.
block_adsbooleanBlock ads and trackers. Default true.
https_block_pagebooleanShow the block page on HTTPS sites. Default false.
block_proxywarebooleanBlock bandwidth-sharing apps and proxy SDKs. Default true.
curl -X PATCH https://api.dnsafe.net/api/v1/tenants/$TENANT \
  -H "Authorization: Bearer $DNSAFE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"safesearch_enforcement": true}'
Response · 200
{
  "message": "updated"
}
PATCH/tenants/{tenant_id}/activeAPI key · Portal login

Pause or resume

Pauses filtering for a network, or turns it back on. Each call flips the current state and returns the new one. Turning a network back on counts toward your plan’s networks.

Parameters

No parameters.
curl -X PATCH https://api.dnsafe.net/api/v1/tenants/$TENANT/active \
  -H "Authorization: Bearer $DNSAFE_API_KEY"
Response · 200
{
  "id": "3007624d-68b4-475f-91dd-9f5a798e68c9",
  "active": false
}
GET/tenants/{tenant_id}/summaryAPI key · Portal login

Get a summary

Lookup totals for a network across its stored logs: all lookups, blocked lookups, threats (ThreatGrid blocks) and the time of the last lookup. total_logs is the same as total_queries.

Parameters

No parameters.
curl https://api.dnsafe.net/api/v1/tenants/$TENANT/summary \
  -H "Authorization: Bearer $DNSAFE_API_KEY"
Response · 200
{
  "total_queries": 48211,
  "total_logs": 48211,
  "total_blocked": 1937,
  "total_threats": 42,
  "last_seen": "2026-10-15T18:22:04+00:00"
}

Networks (IPs)#

The resolver identifies a tenant by the public IP its lookups come from. Register each office’s public IPv4 address (or a range up to /16).

GET/tenants/{tenant_id}/ipsAPI key · Portal login

List IPs

Registered networks for a tenant. auto_update is null unless the IP has an auto-update link (IP Updater); then it shows when the link was last used and the result.

Parameters

No parameters.
curl https://api.dnsafe.net/api/v1/tenants/$TENANT/ips \
  -H "Authorization: Bearer $DNSAFE_API_KEY"
Response · 200
{
  "ips": [
    {
      "id": "a41e\u2026",
      "client_ip": "203.0.113.10",
      "note": "Main office",
      "created_at": "2026-09-20T10:00:00Z",
      "auto_update": null
    }
  ]
}
POST/tenants/{tenant_id}/ipsAPI key · Portal login

Register an IP

Starts filtering lookups from this network within a few minutes.

Parameters

client_ipREQUIREDstringPublic IPv4 address or CIDR, e.g. 203.0.113.10 or 203.0.113.0/28.
notestringLabel shown in the portal.
curl -X POST https://api.dnsafe.net/api/v1/tenants/$TENANT/ips \
  -H "Authorization: Bearer $DNSAFE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"client_ip": "203.0.113.10", "note": "Main office"}'
Response · 200
{
  "id": "a41e\u2026",
  "client_ip": "203.0.113.10",
  "note": "Main office",
  "created_at": "2026-09-26T14:02:11Z"
}
DELETE/tenants/{tenant_id}/ips/{ip_id}API key · Portal login

Remove an IP

Stops filtering for that network.

Parameters

No parameters.
curl -X DELETE https://api.dnsafe.net/api/v1/tenants/$TENANT/ips/$IP_ID \
  -H "Authorization: Bearer $DNSAFE_API_KEY"
Response · 200
{
  "message": "deleted"
}

Rules#

GET/tenants/{tenant_id}/rulesAPI key · Portal login

List rules

All allow/block rules on a tenant, A→Z by domain.

Parameters

actionstringFilter: block or allow.
searchstringDomain contains…
curl "https://api.dnsafe.net/api/v1/tenants/$TENANT/rules?action=block" \
  -H "Authorization: Bearer $DNSAFE_API_KEY"
Response · 200
{
  "rules": [
    {
      "id": "b1c4\u2026",
      "domain": "tiktok.com",
      "action": "block",
      "note": null,
      "days": 31,
      "time_start": "08:00:00",
      "time_end": "15:00:00",
      "created_at": "2026-09-26T14:02:11Z"
    }
  ]
}
POST/tenants/{tenant_id}/rulesAPI key · Portal login

Add a rule

Blocks or allows a domain (and its subdomains) for one tenant. Add days and times to make it a scheduled rule. The days and time fields need a plan with policy schedules; otherwise you get 402.

Parameters

domainREQUIREDstringe.g. tiktok.com. Subdomains are included.
actionREQUIRED"block" | "allow"What to do with matching lookups.
daysinteger 1–127Days bitmask: Mon=1, Tue=2, Wed=4, Thu=8, Fri=16, Sat=32, Sun=64. Default 127 (every day).
time_start / time_end"HH:MM"Active window (server time, US Eastern). Overnight windows like 22:00–06:00 work. Omit for all day.
notestringShown in the portal.
curl -X POST https://api.dnsafe.net/api/v1/tenants/$TENANT/rules \
  -H "Authorization: Bearer $DNSAFE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"domain": "tiktok.com", "action": "block", "days": 31, "time_start": "08:00", "time_end": "15:00"}'
Response · 200
{
  "id": "b1c4\u2026",
  "domain": "tiktok.com",
  "action": "block",
  "note": null,
  "days": 31,
  "time_start": "08:00:00",
  "time_end": "15:00:00",
  "created_at": "2026-09-26T14:02:11Z"
}
POST/tenants/{tenant_id}/rules/bulkAPI key · Portal login

Bulk import

Add many rules at once. Each item takes the same fields as “Add a rule”. Duplicates are skipped.

Parameters

rulesREQUIREDarrayList of rule objects.
curl -X POST https://api.dnsafe.net/api/v1/tenants/$TENANT/rules/bulk \
  -H "Authorization: Bearer $DNSAFE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"rules": [{"domain": "example-casino.com", "action": "block"}, {"domain": "partner-portal.com", "action": "allow"}]}'
Response · 200
{
  "imported": 2
}
DELETE/tenants/{tenant_id}/rules/{rule_id}API key · Portal login

Delete a rule

Removes one rule. To delete several, use Delete rules in bulk.

Parameters

No parameters.
curl -X DELETE https://api.dnsafe.net/api/v1/tenants/$TENANT/rules/$RULE \
  -H "Authorization: Bearer $DNSAFE_API_KEY"
Response · 200
{
  "message": "deleted"
}
DELETE/tenants/{tenant_id}/rules/bulkAPI key · Portal login

Delete rules in bulk

Removes several rules in one call. IDs that don’t belong to this tenant are ignored. An ID that isn’t a valid UUID returns 400.

Parameters

rule_idsREQUIREDarray of stringsIDs of the rules to delete.
curl -X DELETE https://api.dnsafe.net/api/v1/tenants/$TENANT/rules/bulk \
  -H "Authorization: Bearer $DNSAFE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"rule_ids": ["b1c4…", "c7d2…"]}'
Response · 200
{
  "message": "deleted"
}
GET/tenants/{tenant_id}/policy-testAPI key · Portal login

Test a domain

What would happen to a domain on this network right now, and why. It checks SafeSearch, the network’s rules (including schedules), then the threat, ad, bandwidth-sharing and category lists. Device group rules aren’t checked; groups_note is true when the network has groups. verdict is allowed, blocked or safesearch. Limited to 30 tests a minute.

Parameters

domainREQUIREDstringThe domain to test, e.g. tiktok.com.
curl "https://api.dnsafe.net/api/v1/tenants/$TENANT/policy-test?domain=tiktok.com" \
  -H "Authorization: Bearer $DNSAFE_API_KEY"
Response · 200
{
  "domain": "tiktok.com",
  "network": "Harbor Logistics",
  "verdict": "blocked",
  "reason": "Blocked by your block rule for tiktok.com.",
  "source": "Your rules",
  "rule": {
    "domain": "tiktok.com",
    "action": "block",
    "note": null,
    "scheduled": false
  },
  "threat_listed": false,
  "categories": ["Social media"],
  "sources": [],
  "inactive_categories": ["Social media"],
  "groups_note": false
}

IP groups#

Groups let part of a tenant’s network (say, a guest Wi-Fi range) have its own rules. Group rules are checked before tenant rules.

MethodPathWhat it does
GET/tenants/{tenant_id}/groupsList groups
POST/tenants/{tenant_id}/groupsCreate — {"name", "description"}
DELETE/tenants/{tenant_id}/groups/{group_id}Delete a group
GET…/groups/{group_id}/membersList member ranges
POST…/groups/{group_id}/membersAdd a range — {"cidr", "note"}
DELETE…/groups/{group_id}/members/{member_id}Remove a range
GET…/groups/{group_id}/rulesList group rules
POST…/groups/{group_id}/rulesAdd a group rule — same fields as tenant rules
DELETE…/groups/{group_id}/rules/{rule_id}Delete a group rule

Logs#

GET/tenants/{tenant_id}/logsAPI key · Portal login

Query logs

Recent DNS lookups for a tenant, newest first, with a total count for paging.

Parameters

limitinteger1–1000, default 100.
offsetintegerFor paging.
actionstringblocked (any block), allowed (an allow rule matched), passed (resolved normally, including SafeSearch rewrites), or one exact value: block_threat (threat feed), block (other ThreatGrid list entries), block_tenant, block_sched, block_group, block_group_sched, block_cat_ads (ads and trackers), block_proxyware, block_pack_* (content filters, e.g. block_pack_gambling), block_doh, allow_tenant, allow_sched, allow_group, allow_group_sched, allow, safesearch_google, safesearch_bing, safesearch_youtube.
searchstringDomain contains…
curl "https://api.dnsafe.net/api/v1/tenants/$TENANT/logs?action=blocked&limit=50" \
  -H "Authorization: Bearer $DNSAFE_API_KEY"
Response · 200
{
  "logs": [
    {
      "id": 91822,
      "client_ip": "203.0.113.10",
      "domain": "c2-beacon.xyz",
      "action": "block_threat",
      "logged_at": "2026-09-26T14:02:11Z"
    }
  ],
  "total": 284
}
GET/tenants/{tenant_id}/export/csvAPI key · Portal login

Export CSV

Downloads the latest 10,000 lookups as a CSV file (client IP, domain, action, time). Limited to 30 exports an hour, shared with the PDF report.

Parameters

No parameters.
curl https://api.dnsafe.net/api/v1/tenants/$TENANT/export/csv \
  -H "Authorization: Bearer $DNSAFE_API_KEY"
Response · 200
client_ip,domain,action,logged_at
203.0.113.10,c2-beacon.xyz,block_threat,2026-09-26 14:02:11
GET/tenants/{tenant_id}/export/pdfAPI key · Portal login

Export PDF report

Downloads a PDF report for the network: status, rules and a summary of the latest 200 lookups. Counts toward the 30 exports an hour.

Parameters

No parameters.
curl -o report.pdf https://api.dnsafe.net/api/v1/tenants/$TENANT/export/pdf \
  -H "Authorization: Bearer $DNSAFE_API_KEY"
Response · 200
A PDF file (Content-Type: application/pdf)

Public data#

No API key needed. These are the same numbers shown on dnsafe.net.

GET/public/network-statsNo key

Network totals

Totals across every DNSAFE network for the last 24 hours, how many domains are on the threat list, and DNS uptime over the last 30 days (all three regions). Totals only: never domains, networks or customers. Refreshed every 10 minutes; 60 requests a minute per IP. A total is null if it couldn’t be read.

Parameters

No parameters.
cURL
curl https://api.dnsafe.net/api/v1/public/network-stats
Response · 200
{
  "window_hours": 24,
  "threats_blocked": 48210,
  "lookups": 3104522,
  "threat_list_domains": 612034,
  "dns_uptime_30d": 99.97,
  "updated": "2026-10-16T23:40:00+00:00"
}
GET/public/status-summaryNo key

Live status

One line of live service status, the same as status.dnsafe.net. level is up, deg (degraded, an incident or maintenance), down, or unk when status can’t be confirmed right now. title is only there when there’s more detail, like which services are affected. Refreshed every 60 seconds; 60 requests a minute per IP.

Parameters

No parameters.
cURL
curl https://api.dnsafe.net/api/v1/public/status-summary
Response · 200
{
  "level": "up",
  "text": "All systems operational"
}

ThreatDNS API (free beta)#

Checking domains and IPs against threat sources is a separate API on threatdns.com, with its own keys. Make one in API Keys → ThreatDNS API in the portal (or Settings → ThreatDNS API at my.dnsafe.net). ThreatDNS keys start with tdk_live_ and only run checks; they can’t reach networks or settings, and DNSAFE dnsapi_ keys don’t work there.

cURL
curl "https://threatdns.com/v1/check?q=login-micros0ft.top" \
  -H "Authorization: Bearer $THREATDNS_KEY"

500 checks a month (1,000 with a business or MSP plan, or Home Pro), bulk checks of up to 100, and repeating a check you made in the last day is free. Full reference: threatdns.com/api. How to read a report, email checks and limits: the ThreatDNS guide.

Was this page helpful?