Integrate DNSRadar with N8N
n8n is an open-source workflow automation tool that connects to hundreds of services. By integrating DNSRadar with n8n, you can automate responses to DNS changes with complex workflows.
Architecture Overview
The integration works through webhooks:
- DNSRadar detects a DNS change
- DNSRadar sends webhook to n8n
- n8n workflow processes the event
- n8n triggers downstream actions (notifications, tickets, API calls, etc.)
Setting Up the Integration
Step 1: Create an n8n Webhook
In your n8n workflow:
- Add a Webhook node as the trigger
- Set HTTP Method to
POST - Set Path to something memorable like
dnsradar-events - Set Authentication to
None(DNSRadar uses HMAC signatures instead) - Copy the Production URL (e.g.,
https://your-n8n.app/webhook/dnsradar-events)
Step 2: Create DNSRadar Webhook
Create a webhook in DNSRadar pointing to your n8n workflow:
curl -X POST https://api.dnsradar.dev/webhooks \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-n8n.app/webhook/dnsradar-events",
"method": "POST",
"secret": "your-secure-webhook-secret",
"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://your-n8n.app/webhook/dnsradar-events",
"method": "POST",
"secret": "your-secure-webhook-secret",
"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://your-n8n.app/webhook/dnsradar-events",
"method": "POST",
"secret": "your-secure-webhook-secret",
"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://your-n8n.app/webhook/dnsradar-events",
"method": "POST",
"secret": "your-secure-webhook-secret",
"groups": [
"production-dns"
]
}.to_json
response = http.request(request)package main
import (
"bytes"
"encoding/json"
"net/http"
)
data := {
"url": "https://your-n8n.app/webhook/dnsradar-events",
"method": "POST",
"secret": "your-secure-webhook-secret",
"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://your-n8n.app/webhook/dnsradar-events",
"method": "POST",
"secret": "your-secure-webhook-secret",
"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://your-n8n.app/webhook/dnsradar-events",
"method": "POST",
"secret": "your-secure-webhook-secret",
"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://your-n8n.app/webhook/dnsradar-events",
"method": "POST",
"secret": "your-secure-webhook-secret",
"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
);DNSRadar will use the secret to sign each request with HMAC SHA256, sending the signature in the X-DNSRadar-Signature header along with a X-Webhook-Timestamp header to prevent replay attacks.
Step 3: Test the Integration
Test your webhook to verify n8n receives the payload:
curl -X POST https://api.dnsradar.dev/webhooks/wh_abc123/test \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'const response = await fetch('https://api.dnsradar.dev/webhooks/wh_abc123/test', {
method: 'POST',
headers: {
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({})
});
const data = await response.json();import requests
response = requests.post(
'https://api.dnsradar.dev/webhooks/wh_abc123/test',
headers={
'X-API-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={}
)require 'net/http'
require 'json'
uri = URI('https://api.dnsradar.dev/webhooks/wh_abc123/test')
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 = {}.to_json
response = http.request(request)package main
import (
"bytes"
"encoding/json"
"net/http"
)
data := {}
jsonData, _ := json.Marshal(data)
req, _ := http.NewRequest("POST", "https://api.dnsradar.dev/webhooks/wh_abc123/test", 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/wh_abc123/test');
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({});
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 = """{}""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.dnsradar.dev/webhooks/wh_abc123/test"))
.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
{};
var json = JsonSerializer.Serialize(data);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync(
"https://api.dnsradar.dev/webhooks/wh_abc123/test",
content
);Check n8n to see if the webhook was received and the workflow triggered.
Understanding the Webhook Payload
DNSRadar sends this payload to n8n:
{
"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
}
}
Access these values in n8n using expressions like {{ $json.event.domain }} or {{ $json.event.new_state }}.
Example Workflows
1. Slack Notification
Goal: Send Slack message when DNS changes
Workflow:
- Webhook (Trigger) - Receives DNSRadar event
- IF node - Filter for
MISMATCHstate:{{ $json.event.new_state === "MISMATCH" }} - Slack node - Send message
Slack message template:
DNS Alert: {{ $json.event.domain }}{{ $json.event.subdomain ? '.' + $json.event.subdomain : '' }}
Record Type: {{ $json.event.record_type }}
Expected: {{ $json.event.expected_value.join(', ') }}
Current: {{ $json.event.current_value.join(', ') }}
State: {{ $json.event.new_state }}
Time: {{ $json.event.occurred }}
2. Create PagerDuty Incident
Goal: Escalate critical DNS mismatches
Workflow:
- Webhook (Trigger)
- IF node - Check if critical:
{{ $json.event.new_state === "MISMATCH" && $json.event.domain.includes('api.') }} - PagerDuty node - Create incident
PagerDuty configuration:
- Action: Create Incident
- Title:
DNS Mismatch: {{ $json.event.domain }} - Service: Your on-call service
- Urgency: High
- Body: Include all event details
3. Create Jira Ticket
Goal: Track DNS changes as tickets
Workflow:
- Webhook (Trigger)
- Jira node - Create issue
Jira issue:
Summary: DNS Change - {{ $json.event.domain }}
Description:
Domain: {{ $json.event.domain }}{{ $json.event.subdomain ? '.' + $json.event.subdomain : '' }}
Record Type: {{ $json.event.record_type }}
Previous Value: {{ $json.event.previous_value.join(', ') }}
Current Value: {{ $json.event.current_value.join(', ') }}
State Change: {{ $json.event.old_state }} → {{ $json.event.new_state }}
Occurred: {{ $json.event.occurred }}
Event UUID: {{ $json.event_uuid }}
Monitor UUID: {{ $json.monitor_uuid }}
Issue Type: Task
Project: DNS-OPS
Priority: {{ $json.event.new_state === "MISMATCH" ? "High" : "Medium" }}
4. Email Notification with Details
Goal: Send formatted email to team
Workflow:
- Webhook (Trigger)
- Send Email node
Email template:
Subject: DNS Change Alert - {{ $json.event.domain }}
Body:
A DNS change has been detected:
Domain: {{ $json.event.domain }}{{ $json.event.subdomain ? '.' + $json.event.subdomain : '' }}
Record Type: {{ $json.event.record_type }}
Expected Value: {{ $json.event.expected_value.join(', ') }}
Previous Value: {{ $json.event.previous_value.join(', ') }}
Current Value: {{ $json.event.current_value.join(', ') }}
State: {{ $json.event.old_state }} → {{ $json.event.new_state }}
Incident Count: {{ $json.event.incidence_count }}
Occurred: {{ $json.occurred }}
Event ID: {{ $json.event_uuid }}
Monitor ID: {{ $json.monitor_uuid }}
5. Multi-Channel Alerting
Goal: Notify multiple channels based on severity
Workflow:
- Webhook (Trigger)
- Switch node - Route by state:
MISMATCH→ Send to PagerDuty + SlackNOT_FOUND→ Send to Email + JiraTIMEOUT→ Send to Slack only- Default → Log to database
Advanced Patterns
Conditional Routing
Route events based on properties:
// Switch node expression
{{ $json.event.domain.split('.')[0] }}
// Cases:
// "api" → Critical path (PagerDuty)
// "www" → Standard path (Slack)
// "dev" → Low priority (Email only)
Security Best Practices
Validate Webhook Signatures
Add a Code node after the webhook trigger to verify the HMAC signature:
// JavaScript code in n8n Code node
const crypto = require('crypto');
const signature = $input.item.headers['x-dnsradar-signature'];
const timestamp = $input.item.headers['x-webhook-timestamp'];
const secret = 'your-secure-webhook-secret'; // Store in n8n environment variable
// Verify timestamp (prevent replay attacks)
const eventTime = new Date(timestamp);
const now = new Date();
const maxAge = 5 * 60 * 1000; // 5 minutes
if (now - eventTime > maxAge) {
throw new Error('Webhook request too old');
}
// Verify signature
const body = JSON.stringify($input.item.json);
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(body)
.digest('hex');
if (signature !== expectedSignature) {
throw new Error('Invalid webhook signature');
}
// Return the event data if validation passes
return $input.item.json;
Troubleshooting
Webhook Not Triggering
Check:
- n8n webhook URL is correct in DNSRadar
- Webhook is active in DNSRadar
- n8n workflow is activated
- Webhook secret is configured correctly
- n8n is accessible from the internet via HTTPS
- Signature validation (if implemented) is not rejecting requests
Test in n8n
Use n8n's Listening mode:
- Open workflow
- Click webhook node
- Click "Listen for Test Event"
- Send test from DNSRadar
- Verify payload appears in n8n
Debug Payload
Add a Function node after webhook:
// Log full payload
console.log('DNSRadar event:', $input.all())
// Transform if needed
return $input.all()
Integration Templates
Copy-Paste Ready Workflow
{
"nodes": [
{
"parameters": {
"path": "dnsradar-events",
"responseMode": "responseNode",
"options": {}
},
"name": "DNSRadar Webhook",
"type": "n8n-nodes-base.webhook",
"position": [250, 300]
},
{
"parameters": {
"conditions": {
"string": [
{
"value1": "={{$json.event.new_state}}",
"value2": "MISMATCH"
}
]
}
},
"name": "Filter Mismatches",
"type": "n8n-nodes-base.if",
"position": [450, 300]
},
{
"parameters": {
"message": "DNS Mismatch: {{$json.event.domain}}\nExpected: {{$json.event.expected_value}}\nCurrent: {{$json.event.current_value}}"
},
"name": "Send Slack Alert",
"type": "n8n-nodes-base.slack",
"position": [650, 300]
}
]
}