Naar de inhoud
DNSWatcher door PC Patrol

Voor ontwikkelaars

API-documentatie

Koppel DNSWatcher aan je eigen systemen. Voeg domeinen toe, start scans en haal DMARC-rapporten en alerts op met de REST API, of laat ons je systemen bellen met webhooks.

Authenticatie

Maak een sleutel aan in de app onder Instellingen → API-sleutels. Een sleutel begint met dnsw_ en is alleen direct na het aanmaken zichtbaar. Stuur hem mee als Bearer-token. Alle data is beperkt tot het account van de sleutel.

Basis-URL: https://dnswatcher.nl/api/v1

curl https://dnswatcher.nl/api/v1/domains \
  -H "Authorization: Bearer dnsw_xxxxxxxxxxxxxxxxxxxx" \
  -H "Accept: application/json"

Limieten en paginering

  • Maximaal 60 requests per minuut per sleutel. Daarboven krijg je 429.
  • Lijsten zijn gepagineerd. Gebruik ?page=2 enzovoort; in links en meta staat waar je bent.
  • Het aantal sleutels hangt af van je pakket: 3 in Pro, onbeperkt in Business en MSP.
  • Datums zijn ISO 8601 met tijdzone.
GET /api/v1/domains

Domeinen opvragen

Alle domeinen van je account met score en status, gesorteerd op naam. 100 per pagina.

QueryparameterBetekenis
pagePaginanummer (standaard 1)

Voorbeeldantwoord

{
    "data": [
        {
            "name": "voorbeeld.nl",
            "score": 86,
            "verified": true,
            "verified_at": "2026-09-14T10:02:11+02:00",
            "scanning": false,
            "last_checked_at": "2026-10-01T08:15:02+02:00",
            "email_auth": {
                "spf": "pass",
                "dmarc": "warn",
                "dkim": "pass",
                "dkim_selector": "selector1"
            },
            "registration": {
                "registrar": "TransIP",
                "expires_at": "2027-03-14T00:00:00+01:00"
            },
            "tls": {
                "issuer": "Let's Encrypt",
                "expires_at": "2026-12-02T10:11:00+01:00"
            },
            "mails_30d": 4812,
            "url": "https://dnswatcher.nl/domeinen/42"
        }
    ],
    "links": {
        "first": "https://dnswatcher.nl/api/v1/domains?page=1",
        "last": "https://dnswatcher.nl/api/v1/domains?page=1",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 1,
        "path": "https://dnswatcher.nl/api/v1/domains",
        "per_page": 100,
        "to": 1,
        "total": 1
    }
}
POST /api/v1/domains

Domein toevoegen

Voegt een domein toe en start meteen de eerste scan. Bestaat het domein al in je account, dan krijg je dat terug. Antwoordt met 201.

Request-body

{
    "name": "voorbeeld.nl"
}

Voorbeeldantwoord

{
    "data": {
        "name": "voorbeeld.nl",
        "score": 0,
        "verified": false,
        "verified_at": null,
        "scanning": true,
        "last_checked_at": null,
        "email_auth": {
            "spf": "pass",
            "dmarc": "warn",
            "dkim": "pass",
            "dkim_selector": "selector1"
        },
        "registration": {
            "registrar": "TransIP",
            "expires_at": "2027-03-14T00:00:00+01:00"
        },
        "tls": {
            "issuer": "Let's Encrypt",
            "expires_at": "2026-12-02T10:11:00+01:00"
        },
        "mails_30d": 4812,
        "url": "https://dnswatcher.nl/domeinen/42"
    }
}
GET /api/v1/domains/{name}

Eén domein

Details van één domein, inclusief de gevonden SPF-, DMARC- en DKIM-records.

Voorbeeldantwoord

{
    "data": {
        "name": "voorbeeld.nl",
        "score": 86,
        "verified": true,
        "verified_at": "2026-09-14T10:02:11+02:00",
        "scanning": false,
        "last_checked_at": "2026-10-01T08:15:02+02:00",
        "email_auth": {
            "spf": "pass",
            "dmarc": "warn",
            "dkim": "pass",
            "dkim_selector": "selector1"
        },
        "registration": {
            "registrar": "TransIP",
            "expires_at": "2027-03-14T00:00:00+01:00"
        },
        "tls": {
            "issuer": "Let's Encrypt",
            "expires_at": "2026-12-02T10:11:00+01:00"
        },
        "mails_30d": 4812,
        "url": "https://dnswatcher.nl/domeinen/42",
        "records": [
            {
                "type": "SPF",
                "status": "pass",
                "value": "v=spf1 include:spf.protection.outlook.com -all"
            },
            {
                "type": "DMARC",
                "status": "warn",
                "value": "v=DMARC1; p=none; rua=mailto:rua@dnswatcher.nl"
            }
        ]
    }
}
POST /api/v1/domains/{name}/rescan

Opnieuw scannen

Start een volledige scan. Antwoordt met 202 als de scan is gestart, of 200 als er al een scan loopt.

Voorbeeldantwoord

{
    "message": "Scan gestart.",
    "data": {
        "name": "voorbeeld.nl",
        "score": 86,
        "verified": true,
        "verified_at": "2026-09-14T10:02:11+02:00",
        "scanning": true,
        "last_checked_at": "2026-10-01T08:15:02+02:00",
        "email_auth": {
            "spf": "pass",
            "dmarc": "warn",
            "dkim": "pass",
            "dkim_selector": "selector1"
        },
        "registration": {
            "registrar": "TransIP",
            "expires_at": "2027-03-14T00:00:00+01:00"
        },
        "tls": {
            "issuer": "Let's Encrypt",
            "expires_at": "2026-12-02T10:11:00+01:00"
        },
        "mails_30d": 4812,
        "url": "https://dnswatcher.nl/domeinen/42"
    }
}
DELETE /api/v1/domains/{name}

Domein verwijderen

Verwijdert het domein met alle historie uit je account. Antwoordt met 204 zonder inhoud.

GET /api/v1/dmarc-reports

DMARC-rapporten

Regels uit de DMARC-rapporten van je geverifieerde domeinen, nieuwste eerst. Hoe ver terug hangt af van je pakket. 200 per pagina.

QueryparameterBetekenis
domainAlleen dit domein, bijvoorbeeld voorbeeld.nl
resultpass, partial of fail
pagePaginanummer

Voorbeeldantwoord

{
    "data": [
        {
            "domain": "voorbeeld.nl",
            "date": "2026-09-30",
            "reporter": "google.com",
            "source_ip": "203.0.113.5",
            "messages": 120,
            "aligned": 118,
            "policy": "none",
            "result": "pass"
        }
    ],
    "links": {
        "first": "https://dnswatcher.nl/api/v1/domains?page=1",
        "last": "https://dnswatcher.nl/api/v1/domains?page=1",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 1,
        "path": "https://dnswatcher.nl/api/v1/domains",
        "per_page": 100,
        "to": 1,
        "total": 1
    }
}
GET /api/v1/alerts

Alerts

Ongelezen alerts van je account, nieuwste eerst. 100 per pagina.

QueryparameterBetekenis
severityfail, warn of info
include_readZet op 1 om ook gelezen alerts te tonen
pagePaginanummer

Voorbeeldantwoord

{
    "data": [
        {
            "id": 731,
            "domain": "voorbeeld.nl",
            "severity": "fail",
            "title": "DMARC-record verwijderd",
            "description": "Het DMARC-record voor voorbeeld.nl is niet meer gevonden in DNS.",
            "read": false,
            "triggered_at": "2026-10-01T10:42:00+02:00"
        }
    ],
    "links": {
        "first": "https://dnswatcher.nl/api/v1/domains?page=1",
        "last": "https://dnswatcher.nl/api/v1/domains?page=1",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 1,
        "path": "https://dnswatcher.nl/api/v1/domains",
        "per_page": 100,
        "to": 1,
        "total": 1
    }
}

Foutcodes

Fouten komen altijd als JSON terug met een message-veld; bij 422 staat per veld de fout in errors.

401 Unauthorized Geen, een ongeldige of een ingetrokken API-sleutel.
402 Payment Required Je pakket heeft geen API-toegang (Free), of je domeinlimiet is bereikt bij POST /domains.
404 Not Found Het domein bestaat niet in je account.
422 Unprocessable Content De invoer klopt niet, bijvoorbeeld een ongeldige domeinnaam. Details staan in errors.
429 Too Many Requests Meer dan 60 requests per minuut met dezelfde sleutel.
{
    "message": "Voer een geldig domein in, bijvoorbeeld voorbeeld.nl.",
    "errors": {
        "name": [
            "Voer een geldig domein in, bijvoorbeeld voorbeeld.nl."
        ]
    }
}

Webhooks

Stel in de app onder Instellingen → Notificaties een https-URL in. We sturen dan een POST met JSON bij elke gebeurtenis:

  • alert.created: een nieuwe alert, zoals een verdwenen record, kapotte DNSSEC of een onbekende afzender.
  • dns.changed: een gewijzigd, toegevoegd of verwijderd DNS-record.
  • test: het testbericht vanuit de instellingen.

Mislukte aflevering (een 5xx-antwoord of time-out) proberen we nog drie keer opnieuw: na 10 seconden, na 1 minuut en na 5 minuten. Webhooks zitten in Pro en hoger.

alert.created

{
    "id": "9b1f6c1e-3c2a-4f0e-8d6a-2f6f4b7c9e01",
    "event": "alert.created",
    "sent_at": "2026-10-01T10:42:03+02:00",
    "data": {
        "id": 731,
        "domain": "voorbeeld.nl",
        "severity": "fail",
        "title": "DMARC-record verwijderd",
        "description": "Het DMARC-record voor voorbeeld.nl is niet meer gevonden in DNS.",
        "triggered_at": "2026-10-01T10:42:00+02:00",
        "url": "https://dnswatcher.nl/alerts"
    }
}

dns.changed · data

{
    "domain": "voorbeeld.nl",
    "type": "MX",
    "action": "Record toegevoegd (@)",
    "from": null,
    "to": "0 voorbeeld-nl.mail.protection.outlook.com",
    "severity": "pass",
    "occurred_at": "2026-10-01T09:15:00+02:00",
    "url": "https://dnswatcher.nl/dns-historie?domain=42"
}

Handtekening controleren

Elk bericht heeft de header X-DNSWatcher-Signature met de waarde sha256= gevolgd door een HMAC-SHA256 (hex) van de ruwe request-body, berekend met je webhook-sleutel (whsec_…). Vergelijk in constante tijd en verwerk alleen berichten waarvan de handtekening klopt.

// PHP
$expected = 'sha256='.hash_hmac('sha256', $rawBody, $secret);
if (! hash_equals($expected, $request->header('X-DNSWatcher-Signature'))) {
    abort(401);
}

// Node.js
const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
const valid = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(req.get('X-DNSWatcher-Signature')));

Klaar om te koppelen?

Maak een account, kies Pro of hoger en genereer je eerste API-sleutel.

Liever meteen bewaken? Maak een gratis account