Authentifizierung
Alle API-Anfragen erfordern eine Authentifizierung mit einem API-Schlüssel. Übergeben Sie den Schlüssel im Authorization-Header als Bearer-Token. Der API-Schlüssel muss mit dem Präfix nxd_ beginnen.
Tarifanforderung: Die REST API, die ISPmanager-kompatible API und Webhooks sind ab dem Pro-Tarif verfügbar, ebenso die beiden Funktionen, die diese Referenz mit abdeckt: DNSSEC und sekundäre (Slave-)Zonen. Ein Schlüssel in einem Tarif ohne diese Funktionen erhält eine 403.
Authorization: Bearer nxd_your_api_key_here
Die API-Firewall ist zustandslos – jede Anfrage wird unabhängig authentifiziert. Es gibt keine Sitzungen oder Cookies.
Halten Sie Ihren API-Schlüssel geheim. Teilen Sie ihn nicht in clientseitigem Code, öffentlichen Repositories oder URLs. Wenn ein Schlüssel kompromittiert ist, widerrufen Sie ihn sofort und erstellen Sie einen neuen.
Authentifizierungsfehler
| Zustand | Ursache |
|---|---|
401 |
Fehlender oder ungültiger API-Schlüssel, abgelaufener Schlüssel oder gekündigtes Konto |
403 |
Dem Schlüssel fehlt die vom Endpunkt benötigte Berechtigung, oder der Tarif des Kontos enthält keinen API-Zugriff – die Tarifprüfung antwortet auf jedem Pfad mit 403, nicht mit 401. |
Antwortformat
Alle Antworten sind JSON. Erfolgreiche Antworten haben die folgende Struktur:
Einzelne Ressource
{
"status": "success",
"data": {
"id": "xK9mQ2",
"name": "example.com",
...
}
}
Paginierte Liste
{
"status": "success",
"data": [ ... ],
"meta": {
"total": 150,
"page": 1,
"per_page": 25,
"last_page": 6
}
}
Fehlerantwort
{
"status": "error",
"error": {
"code": "validation_error",
"message": "Validation failed.",
"details": {
"name": ["Domain name is required."]
}
}
}
Fehler, die tiefer in der Plattform ausgelöst werden – ein Kontingentlimit, eine gesperrte Domain, ein Nameserver-Ausfall –, enthalten dasselbe error-Objekt, aber kein Feld status. Verzweigen Sie auf error.code, das stabil ist, und nicht auf das Vorhandensein von status. Die Meldungen sind auf jeder Instanz und in jeder Sprache englisch, das ist vertraglich festgelegt; error.code ist der maschinenlesbare Teil.
Öffentliche IDs
Jede Ressource wird durch eine opake id (zum Beispiel xK9mQ2) identifiziert, die in URL-Pfaden verwendet wird. Numerische Datenbank-IDs werden niemals offengelegt oder akzeptiert.
Paginierung
Listenendpunkte, die paginierte Ergebnisse zurückgeben, akzeptieren die folgenden Abfrageparameter:
| Parametername | Typ | Standard | Beschreibung |
|---|---|---|---|
page |
integer | 1 | Seitennummer (mindestens 1) |
per_page |
integer | 25 | Einträge pro Seite (1–100) |
Anfrage-Limits
Anfragen werden pro Konto gezählt, nicht pro Schlüssel, in einem gleitenden Fenster von einer Minute; das Budget ergibt sich aus Ihrem Tarif – den Wert finden Sie im Tarifvergleich auf der Preisseite. Nicht authentifizierte Anfragen werden pro IP-Adresse gezählt. Jede Antwort enthält den aktuellen Stand Ihres Budgets, sodass Sie nicht raten müssen:
| HTTP-Header | Bedeutung |
|---|---|
X-RateLimit-Limit | Im Fenster erlaubte Anfragen. |
X-RateLimit-Remaining | Im aktuellen Fenster verbleibende Anfragen. |
X-RateLimit-Reset | Unix-Zeitstempel, zu dem das Fenster wechselt. |
Retry-After | Wartezeit in Sekunden, wird bei einer 429 gesendet. |
Bei Massenoperationen – dem Import einer großen Zone, dem Abgleich hunderter Einträge – lesen Sie X-RateLimit-Remaining und pausieren Sie, bevor der Wert null erreicht, statt nach einer 429 erneut zu senden. Das CLI erledigt das für Sie.
Einige Operationen haben zusätzlich zum Anfragebudget ein eigenes, längeres Zeitfenster: eine Zone darf dreimal pro Tag in eine andere Nameserver-Gruppe verschoben werden. Die Antwort nennt das erreichte Limit.
Zonen
Verwalten Sie DNS-Zonen. Erfordert zones.read für Leseoperationen und zones.write für Schreiboperationen.
GET /v1/zones
Alle Zonen des authentifizierten Benutzers auflisten.
Abfrageparameter
search– nach Zonenname filternpage,per_page– Paginierung
Antwortfelder
Felder id, name, type (master/slave), status, ns_group, created_at, updated_at
GET /v1/zones/{id}
Detaillierte Informationen zu einer bestimmten Zone abrufen, einschließlich SOA-Daten, Nameserver und Eintragsanzahl.
Zusätzliche Antwortfelder
records_count, soa (primary_ns, admin_email, serial, refresh, retry, expire, minimum), nameservers (Array), ns_group (id, slug, name)
POST /v1/zones
Eine neue DNS-Zone erstellen. Abgelehnt mit 409, wenn die Domain bereits existiert oder sich mit der Zone eines anderen Kontos überschneidet, und mit 422, wenn das Zonenlimit des Tarifs erreicht ist oder die Domain gesperrt ist.
Anfragekörper (JSON)
{
"name": "example.com",
"type": "master",
"ns_group": "eu"
}
Stattdessen eine sekundäre (Slave-)Zone:
{
"name": "example.com",
"type": "slave",
"master_ip": "203.0.113.10"
}
name(erforderlich) – Domainnametype–"master"(Standard) oder"slave"ns_group– NS-Gruppe, der die Zone zugewiesen wird (optional, verwendet Standard wenn nicht angegeben)master_ip– erforderlich für sekundäre Zonen; muss eine gültige öffentliche IP-Adresse sein
Gibt 201 Created mit dem Zonenobjekt zurück.
PATCH /v1/zones/{id}
Verschiebt die Zone in eine andere Nameserver-Gruppe. Dies ist der einzige PATCH der API. Berechtigung: zones.write.
Anfragekörper (JSON)
{
"ns_group": "eu"
}
Gibt die Zone im Zustand nach der Verschiebung zurück, in derselben Struktur wie GET /v1/zones/{id}. Die Gruppe wird über ihren Slug benannt – die Werte, die GET /v1/ns-groups für Ihr Konto auflistet; alles andere wird mit einer 400 abgelehnt.
Die Zone antwortet während des gesamten Vorgangs: die neuen Nameserver werden vor der Antwort bereitgestellt, und die vorherigen bedienen Anfragen weiter, solange Resolver aktualisieren. Passen Sie danach die Delegierung bei Ihrem Registrar an. Eine Zone darf dreimal pro Tag verschoben werden; danach antwortet der Aufruf mit 429.
DELETE /v1/zones/{id}
Eine Zone und alle zugehörigen Einträge löschen.
Gibt 204 No Content bei Erfolg zurück.
GET /v1/zones/{id}/export
Eine Zone im BIND-Format oder als strukturiertes JSON exportieren.
Abfrageparameter
format–"bind"(Standard) gibt BIND-Zonendateitext zurück;"json"gibt ein strukturiertes Array von Einträgen mit Name, Typ, Inhalt und TTL zurück
Einträge
Verwalten Sie DNS-Einträge innerhalb einer Zone. Alle Eintrags-Endpunkte sind unter einer Zone verschachtelt. Erfordert records.read für Leseoperationen und records.write für Schreiboperationen.
GET /v1/zones/{zoneId}/records
Alle Einträge in einer Zone auflisten.
Abfrageparameter
type– nach Eintragstyp filtern (z. B.A,CNAME,MX)name– nach Eintragsname filtern (Teilzeichenkettensuche)search– in Name und Inhalt suchen
Antwortfelder
id, name, type, content, ttl, disabled, fields (typspezifisch ausgewertete Felder)
GET /v1/zones/{zoneId}/records/{recordId}
Einen einzelnen Eintrag anhand seiner ID abrufen.
POST /v1/zones/{zoneId}/records
Einen neuen DNS-Eintrag erstellen.
Anfragekörper (JSON)
{
"type": "A",
"name": "www",
"ttl": 3600,
"content": "93.184.216.34"
}
type(erforderlich) – Eintragstyp (A, AAAA, CNAME, MX, TXT, SRV, CAA, NS, PTR, ALIAS, DNAME, DS, TLSA)name– Eintragsname relativ zur Zone (Standard:@für den Zonenapex)ttl– Gültigkeitsdauer in Sekunden (Standard: 3600)content– Eintragswert (IP für A/AAAA, Hostname für CNAME/NS/PTR, Text für TXT, Mailserver für MX)
Typspezifische Felder
- MX:
priority(Standard: 10) - SRV-Eintrag:
priority,weight,port - CAA:
flags(Standard: 0),tag(Standard: „issue") - DS-Eintrag:
keytag,algorithm,digest_type - TLSA-Eintrag:
usage,selector,matching_type
Bei MX, SRV, CAA, DS und TLSA enthält content nur den Primärwert – den Mailserver, das SRV-Ziel, die CA-Domain, den reinen Hex-Digest – alles Weitere gehört in die Felder oben. Zusammengesetzte Eintragsdaten (zum Beispiel 0 issue "letsencrypt.org" als CAA-Inhalt) werden mit einer 400 abgelehnt, die das Feld nennt.
Die TTL gehört zum Eintragssatz. Lassen Sie ttl weg, wenn Sie einem bereits vorhandenen Namen einen weiteren Wert hinzufügen – die bestehende TTL bleibt dann erhalten; geben Sie einen Wert an, wird die TTL für jeden Wert unter diesem Namen neu gesetzt. Bei einem völlig neuen Namen gilt der Standard von 3600 Sekunden.
Gibt 201 Created mit dem Eintragsobjekt zurück.
PUT /v1/zones/{zoneId}/records/{recordId}
Einen bestehenden Eintrag aktualisieren. Geben Sie nur die Felder an, die Sie ändern möchten; ausgelassene Felder behalten ihre aktuellen Werte.
{
"content": "93.184.216.35",
"ttl": 7200
}
Gibt 200 OK mit dem aktualisierten Eintragsobjekt zurück. Hinweis: Die Eintrags-ID kann sich nach einer Aktualisierung ändern, da sie aus Name, Typ und Inhalt des Eintrags berechnet wird.
DELETE /v1/zones/{zoneId}/records/{recordId}
Einen Eintrag aus der Zone löschen.
Gibt 204 No Content bei Erfolg zurück.
DNSSEC
Verwalten Sie DNSSEC für Ihre Zonen. Erfordert zones.read zum Anzeigen des Status und zones.write zum Aktivieren oder Deaktivieren.
GET /v1/zones/{id}/dnssec
DNSSEC-Status einer Zone abrufen, einschließlich Schlüssel und DS-Einträge.
Antwortfelder
enabled (boolean), keys (Array von DNSKEY-Einträgen), ds_records (Array von DS-Einträgen, die beim Registrar zu setzen sind)
POST /v1/zones/{id}/dnssec/enable
DNSSEC für eine Zone aktivieren. Generiert Signierschlüssel automatisch.
Gibt den DNSSEC-Status mit generierten Schlüsseln und DS-Einträgen zurück.
POST /v1/zones/{id}/dnssec/disable
DNSSEC für eine Zone deaktivieren. Entfernt alle Signierschlüssel.
Gibt {"enabled": false, "keys": [], "ds_records": []} zurück.
NS-Gruppen
Listet die verfügbaren Nameserver-Gruppen auf. Verwenden Sie die id einer Gruppe als ns_group beim Erstellen einer Zone. Jeder gültige API-Schlüssel kann diesen Endpunkt lesen.
GET /v1/ns-groups
Listet die aktiven Nameserver-Gruppen auf.
Antwortfelder pro Gruppe
id, name, slug
Konto
Kontoinformationen anzeigen und API-Schlüssel verwalten.
GET /v1/account
Aktuelle Kontoinformationen abrufen, einschließlich Abonnementdetails.
Antwortfelder
Felder id (UUID), email, name, role, status, language, timezone, created_at
subscription – Objekt mit plan, billing_cycle, status, current_period_start, current_period_end (oder null, wenn kein Abonnement vorhanden)
GET /v1/account/api-keys
Alle API-Schlüssel des authentifizierten Benutzers auflisten.
Antwortfelder pro Schlüssel
id, name, key_prefix (erste 8 Zeichen), permissions (Array), last_used_at, expires_at, created_at
POST /v1/account/api-keys
Einen neuen API-Schlüssel erstellen.
Anfragekörper (JSON)
{
"name": "CI/CD Pipeline",
"permissions": ["zones.read", "records.read", "records.write"],
"expires_at": "2027-01-01"
}
name(erforderlich) – lesbarer Name (maximal 255 Zeichen)permissions(erforderlich) – Array von Berechtigungen (mindestens eine erforderlich):zones.read,zones.write,records.read,records.write,webhooks.read,webhooks.writeexpires_at– optionales Ablaufdatum (ISO 8601 oderYYYY-MM-DD); muss in der Zukunft liegen
Die Antwort enthält den vollständigen API-Schlüssel im Feld
key. Dies ist das einzige Mal, dass der vollständige Schlüssel zurückgegeben wird. Bewahren Sie ihn sicher auf.
Gibt 201 Created mit den Schlüsseldetails einschließlich des vollständigen key-Werts zurück.
DELETE /v1/account/api-keys/{id}
Einen API-Schlüssel widerrufen (dauerhaft löschen).
Gibt 204 No Content bei Erfolg zurück.
Abrechnung
Abonnement, Tarife und Rechnungen anzeigen. Diese Endpunkte sind schreibgeschützt.
GET /v1/billing/subscription
Aktuelle Abonnementdetails abrufen. Gibt null zurück, wenn kein aktives Abonnement vorhanden ist.
Antwortfelder
Felder id, plan, billing_cycle, status, current_period_start, current_period_end, created_at
GET /v1/billing/plans
Alle verfügbaren Tarife mit Preisen und Funktionen auflisten.
Antwortfelder pro Tarif
id, name, slug, description, price_monthly, price_yearly, currency, max_domains, max_records, features (Array)
GET /v1/billing/invoices
Listet die Rechnungen des authentifizierten Benutzers auf, neueste zuerst.
Abfrageparameter
status– nach Status filtern (draft,issued,sent,void)page,per_page– Paginierung
GET /v1/billing/invoices/{id}
Ruft eine einzelne Rechnung anhand ihrer <code>id</code> ab.
Antwortfelder
Felder id, number, status, amount (brutto), net_amount (netto), tax_amount, tax_rate, currency, issued_at, created_at. Geldbeträge sind einfache Dezimalzeichenfolgen.
Webhooks
Verwalten Sie ausgehende Webhook-Abonnements, um Echtzeit-Benachrichtigungen über Änderungen an Zonen und Einträgen zu erhalten. Erfordert webhooks.read für Lesevorgänge und webhooks.write zum Erstellen, Ändern oder Löschen.
GET /v1/webhooks
Listet alle Webhook-Abonnements des authentifizierten Benutzers auf.
Antwortfelder pro Webhook
id, url, events (Array), description, is_active, failure_count, last_triggered_at, created_at
POST /v1/webhooks
Erstellt ein Webhook-Abonnement.
Anfragekörper (JSON)
{
"url": "https://example.com/webhook",
"events": ["zone.created", "record.created"],
"description": "Production webhook"
}
url(erforderlich) – HTTPS-Endpunkt, der die Ereignis-Payloads empfängtevents(erforderlich) – Array von Ereignistypen für das Abonnementdescription– optionale lesbare Bezeichnung
Die Antwort enthält ein
secretzur Überprüfung der Webhook-Signaturen (HMAC). Dies ist das einzige Mal, dass das Secret zurückgegeben wird. Bewahren Sie es sicher auf.
Gibt 201 Created mit der id und dem secret des Webhooks zurück.
GET /v1/webhooks/{id}
Ruft ein einzelnes Webhook-Abonnement zusammen mit seinen letzten Zustellungen ab.
PUT /v1/webhooks/{id}
Aktualisiert ein Webhook-Abonnement. Geben Sie nur die Felder an, die Sie ändern möchten.
Gibt 200 OK mit dem aktualisierten Webhook-Objekt zurück.
DELETE /v1/webhooks/{id}
Löscht ein Webhook-Abonnement.
Gibt 204 No Content bei Erfolg zurück.
POST /v1/webhooks/{id}/test
Sendet ein Testereignis an den Webhook-Endpunkt, um die Erreichbarkeit zu prüfen.
Stellt eine Testzustellung mit einer "type": "test"-Payload in die Warteschlange.
Zustellung verifizieren
Jede Zustellung wird mit dem Secret signiert, das bei der Erstellung des Webhooks zurückgegeben wurde, und trägt vier Header:
X-NexDNS-Signature: sha256=<hmac>
X-NexDNS-Timestamp: 1785370265
X-NexDNS-Event: record.created
X-NexDNS-Delivery: 42
Berechnen Sie HMAC-SHA256 mit Ihrem Secret über den exakten Rohtext des Anfragekörpers neu und vergleichen Sie das Ergebnis in einem laufzeitkonstanten Vergleich mit dem Hex-Digest nach sha256=. Stimmen beide nicht überein, kam die Anfrage nicht von uns. X-NexDNS-Delivery kennzeichnet den einzelnen Versuch: Wiederholungen desselben Ereignisses teilen dieselbe Ereignis-id, aber nicht dieselbe Zustellnummer.
Zustellungs-Payload
{
"id": "evt_szpj9u04z8u0",
"type": "record.created",
"created_at": "2026-07-30 00:31:05",
"data": {
"zone": { "name": "example.com" },
"record": { "name": "www.example.com.", "type": "A", "content": "203.0.113.10", "ttl": 3600 }
}
}
Verfügbare Ereignistypen
Abonnieren Sie eine beliebige Kombination dieser Ereignistypen:
zone.created, zone.updated, zone.deleted, record.created, record.updated, record.deleted, dnssec.enabled, dnssec.disabled, zone.health.problem, zone.health.resolved
Fehlercodes
Alle Fehler folgen einem einheitlichen Format mit einem Fehler-code-String und einer lesbaren message.
| HTTP-Status | Fehlercode | Beschreibung |
|---|---|---|
400 |
validation_error |
Der Anfragekörper hat die Validierung nicht bestanden. Prüfen Sie details auf feldspezifische Fehler. |
401 |
unauthorized |
Fehlender, ungültiger oder abgelaufener API-Schlüssel. |
403 |
forbidden |
Dem API-Schlüssel fehlt die erforderliche Berechtigung, der Tarif des Kontos enthält keinen API-Zugriff, oder der Tarif enthält die genutzte Funktion nicht (zum Beispiel sekundäre Zonen oder DNSSEC). |
404 |
not_found |
Die angeforderte Ressource existiert nicht oder ist für den authentifizierten Benutzer nicht zugänglich. |
409 |
conflict |
Ressource existiert bereits (z. B. doppelter Zonenname). |
422 |
quota_exceeded |
Das Zonen- oder Eintragslimit Ihres Tarifs ist erreicht. |
422 |
domain_blacklisted |
Die Domain steht auf der Sperrliste und kann nicht hinzugefügt werden. |
429 |
rate_limit_exceeded |
Zu viele Anfragen. Prüfen Sie den Retry-After-Header. |
500 |
server_error |
Ein unerwarteter interner Fehler ist aufgetreten. Bitte versuchen Sie es erneut oder kontaktieren Sie den Support, falls das Problem weiterhin besteht. |
502 |
dns_server_error |
Die Nameserver sind vorübergehend nicht erreichbar. Die Anfrage wurde nicht angewendet; wiederholen Sie sie. |
Codebeispiele
Alle Beispiele verwenden curl. Ersetzen Sie nxd_your_api_key durch Ihren tatsächlichen API-Schlüssel.
Zonen auflisten
curl -s "https://api.nexdns.tech/v1/zones" \
-H "Authorization: Bearer nxd_your_api_key"
Zone erstellen
curl -s -X POST "https://api.nexdns.tech/v1/zones" \
-H "Authorization: Bearer nxd_your_api_key" \
-H "Content-Type: application/json" \
-d '{"name": "example.com"}'
A-Eintrag hinzufügen
curl -s -X POST "https://api.nexdns.tech/v1/zones/{zoneId}/records" \
-H "Authorization: Bearer nxd_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"type": "A",
"name": "www",
"ttl": 3600,
"content": "93.184.216.34"
}'
MX-Eintrag hinzufügen
curl -s -X POST "https://api.nexdns.tech/v1/zones/{zoneId}/records" \
-H "Authorization: Bearer nxd_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"type": "MX",
"name": "@",
"ttl": 3600,
"content": "mail.example.com",
"priority": 10
}'
Eintrag aktualisieren
curl -s -X PUT "https://api.nexdns.tech/v1/zones/{zoneId}/records/{recordId}" \
-H "Authorization: Bearer nxd_your_api_key" \
-H "Content-Type: application/json" \
-d '{"content": "93.184.216.35", "ttl": 7200}'
Eintrag löschen
curl -s -X DELETE "https://api.nexdns.tech/v1/zones/{zoneId}/records/{recordId}" \
-H "Authorization: Bearer nxd_your_api_key"
Zone exportieren (BIND-Format)
curl -s "https://api.nexdns.tech/v1/zones/{zoneId}/export" \
-H "Authorization: Bearer nxd_your_api_key"
DNSSEC aktivieren
curl -s -X POST "https://api.nexdns.tech/v1/zones/{zoneId}/dnssec/enable" \
-H "Authorization: Bearer nxd_your_api_key"
API-Schlüssel erstellen
curl -s -X POST "https://api.nexdns.tech/v1/account/api-keys" \
-H "Authorization: Bearer nxd_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "Read-only key",
"permissions": ["zones.read", "records.read"],
"expires_at": "2027-12-31"
}'
Kontoinformationen abrufen
curl -s "https://api.nexdns.tech/v1/account" \
-H "Authorization: Bearer nxd_your_api_key"