Create a DNS Monitor
Creating a DNS monitor with DNSRadar is straightforward. Monitors allow you to track specific DNS records and receive notifications when changes are detected.
This guide will walk you through creating monitors using the API.
Basic Monitor Creation
To create a monitor, send a POST request to the /monitors endpoint with the DNS record details you want to monitor.
curl -X POST https://api.dnsradar.dev/monitors \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"domain": "piedpiper.com",
"record_type": "A",
"expected_value": [
"1.2.3.4",
"5.6.7.8"
]
}'const response = await fetch('https://api.dnsradar.dev/monitors', {
method: 'POST',
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({
"domain": "piedpiper.com",
"record_type": "A",
"expected_value": [
"1.2.3.4",
"5.6.7.8"
]
})
});
const data = await response.json();import requests
response = requests.post(
'https://api.dnsradar.dev/monitors',
headers={
'X-API-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={
"domain": "piedpiper.com",
"record_type": "A",
"expected_value": [
"1.2.3.4",
"5.6.7.8"
]
}
)require 'net/http'
require 'json'
uri = URI('https://api.dnsradar.dev/monitors')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri)
request['X-API-Key'] = 'YOUR_API_KEY'
request['Content-Type'] = 'application/json'
request.body = {
"domain": "piedpiper.com",
"record_type": "A",
"expected_value": [
"1.2.3.4",
"5.6.7.8"
]
}.to_json
response = http.request(request)package main
import (
"bytes"
"encoding/json"
"net/http"
)
data := {
"domain": "piedpiper.com",
"record_type": "A",
"expected_value": [
"1.2.3.4",
"5.6.7.8"
]
}
jsonData, _ := json.Marshal(data)
req, _ := http.NewRequest("POST", "https://api.dnsradar.dev/monitors", bytes.NewBuffer(jsonData))
req.Header.Set("X-API-Key", "YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
response, _ := client.Do(req)<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.dnsradar.dev/monitors');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
$headers = [
'X-API-Key: YOUR_API_KEY',
'Content-Type: application/json'
];
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$data = json_encode({
"domain": "piedpiper.com",
"record_type": "A",
"expected_value": [
"1.2.3.4",
"5.6.7.8"
]
});
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$response = curl_exec($ch);
curl_close($ch);import java.net.http.*;
import java.net.URI;
HttpClient client = HttpClient.newHttpClient();
String json = """{
"domain": "piedpiper.com",
"record_type": "A",
"expected_value": [
"1.2.3.4",
"5.6.7.8"
]
}""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.dnsradar.dev/monitors"))
.header("X-API-Key", "YOUR_API_KEY")
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString(json))
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());using System.Net.Http;
using System.Text;
using System.Text.Json;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var data = new
{
"domain": "piedpiper.com",
"record_type": "A",
"expected_value": [
"1.2.3.4",
"5.6.7.8"
]
};
var json = JsonSerializer.Serialize(data);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync(
"https://api.dnsradar.dev/monitors",
content
);Request Parameters
domain(required): The domain name to monitorsubdomain(optional): The subdomain to monitor. Omit for apex domain monitoringrecord_type(required): The type of DNS record (A, AAAA, CNAME, MX, TXT, NS, PTR)expected_value(required): The expected DNS value(s). Can be a string or array of stringsfrequency(optional): Check frequency in minutes. Default: 60. Options: 5, 10, 15, 30, 60, 120is_exact_match(optional): Whether to require exact value matching. Default: truegroup(optional): Group slug to organize monitors. Uses default group if not specified
Monitoring with Subdomains
To monitor a specific subdomain, include the subdomain parameter in your request.
curl -X POST https://api.dnsradar.dev/monitors \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"domain": "piedpiper.com",
"subdomain": "www",
"record_type": "CNAME",
"expected_value": "piedpiper.netlify.app",
"frequency": 5
}'const response = await fetch('https://api.dnsradar.dev/monitors', {
method: 'POST',
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({
"domain": "piedpiper.com",
"subdomain": "www",
"record_type": "CNAME",
"expected_value": "piedpiper.netlify.app",
"frequency": 5
})
});
const data = await response.json();import requests
response = requests.post(
'https://api.dnsradar.dev/monitors',
headers={
'X-API-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={
"domain": "piedpiper.com",
"subdomain": "www",
"record_type": "CNAME",
"expected_value": "piedpiper.netlify.app",
"frequency": 5
}
)require 'net/http'
require 'json'
uri = URI('https://api.dnsradar.dev/monitors')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri)
request['X-API-Key'] = 'YOUR_API_KEY'
request['Content-Type'] = 'application/json'
request.body = {
"domain": "piedpiper.com",
"subdomain": "www",
"record_type": "CNAME",
"expected_value": "piedpiper.netlify.app",
"frequency": 5
}.to_json
response = http.request(request)package main
import (
"bytes"
"encoding/json"
"net/http"
)
data := {
"domain": "piedpiper.com",
"subdomain": "www",
"record_type": "CNAME",
"expected_value": "piedpiper.netlify.app",
"frequency": 5
}
jsonData, _ := json.Marshal(data)
req, _ := http.NewRequest("POST", "https://api.dnsradar.dev/monitors", bytes.NewBuffer(jsonData))
req.Header.Set("X-API-Key", "YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
response, _ := client.Do(req)<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.dnsradar.dev/monitors');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
$headers = [
'X-API-Key: YOUR_API_KEY',
'Content-Type: application/json'
];
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$data = json_encode({
"domain": "piedpiper.com",
"subdomain": "www",
"record_type": "CNAME",
"expected_value": "piedpiper.netlify.app",
"frequency": 5
});
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$response = curl_exec($ch);
curl_close($ch);import java.net.http.*;
import java.net.URI;
HttpClient client = HttpClient.newHttpClient();
String json = """{
"domain": "piedpiper.com",
"subdomain": "www",
"record_type": "CNAME",
"expected_value": "piedpiper.netlify.app",
"frequency": 5
}""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.dnsradar.dev/monitors"))
.header("X-API-Key", "YOUR_API_KEY")
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString(json))
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());using System.Net.Http;
using System.Text;
using System.Text.Json;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var data = new
{
"domain": "piedpiper.com",
"subdomain": "www",
"record_type": "CNAME",
"expected_value": "piedpiper.netlify.app",
"frequency": 5
};
var json = JsonSerializer.Serialize(data);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync(
"https://api.dnsradar.dev/monitors",
content
);The subdomain parameter should contain only the subdomain portion. For example, to monitor www.piedpiper.com, use subdomain: "www" and domain: "piedpiper.com".
Understanding Expected Values
The expected_value parameter accepts either a single string or an array of strings, depending on your monitoring needs.
Single Value
For DNS records that should have one specific value:
{
"expected_value": "piedpiper.netlify.app"
}
Multiple Values
For DNS records that may have multiple valid values (like A records with multiple IPs):
{
"expected_value": ["1.2.3.4", "5.6.7.8"]
}
Grouping Monitors
Groups allow you to organize monitors and manage webhook notifications collectively. By default, monitors are added to your default group, but you can choose another group when creating a Monitor, by passing a "slug".
If you pass a slug that doesn't exists at DNSRadar, we'll create the group for you on the fly.
curl -X POST https://api.dnsradar.dev/monitors \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"domain": "piedpiper.com",
"record_type": "A",
"expected_value": [
"1.2.3.4"
],
"group": "production-servers"
}'const response = await fetch('https://api.dnsradar.dev/monitors', {
method: 'POST',
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({
"domain": "piedpiper.com",
"record_type": "A",
"expected_value": [
"1.2.3.4"
],
"group": "production-servers"
})
});
const data = await response.json();import requests
response = requests.post(
'https://api.dnsradar.dev/monitors',
headers={
'X-API-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={
"domain": "piedpiper.com",
"record_type": "A",
"expected_value": [
"1.2.3.4"
],
"group": "production-servers"
}
)require 'net/http'
require 'json'
uri = URI('https://api.dnsradar.dev/monitors')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri)
request['X-API-Key'] = 'YOUR_API_KEY'
request['Content-Type'] = 'application/json'
request.body = {
"domain": "piedpiper.com",
"record_type": "A",
"expected_value": [
"1.2.3.4"
],
"group": "production-servers"
}.to_json
response = http.request(request)package main
import (
"bytes"
"encoding/json"
"net/http"
)
data := {
"domain": "piedpiper.com",
"record_type": "A",
"expected_value": [
"1.2.3.4"
],
"group": "production-servers"
}
jsonData, _ := json.Marshal(data)
req, _ := http.NewRequest("POST", "https://api.dnsradar.dev/monitors", bytes.NewBuffer(jsonData))
req.Header.Set("X-API-Key", "YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
response, _ := client.Do(req)<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.dnsradar.dev/monitors');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
$headers = [
'X-API-Key: YOUR_API_KEY',
'Content-Type: application/json'
];
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$data = json_encode({
"domain": "piedpiper.com",
"record_type": "A",
"expected_value": [
"1.2.3.4"
],
"group": "production-servers"
});
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$response = curl_exec($ch);
curl_close($ch);import java.net.http.*;
import java.net.URI;
HttpClient client = HttpClient.newHttpClient();
String json = """{
"domain": "piedpiper.com",
"record_type": "A",
"expected_value": [
"1.2.3.4"
],
"group": "production-servers"
}""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.dnsradar.dev/monitors"))
.header("X-API-Key", "YOUR_API_KEY")
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString(json))
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());using System.Net.Http;
using System.Text;
using System.Text.Json;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var data = new
{
"domain": "piedpiper.com",
"record_type": "A",
"expected_value": [
"1.2.3.4"
],
"group": "production-servers"
};
var json = JsonSerializer.Serialize(data);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync(
"https://api.dnsradar.dev/monitors",
content
);Webhook Management: Webhooks are linked to groups, not individual monitors. This design allows you to manage notifications for multiple monitors efficiently by updating the group's webhook configuration.
If the specified group doesn't exist, it will be created automatically.
API Response
When a monitor is successfully created, the API returns the monitor object with additional system-generated fields:
{
"uuid": "mon_abc123",
"created": "2026-01-06T12:34:56Z",
"domain": "piedpiper.com",
"subdomain": null,
"record_type": "A",
"expected_value": ["1.2.3.4", "5.6.7.8"],
"current_value": null,
"is_exact_match": true,
"state": "UNSET",
"incidence_count": 0,
"last_checked": null,
"is_active": true,
"frequency": 60
}
Response Fields
- uuid: Unique identifier for the monitor (prefixed with
mon_) - created: ISO 8601 timestamp of monitor creation
- current_value: Current DNS value (null until first check)
- state: Monitor state (
UNSET,VALID,INVALID,TIMEOUT,MISMATCH,NOT_FOUND) - incidence_count: Number of incidents/changes detected
- last_checked: ISO 8601 timestamp of last check
- is_active: Whether the monitor is actively checking
Monitor States
Understanding monitor states helps you interpret monitoring results:
UNSET: Monitor created but not yet checkedVALID: DNS record matches expected valueMISMATCH: DNS record doesn't match expected valueNOT_FOUND: DNS record doesn't existTIMEOUT: DNS query timed outINVALID: DNS query returned invalid data
Flexible Matching with is_exact_match
The is_exact_match parameter controls how strictly DNSRadar validates DNS records. When set to false, additional behavior applies based on the record type:
curl -X POST https://api.dnsradar.dev/monitors \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"domain": "piedpiper.com",
"record_type": "TXT",
"expected_value": "v=spf1 include:_spf.service.com",
"is_exact_match": false
}'const response = await fetch('https://api.dnsradar.dev/monitors', {
method: 'POST',
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({
"domain": "piedpiper.com",
"record_type": "TXT",
"expected_value": "v=spf1 include:_spf.service.com",
"is_exact_match": false
})
});
const data = await response.json();import requests
response = requests.post(
'https://api.dnsradar.dev/monitors',
headers={
'X-API-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={
"domain": "piedpiper.com",
"record_type": "TXT",
"expected_value": "v=spf1 include:_spf.service.com",
"is_exact_match": false
}
)require 'net/http'
require 'json'
uri = URI('https://api.dnsradar.dev/monitors')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri)
request['X-API-Key'] = 'YOUR_API_KEY'
request['Content-Type'] = 'application/json'
request.body = {
"domain": "piedpiper.com",
"record_type": "TXT",
"expected_value": "v=spf1 include:_spf.service.com",
"is_exact_match": false
}.to_json
response = http.request(request)package main
import (
"bytes"
"encoding/json"
"net/http"
)
data := {
"domain": "piedpiper.com",
"record_type": "TXT",
"expected_value": "v=spf1 include:_spf.service.com",
"is_exact_match": false
}
jsonData, _ := json.Marshal(data)
req, _ := http.NewRequest("POST", "https://api.dnsradar.dev/monitors", bytes.NewBuffer(jsonData))
req.Header.Set("X-API-Key", "YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
response, _ := client.Do(req)<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.dnsradar.dev/monitors');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
$headers = [
'X-API-Key: YOUR_API_KEY',
'Content-Type: application/json'
];
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$data = json_encode({
"domain": "piedpiper.com",
"record_type": "TXT",
"expected_value": "v=spf1 include:_spf.service.com",
"is_exact_match": false
});
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$response = curl_exec($ch);
curl_close($ch);import java.net.http.*;
import java.net.URI;
HttpClient client = HttpClient.newHttpClient();
String json = """{
"domain": "piedpiper.com",
"record_type": "TXT",
"expected_value": "v=spf1 include:_spf.service.com",
"is_exact_match": false
}""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.dnsradar.dev/monitors"))
.header("X-API-Key", "YOUR_API_KEY")
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString(json))
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());using System.Net.Http;
using System.Text;
using System.Text.Json;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var data = new
{
"domain": "piedpiper.com",
"record_type": "TXT",
"expected_value": "v=spf1 include:_spf.service.com",
"is_exact_match": false
};
var json = JsonSerializer.Serialize(data);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync(
"https://api.dnsradar.dev/monitors",
content
);For detailed information about flexible matching:
- Flexible SPF Record Matching
- Flexible DMARC Record Matching
- Flexible MX Record Matching
- Flexible A/AAAA Record Matching
Rate Limits
The /monitors endpoint is rate-limited to 250 requests per minute. For bulk operations, consider using the bulk creation endpoint.
Plan Limitations
Free Plan: Limited to 50 monitors and 60-minute check frequency.
Premium Plans: Support up to unlimited monitors and down to a 5-minute check intervals.