Configure Webhooks for DNS Notifications
Webhooks allow DNSRadar to send HTTP requests to your endpoints when DNS changes are detected. This enables you to integrate DNS monitoring into your existing systems, trigger automated responses, or notify your team through custom channels.
Creating a Webhook
Send a POST request to /webhooks with your endpoint configuration:
curl -X POST https://api.dnsradar.dev/webhooks \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"secret": "your-webhook-secret-key",
"headers": {
"X-Custom-Header": "Value"
}
}'const response = await fetch('https://api.dnsradar.dev/webhooks', {
method: 'POST',
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"secret": "your-webhook-secret-key",
"headers": {
"X-Custom-Header": "Value"
}
})
});
const data = await response.json();import requests
response = requests.post(
'https://api.dnsradar.dev/webhooks',
headers={
'X-API-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"secret": "your-webhook-secret-key",
"headers": {
"X-Custom-Header": "Value"
}
}
)require 'net/http'
require 'json'
uri = URI('https://api.dnsradar.dev/webhooks')
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 = {
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"secret": "your-webhook-secret-key",
"headers": {
"X-Custom-Header": "Value"
}
}.to_json
response = http.request(request)package main
import (
"bytes"
"encoding/json"
"net/http"
)
data := {
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"secret": "your-webhook-secret-key",
"headers": {
"X-Custom-Header": "Value"
}
}
jsonData, _ := json.Marshal(data)
req, _ := http.NewRequest("POST", "https://api.dnsradar.dev/webhooks", 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/webhooks');
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({
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"secret": "your-webhook-secret-key",
"headers": {
"X-Custom-Header": "Value"
}
});
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 = """{
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"secret": "your-webhook-secret-key",
"headers": {
"X-Custom-Header": "Value"
}
}""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.dnsradar.dev/webhooks"))
.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
{
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"secret": "your-webhook-secret-key",
"headers": {
"X-Custom-Header": "Value"
}
};
var json = JsonSerializer.Serialize(data);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync(
"https://api.dnsradar.dev/webhooks",
content
);Required Fields
url: The endpoint URL to receive webhook notificationsmethod: HTTP method (POST, PUT, PATCH, DELETE)
Optional Fields
secret: Secret key for HMAC SHA256 signature verification (highly recommended)headers: Custom HTTP headers as key-value pairsgroups: Array of group slugs to associate the webhook with
Webhook Security
DNSRadar provides built-in request signing to verify webhook authenticity. When you provide a secret parameter, DNSRadar signs each webhook request with HMAC SHA256.
curl -X POST https://api.dnsradar.dev/webhooks \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"secret": "your-webhook-secret-key",
"headers": {
"Authorization": "Bearer your-api-token"
}
}'const response = await fetch('https://api.dnsradar.dev/webhooks', {
method: 'POST',
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"secret": "your-webhook-secret-key",
"headers": {
"Authorization": "Bearer your-api-token"
}
})
});
const data = await response.json();import requests
response = requests.post(
'https://api.dnsradar.dev/webhooks',
headers={
'X-API-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"secret": "your-webhook-secret-key",
"headers": {
"Authorization": "Bearer your-api-token"
}
}
)require 'net/http'
require 'json'
uri = URI('https://api.dnsradar.dev/webhooks')
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 = {
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"secret": "your-webhook-secret-key",
"headers": {
"Authorization": "Bearer your-api-token"
}
}.to_json
response = http.request(request)package main
import (
"bytes"
"encoding/json"
"net/http"
)
data := {
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"secret": "your-webhook-secret-key",
"headers": {
"Authorization": "Bearer your-api-token"
}
}
jsonData, _ := json.Marshal(data)
req, _ := http.NewRequest("POST", "https://api.dnsradar.dev/webhooks", 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/webhooks');
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({
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"secret": "your-webhook-secret-key",
"headers": {
"Authorization": "Bearer your-api-token"
}
});
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 = """{
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"secret": "your-webhook-secret-key",
"headers": {
"Authorization": "Bearer your-api-token"
}
}""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.dnsradar.dev/webhooks"))
.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
{
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"secret": "your-webhook-secret-key",
"headers": {
"Authorization": "Bearer your-api-token"
}
};
var json = JsonSerializer.Serialize(data);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync(
"https://api.dnsradar.dev/webhooks",
content
);How Request Signing Works
When a webhook is triggered, DNSRadar:
- Creates an HMAC SHA256 signature of the request body using your secret
- Sends the signature in the
X-DNSRadar-Signatureheader - Includes the event timestamp in the
X-Webhook-Timestampheader (UTC)
Your endpoint should verify the signature to ensure the request came from DNSRadar and hasn't been tampered with.
Security Best Practice: Always provide a secret parameter and validate the signature on your endpoint. This prevents unauthorized requests and replay attacks.
Group Association
Webhooks are linked to groups, not individual monitors. This design allows efficient notification management:
Default Group
If you don't specify groups, the webhook is added to your default group:
curl -X POST https://api.dnsradar.dev/webhooks \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST"
}'const response = await fetch('https://api.dnsradar.dev/webhooks', {
method: 'POST',
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST"
})
});
const data = await response.json();import requests
response = requests.post(
'https://api.dnsradar.dev/webhooks',
headers={
'X-API-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST"
}
)require 'net/http'
require 'json'
uri = URI('https://api.dnsradar.dev/webhooks')
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 = {
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST"
}.to_json
response = http.request(request)package main
import (
"bytes"
"encoding/json"
"net/http"
)
data := {
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST"
}
jsonData, _ := json.Marshal(data)
req, _ := http.NewRequest("POST", "https://api.dnsradar.dev/webhooks", 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/webhooks');
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({
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST"
});
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 = """{
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST"
}""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.dnsradar.dev/webhooks"))
.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
{
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST"
};
var json = JsonSerializer.Serialize(data);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync(
"https://api.dnsradar.dev/webhooks",
content
);Specific Groups
Associate the webhook with one or more groups:
curl -X POST https://api.dnsradar.dev/webhooks \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"secret": "your-webhook-secret-key",
"groups": [
"production-servers",
"critical-dns"
]
}'const response = await fetch('https://api.dnsradar.dev/webhooks', {
method: 'POST',
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"secret": "your-webhook-secret-key",
"groups": [
"production-servers",
"critical-dns"
]
})
});
const data = await response.json();import requests
response = requests.post(
'https://api.dnsradar.dev/webhooks',
headers={
'X-API-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"secret": "your-webhook-secret-key",
"groups": [
"production-servers",
"critical-dns"
]
}
)require 'net/http'
require 'json'
uri = URI('https://api.dnsradar.dev/webhooks')
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 = {
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"secret": "your-webhook-secret-key",
"groups": [
"production-servers",
"critical-dns"
]
}.to_json
response = http.request(request)package main
import (
"bytes"
"encoding/json"
"net/http"
)
data := {
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"secret": "your-webhook-secret-key",
"groups": [
"production-servers",
"critical-dns"
]
}
jsonData, _ := json.Marshal(data)
req, _ := http.NewRequest("POST", "https://api.dnsradar.dev/webhooks", 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/webhooks');
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({
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"secret": "your-webhook-secret-key",
"groups": [
"production-servers",
"critical-dns"
]
});
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 = """{
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"secret": "your-webhook-secret-key",
"groups": [
"production-servers",
"critical-dns"
]
}""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.dnsradar.dev/webhooks"))
.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
{
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"secret": "your-webhook-secret-key",
"groups": [
"production-servers",
"critical-dns"
]
};
var json = JsonSerializer.Serialize(data);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync(
"https://api.dnsradar.dev/webhooks",
content
);Auto-Create Groups
If specified groups don't exist, they're created automatically:
curl -X POST https://api.dnsradar.dev/webhooks \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"groups": [
"customer-new-client",
"monitoring-tier-premium"
]
}'const response = await fetch('https://api.dnsradar.dev/webhooks', {
method: 'POST',
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"groups": [
"customer-new-client",
"monitoring-tier-premium"
]
})
});
const data = await response.json();import requests
response = requests.post(
'https://api.dnsradar.dev/webhooks',
headers={
'X-API-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"groups": [
"customer-new-client",
"monitoring-tier-premium"
]
}
)require 'net/http'
require 'json'
uri = URI('https://api.dnsradar.dev/webhooks')
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 = {
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"groups": [
"customer-new-client",
"monitoring-tier-premium"
]
}.to_json
response = http.request(request)package main
import (
"bytes"
"encoding/json"
"net/http"
)
data := {
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"groups": [
"customer-new-client",
"monitoring-tier-premium"
]
}
jsonData, _ := json.Marshal(data)
req, _ := http.NewRequest("POST", "https://api.dnsradar.dev/webhooks", 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/webhooks');
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({
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"groups": [
"customer-new-client",
"monitoring-tier-premium"
]
});
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 = """{
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"groups": [
"customer-new-client",
"monitoring-tier-premium"
]
}""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.dnsradar.dev/webhooks"))
.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
{
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"groups": [
"customer-new-client",
"monitoring-tier-premium"
]
};
var json = JsonSerializer.Serialize(data);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync(
"https://api.dnsradar.dev/webhooks",
content
);This creates both groups and attaches the webhook to them.
API Response
The API returns the created webhook object:
{
"uuid": "wh_abc123...",
"created": "2026-01-08T10:30:00Z",
"url": "https://api.service.com/webhooks/dnsradar",
"method": "POST",
"headers": {
"Authorization": "Bearer token123",
"X-Custom-Header": "value"
},
"is_active": true,
"last_error": null,
"last_executed": null
}
Response Fields
uuid: Unique webhook identifier (prefixed withwh_)created: ISO 8601 timestamp of creationis_active: Whether webhook is enabledlast_error: Most recent error message (if any)last_executed: ISO 8601 timestamp of last execution
Webhook Payload
When a DNS change is detected, DNSRadar sends a POST request with event details:
{
"uuid": "req_abc123...",
"webhook_uuid": "wh_abc123...",
"created": "2026-01-08T10:35:22Z",
"event": {
"event_uuid": "evt_xyz789",
"monitor_uuid": "mon_abc123",
"domain": "piedpiper.com",
"subdomain": "www",
"record_type": "A",
"expected_value": ["1.2.3.4"],
"previous_value": ["1.2.3.4"],
"current_value": ["5.6.7.8"],
"old_state": "VALID",
"new_state": "MISMATCH",
"occurred": "2026-01-08T10:35:22Z",
"incidence_count": 1
}
}
Payload Fields
The Webhook event payload contains information about the current request, and an object event containing the actual event.
event_uuid: Unique identifier for this eventmonitor_uuid: UUID of the monitor that detected the changedomain/subdomain: DNS record locationrecord_type: Type of DNS record (A, AAAA, CNAME, MX, TXT, NS, PTR)expected_value: What the monitor expects to seeprevious_value: DNS value before the changecurrent_value: New DNS value detectedold_state: Previous monitor statenew_state: Current monitor stateoccurred: ISO 8601 timestamp of the eventincidence_count: Total number of incidents for this monitor
Multiple Webhooks Per Group
Groups can have multiple webhooks, enabling:
- Notifications to multiple channels (Slack + email)
- Different alert severities to different endpoints
- Redundant notification systems
- Multi-team notifications
curl -X POST https://api.dnsradar.dev/webhooks \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://hooks.slack.com/services/TEAM/WEBHOOK",
"method": "POST",
"groups": [
"production-dns"
]
}'const response = await fetch('https://api.dnsradar.dev/webhooks', {
method: 'POST',
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({
"url": "https://hooks.slack.com/services/TEAM/WEBHOOK",
"method": "POST",
"groups": [
"production-dns"
]
})
});
const data = await response.json();import requests
response = requests.post(
'https://api.dnsradar.dev/webhooks',
headers={
'X-API-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={
"url": "https://hooks.slack.com/services/TEAM/WEBHOOK",
"method": "POST",
"groups": [
"production-dns"
]
}
)require 'net/http'
require 'json'
uri = URI('https://api.dnsradar.dev/webhooks')
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 = {
"url": "https://hooks.slack.com/services/TEAM/WEBHOOK",
"method": "POST",
"groups": [
"production-dns"
]
}.to_json
response = http.request(request)package main
import (
"bytes"
"encoding/json"
"net/http"
)
data := {
"url": "https://hooks.slack.com/services/TEAM/WEBHOOK",
"method": "POST",
"groups": [
"production-dns"
]
}
jsonData, _ := json.Marshal(data)
req, _ := http.NewRequest("POST", "https://api.dnsradar.dev/webhooks", 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/webhooks');
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({
"url": "https://hooks.slack.com/services/TEAM/WEBHOOK",
"method": "POST",
"groups": [
"production-dns"
]
});
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 = """{
"url": "https://hooks.slack.com/services/TEAM/WEBHOOK",
"method": "POST",
"groups": [
"production-dns"
]
}""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.dnsradar.dev/webhooks"))
.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
{
"url": "https://hooks.slack.com/services/TEAM/WEBHOOK",
"method": "POST",
"groups": [
"production-dns"
]
};
var json = JsonSerializer.Serialize(data);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync(
"https://api.dnsradar.dev/webhooks",
content
);Then add another webhook to the same group:
curl -X POST https://api.dnsradar.dev/webhooks \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://api.pagerduty.com/incidents",
"method": "POST",
"headers": {
"Authorization": "Token token=YOUR_KEY"
},
"groups": [
"production-dns"
]
}'const response = await fetch('https://api.dnsradar.dev/webhooks', {
method: 'POST',
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({
"url": "https://api.pagerduty.com/incidents",
"method": "POST",
"headers": {
"Authorization": "Token token=YOUR_KEY"
},
"groups": [
"production-dns"
]
})
});
const data = await response.json();import requests
response = requests.post(
'https://api.dnsradar.dev/webhooks',
headers={
'X-API-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={
"url": "https://api.pagerduty.com/incidents",
"method": "POST",
"headers": {
"Authorization": "Token token=YOUR_KEY"
},
"groups": [
"production-dns"
]
}
)require 'net/http'
require 'json'
uri = URI('https://api.dnsradar.dev/webhooks')
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 = {
"url": "https://api.pagerduty.com/incidents",
"method": "POST",
"headers": {
"Authorization": "Token token=YOUR_KEY"
},
"groups": [
"production-dns"
]
}.to_json
response = http.request(request)package main
import (
"bytes"
"encoding/json"
"net/http"
)
data := {
"url": "https://api.pagerduty.com/incidents",
"method": "POST",
"headers": {
"Authorization": "Token token=YOUR_KEY"
},
"groups": [
"production-dns"
]
}
jsonData, _ := json.Marshal(data)
req, _ := http.NewRequest("POST", "https://api.dnsradar.dev/webhooks", 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/webhooks');
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({
"url": "https://api.pagerduty.com/incidents",
"method": "POST",
"headers": {
"Authorization": "Token token=YOUR_KEY"
},
"groups": [
"production-dns"
]
});
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 = """{
"url": "https://api.pagerduty.com/incidents",
"method": "POST",
"headers": {
"Authorization": "Token token=YOUR_KEY"
},
"groups": [
"production-dns"
]
}""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.dnsradar.dev/webhooks"))
.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
{
"url": "https://api.pagerduty.com/incidents",
"method": "POST",
"headers": {
"Authorization": "Token token=YOUR_KEY"
},
"groups": [
"production-dns"
]
};
var json = JsonSerializer.Serialize(data);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync(
"https://api.dnsradar.dev/webhooks",
content
);Now both webhooks receive notifications for monitors in the production-dns group.
Webhook Limits
Per-Group Limit: Each group can have up to 5 webhooks (default). This ensures efficient notification delivery while preventing excessive webhook calls.
If you need more than 5 webhooks for a group, feel free to reach out to us with your use case and we'll increase the limit accordingly.
Best Practices
- Use HTTPS: Always use HTTPS endpoints for security
- Implement Authentication: Validate webhook requests using headers
- Handle Retries: Design endpoints to be idempotent
- Return Quickly: Respond to webhooks quickly (< 5 seconds)
- Test Webhooks: Use the test endpoint before production
- Monitor Webhook Health: Track webhook failures and errors
Security Considerations
Verify Webhook Signature
Validate the HMAC SHA256 signature to ensure requests come from DNSRadar:
// Node.js example with Express
const crypto = require('crypto')
app.post('/webhooks/dnsradar', (req, res) => {
const signature = req.headers['x-dnsradar-signature']
const timestamp = req.headers['x-webhook-timestamp']
const secret = process.env.DNSRADAR_WEBHOOK_SECRET
// Create HMAC signature from request body
const body = JSON.stringify(req.body)
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(body)
.digest('hex')
// Compare signatures
if (signature !== expectedSignature) {
return res.status(401).send('Invalid signature')
}
// Process webhook
const event = req.body
handleDNSEvent(event)
res.status(200).send('OK')
})
# Python example with Flask
import hmac
import hashlib
from flask import Flask, request
@app.route('/webhooks/dnsradar', methods=['POST'])
def webhook():
signature = request.headers.get('X-DNSRadar-Signature')
timestamp = request.headers.get('X-Webhook-Timestamp')
secret = os.environ['DNSRADAR_WEBHOOK_SECRET']
# Create HMAC signature from request body
body = request.get_data()
expected_signature = hmac.new(
secret.encode('utf-8'),
body,
hashlib.sha256
).hexdigest()
# Compare signatures
if not hmac.compare_digest(signature, expected_signature):
return 'Invalid signature', 401
# Process webhook
event = request.get_json()
handle_dns_event(event)
return 'OK', 200
// PHP example
<?php
$signature = $_SERVER['HTTP_X_DNSRADAR_SIGNATURE'];
$timestamp = $_SERVER['HTTP_X_WEBHOOK_TIMESTAMP'];
$secret = getenv('DNSRADAR_WEBHOOK_SECRET');
// Create HMAC signature from request body
$body = file_get_contents('php://input');
$expectedSignature = hash_hmac('sha256', $body, $secret);
// Compare signatures
if (!hash_equals($signature, $expectedSignature)) {
http_response_code(401);
exit('Invalid signature');
}
// Process webhook
$event = json_decode($body, true);
handleDNSEvent($event);
http_response_code(200);
echo 'OK';
Prevent Replay Attacks
Use the X-Webhook-Timestamp header to reject old requests:
const MAX_AGE = 5 * 60 * 1000 // 5 minutes
app.post('/webhooks/dnsradar', (req, res) => {
const signature = req.headers['x-dnsradar-signature']
const timestamp = req.headers['x-webhook-timestamp']
const secret = process.env.DNSRADAR_WEBHOOK_SECRET
// Verify timestamp is recent
const eventTime = new Date(timestamp)
const now = new Date()
if (now - eventTime > MAX_AGE) {
return res.status(400).send('Request too old')
}
// Verify signature
const body = JSON.stringify(req.body)
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(body)
.digest('hex')
if (signature !== expectedSignature) {
return res.status(401).send('Invalid signature')
}
// Process webhook
const event = req.body
handleDNSEvent(event)
res.status(200).send('OK')
})
# Python replay attack prevention
from datetime import datetime, timedelta
@app.route('/webhooks/dnsradar', methods=['POST'])
def webhook():
signature = request.headers.get('X-DNSRadar-Signature')
timestamp = request.headers.get('X-Webhook-Timestamp')
secret = os.environ['DNSRADAR_WEBHOOK_SECRET']
# Verify timestamp is recent (within 5 minutes)
event_time = datetime.fromisoformat(timestamp.replace('Z', '+00:00'))
now = datetime.now(timezone.utc)
if (now - event_time).total_seconds() > 300:
return 'Request too old', 400
# Verify signature
body = request.get_data()
expected_signature = hmac.new(
secret.encode('utf-8'),
body,
hashlib.sha256
).hexdigest()
if not hmac.compare_digest(signature, expected_signature):
return 'Invalid signature', 401
# Process webhook
event = request.get_json()
handle_dns_event(event)
return 'OK', 200
IP Allowlisting
Consider restricting webhook requests to DNSRadar's IP ranges (contact support for current IP list).
Error Handling
Your webhook endpoint should always return a 2xx status code to be considered successful.
All other status code will trigger a retry.