DNS-API: Zonen und Records
Diese Seite beschreibt die Endpunkte für Zonen, Records und delegierte Subdomains. Grundlagen wie Basis-URL, Authentifizierung und Fehlerformat findest du im API-Überblick. Alle Endpunkte auf dieser Seite erfordern einen Token mit Zugriff auf den Bereich Records; auf ausgewählte Zonen beschränkte Token erreichen nur diese Zonen.
Die Beispiele verwenden die Variable XCLOUD_DNS_TOKEN für deinen API-Token und folgende
Basis-URL:
export XCLOUD_DNS_TOKEN='xcdns_...'
export XCLOUD_DNS_API='https://app.xcloud.eu/api/dns/v1'
Zonen
| Methode | Pfad | Beschreibung |
|---|---|---|
GET |
/zones |
Alle Zonen auflisten, nach Namen sortiert |
GET |
/zones/{id} |
Eine Zone anzeigen |
POST |
/zones |
Eine Zone anlegen |
DELETE |
/zones/{id} |
Eine Zone samt aller Records löschen |
POST |
/zones/{id}/delegation_check |
Die Delegierung erneut prüfen |
POST |
/zones/{id}/dnssec |
DNSSEC einschalten |
DELETE |
/zones/{id}/dnssec |
DNSSEC ausschalten |
GET |
/zones/{id}/export |
Records als BIND-Zonendatei exportieren |
POST |
/zones/{id}/import |
Records aus einer BIND-Zonendatei importieren |
POST |
/zones/{id}/retrieve |
Zonentransfer anstoßen (nur sekundäre Zonen) |
Eine Zone lässt sich nach dem Anlegen nicht mehr ändern; für Zonen gibt es keinen
PATCH-Endpunkt.
Attribute einer Zone
| Attribut | Beschreibung |
|---|---|
id |
ID der Zone |
name |
Zonenname, z. B. example.com |
state |
pending, active, error oder deleting |
state_detail |
Zusätzliche Informationen zum Zustand oder null |
nameservers |
Die für die Zone zuständigen xCloud-Nameserver |
serial |
Aktuelle Seriennummer der Zone oder null |
zone_type |
master (Records werden in xCloud verwaltet) oder slave (sekundär) |
masters |
IP-Adressen der Primary-Nameserver einer sekundären Zone |
dnssec_status |
DNSSEC-Signierungsstatus oder null |
dnssec_ds |
DS-Records der signierten Zone |
dnssec_dnskey |
DNSKEY-Records der signierten Zone |
delegation_status |
ok, misconfigured oder unknown |
delegation_checked_at |
Zeitpunkt der letzten Delegierungsprüfung oder null |
delegation_detail |
Am Parent beobachtete Nameserver oder null |
records_count |
Anzahl der Records in der Zone |
registration_id |
ID der verknüpften, über xCloud registrierten Domain oder null |
content_changed_at |
Zeitpunkt der letzten Änderung an den Records oder null |
created_at |
Zeitpunkt der Erstellung |
updated_at |
Zeitpunkt der letzten Änderung |
Zone anzeigen
GET /zones/{id} liefert eine Zone, GET /zones alle Zonen in derselben Form:
curl "$XCLOUD_DNS_API/zones/$ZONE_ID" \
-H "Authorization: Bearer $XCLOUD_DNS_TOKEN"
{
"data": {
"id": "0b7c4f0e-2a51-4c4e-9a7f-5d3c1e8b9f10",
"name": "example.com",
"state": "active",
"state_detail": null,
"nameservers": ["ns1.example.net", "ns2.example.net"],
"serial": "2026102001",
"zone_type": "master",
"masters": [],
"dnssec_status": null,
"dnssec_ds": [],
"dnssec_dnskey": [],
"delegation_status": "ok",
"delegation_checked_at": "2026-10-20T06:00:12+02:00",
"delegation_detail": "ns1.example.net, ns2.example.net",
"records_count": 12,
"registration_id": "1d2e3f4a-5b6c-4d7e-8f9a-0b1c2d3e4f51",
"created_at": "2026-09-14T10:21:37+02:00",
"updated_at": "2026-10-20T06:00:12+02:00",
"content_changed_at": "2026-10-19T17:42:05+02:00"
}
}
Zone anlegen
POST /zones legt eine Zone an. Die Zone startet im Zustand pending und wird active,
sobald sie auf den Nameservern eingerichtet ist.
| Attribut | Pflicht | Beschreibung |
|---|---|---|
name |
ja | Domainname der Zone, z. B. example.com |
zone_type |
nein | master (Standard) oder slave für eine sekundäre Zone |
masters |
bei slave |
IP-Adressen (IPv4 oder IPv6) deiner Primary-Nameserver |
Jeder Zonenname kann nur einmal existieren. NS- und SOA-Records werden automatisch
gesetzt. Sobald die Zone aktiv ist, trage für die Domain die Nameserver aus dem Attribut
nameservers der Zone ein.
Eine sekundäre Zone anlegen, die ihre Records per Zonentransfer (AXFR) von zwei Primary-Nameservern übernimmt:
curl -X POST "$XCLOUD_DNS_API/zones" \
-H "Authorization: Bearer $XCLOUD_DNS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"zone": {
"name": "example.com",
"zone_type": "slave",
"masters": ["192.0.2.53", "2001:db8::53"]
}
}'
Für eine normale Zone schickst du nur den Namen: {"zone": {"name": "example.com"}}.
Die Records einer sekundären Zone sind schreibgeschützt: Anlegen, Ändern oder Löschen von
Records, DNSSEC und Import werden mit 422 abgelehnt. POST /zones/{id}/retrieve stößt
einen sofortigen Zonentransfer von den Primary-Nameservern an; bei anderen Zonen liefert
es 422.
Delegierungsprüfung
xCloud prüft regelmäßig, ob die Delegierung der Domain bei der Registry auf die
Nameserver der Zone zeigt; das Ergebnis steht in delegation_status. POST
/zones/{id}/delegation_check stellt eine zusätzliche Prüfung in die Warteschlange. Eine
Zone lässt sich höchstens einmal pro Minute erneut prüfen; häufigere Anfragen werden mit
422 abgelehnt.
DNSSEC
POST /zones/{id}/dnssec schaltet die DNSSEC-Signierung der Zone ein, DELETE
/zones/{id}/dnssec schaltet sie aus. Beides läuft im Hintergrund; die Antwort zeigt die
Zone zum Zeitpunkt der Anfrage.
- Bei über xCloud registrierten Domains werden die DS-Records automatisch bei der Registry veröffentlicht (und beim Ausschalten von DNSSEC entfernt).
- Bei extern registrierten Domains entnimmst du die DS-Records dem Attribut
dnssec_dsund hinterlegst sie bei deinem Registrar.
Zonendatei exportieren
GET /zones/{id}/export liefert alle Records der Zone als BIND-Zonendatei mit dem
Content-Type text/plain. SOA- und Apex-NS-Records verwalten die Nameserver selbst; sie
sind nicht enthalten.
Zonendatei importieren
POST /zones/{id}/import legt Records aus einer BIND-Zonendatei an.
| Attribut | Pflicht | Beschreibung |
|---|---|---|
zonefile |
ja | Inhalt der BIND-Zonendatei als String |
dry_run |
nein | true zeigt nur, was importiert würde; Standard false |
Anders als bei anderen Endpunkten sind die Attribute nicht in ein äußeres Objekt
verpackt. Das folgende Beispiel liest eine lokale Zonendatei, verpackt sie mit jq in
die Anfrage und führt zunächst einen Probelauf aus:
jq -n --rawfile zonefile example.com.zone '{zonefile: $zonefile, dry_run: true}' |
curl -X POST "$XCLOUD_DNS_API/zones/$ZONE_ID/import" \
-H "Authorization: Bearer $XCLOUD_DNS_TOKEN" \
-H "Content-Type: application/json" \
-d @-
Die Antwort ist ein Importbericht:
{
"data": {
"dry_run": true,
"creates": [
{ "record_type": "A", "subdomain": "www", "content": "192.0.2.10", "ttl": 3600,
"prio": null }
],
"skipped": [
{ "line": 7, "reason": "an identical record already exists" }
],
"errors": []
}
}
creates: Records, die angelegt werden (bzw. beim Probelauf angelegt würden)skipped: übersprungene Zeilen, z. B. weil ein identischer Record schon existiert oder die Zeile nicht unterstützt wirderrors: Zeilen, die die Validierung nicht bestehen, mit Zeilennummer und Meldung
Wiederhole die Anfrage mit "dry_run": false, um den Import zu übernehmen. Die Records
aus creates werden nur angelegt, wenn errors leer ist; dann alle gemeinsam.
Zone löschen
DELETE /zones/{id} löscht die Zone samt aller Records endgültig.
Records
| Methode | Pfad | Beschreibung |
|---|---|---|
GET |
/zones/{zone_id}/records |
Die Records einer Zone auflisten |
GET |
/records |
Die Records aller Zonen auflisten |
POST |
/zones/{zone_id}/records |
Einen Record anlegen |
PATCH |
/records/{id} |
Einen Record ändern |
DELETE |
/records/{id} |
Einen Record löschen |
PATCH |
/zones/{zone_id}/records/bulk_ttl |
Die TTL mehrerer Records setzen |
POST |
/zones/{zone_id}/records/bulk_destroy |
Mehrere Records löschen |
POST |
/records/{id}/dyndns |
DynDNS für einen Record einschalten |
DELETE |
/records/{id}/dyndns |
DynDNS für einen Record ausschalten |
GET /zones/{zone_id}/records liefert die Records einer Zone, sortiert nach Subdomain
und Typ. GET /records liefert die Records aller Zonen, sortiert nach Zonenname,
Subdomain und Typ; der optionale Query-Parameter zone_id beschränkt die Liste auf eine
Zone. Automatisch gesetzte NS- und SOA-Records sind nicht enthalten.
Attribute eines Records
| Attribut | Beschreibung |
|---|---|
id |
ID des Records |
zone_id |
ID der Zone |
zone_name |
Name der Zone |
record_type |
A, AAAA, CNAME, MX, NS, PTR, SPF, SRV, TXT oder TLSA |
subdomain |
Name relativ zur Zone, z. B. www; leer für die Zone selbst |
content |
Wert des Records |
ttl |
TTL in Sekunden |
prio |
Priorität bei MX und SRV, sonst null |
comment |
Freitext-Notiz oder null |
dyndns_enabled |
Ob DynDNS eingeschaltet ist |
dyndns_url |
DynDNS-Update-URL oder null |
created_at |
Zeitpunkt der Erstellung |
updated_at |
Zeitpunkt der letzten Änderung |
Records auflisten
Die Records einer Zone abrufen:
curl "$XCLOUD_DNS_API/zones/$ZONE_ID/records" \
-H "Authorization: Bearer $XCLOUD_DNS_TOKEN"
{
"data": [
{
"id": "5f0c2d6e-8b1a-4f3e-9c2d-1a7b8e9f0c11",
"zone_id": "0b7c4f0e-2a51-4c4e-9a7f-5d3c1e8b9f10",
"zone_name": "example.com",
"record_type": "MX",
"subdomain": "",
"content": "mail.example.com",
"ttl": 3600,
"prio": 10,
"comment": "Primärer Mailserver",
"dyndns_enabled": false,
"dyndns_url": null,
"created_at": "2026-09-14T10:25:03+02:00",
"updated_at": "2026-09-14T10:25:03+02:00"
},
{
"id": "9a3e7b21-4c5d-4e6f-8a9b-0c1d2e3f4a52",
"zone_id": "0b7c4f0e-2a51-4c4e-9a7f-5d3c1e8b9f10",
"zone_name": "example.com",
"record_type": "A",
"subdomain": "www",
"content": "192.0.2.10",
"ttl": 3600,
"prio": null,
"comment": null,
"dyndns_enabled": false,
"dyndns_url": null,
"created_at": "2026-09-14T10:24:51+02:00",
"updated_at": "2026-10-19T17:42:05+02:00"
}
]
}
Record anlegen
POST /zones/{zone_id}/records legt einen Record in der Zone an.
| Attribut | Pflicht | Beschreibung |
|---|---|---|
record_type |
ja | Record-Typ, siehe Tabelle unten |
content |
ja | Wert des Records, höchstens 20.000 Zeichen |
subdomain |
nein | Name relativ zur Zone; für die Zone selbst weglassen |
ttl |
nein | TTL in Sekunden, mindestens 60; Standard 3600 |
prio |
bei MX, SRV |
Priorität (Ganzzahl ab 0); nur bei MX und SRV |
comment |
nein | Freitext-Notiz, höchstens 255 Zeichen |
Das Format des Werts hängt vom Record-Typ ab:
| Typ | content |
Hinweise |
|---|---|---|
A |
IPv4-Adresse, z. B. 192.0.2.10 |
DynDNS möglich |
AAAA |
IPv6-Adresse, z. B. 2001:db8::10 |
DynDNS möglich |
CNAME |
Ziel-Hostname, z. B. shop.example.net |
Nicht auf der Zone selbst |
MX |
Hostname des Mailservers, z. B. mail.example.com |
prio erforderlich |
NS |
Hostname des Nameservers, z. B. ns1.example.net |
Delegiert die Subdomain |
PTR |
Ziel-Hostname | |
SPF |
SPF-Richtlinie als Text | |
SRV |
Weight Port Ziel, z. B. 10 5060 sip.example.com |
prio erforderlich |
TXT |
Freier Text, z. B. v=DMARC1; p=reject |
|
TLSA |
Usage Selector Matching-Type Daten, z. B. 3 1 1 2b4f… |
Name _port._protokoll |
Weitere Regeln:
- Der Name eines
TLSA-Records muss mit_port._protokollbeginnen, z. B._443._tcpoder_25._tcp.mail. - Ein
CNAME-Record muss der einzige Record mit seinem Namen sein. - Gib
TXT- undSPF-Werte als reinen Text ohne umschließende Anführungszeichen an. Hostnamen kannst du mit oder ohne abschließenden Punkt angeben. - Unterhalb einer delegierten Subdomain sind nur
NS-Records erlaubt, unterhalb einer virtuellen Subdomain alle Typen außerNS.
Ein MX-Record für die Zone selbst:
curl -X POST "$XCLOUD_DNS_API/zones/$ZONE_ID/records" \
-H "Authorization: Bearer $XCLOUD_DNS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"record": {
"record_type": "MX",
"content": "mail.example.com",
"prio": 10,
"ttl": 3600,
"comment": "Primärer Mailserver"
}
}'
Ein SRV-Record für SIP über TCP. Die Priorität gehört in prio, die übrigen drei
Werte in content:
curl -X POST "$XCLOUD_DNS_API/zones/$ZONE_ID/records" \
-H "Authorization: Bearer $XCLOUD_DNS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"record": {
"record_type": "SRV",
"subdomain": "_sip._tcp",
"content": "5 5060 sip.example.com",
"prio": 10,
"ttl": 3600
}
}'
Ein TXT-Record mit einer DMARC-Richtlinie:
curl -X POST "$XCLOUD_DNS_API/zones/$ZONE_ID/records" \
-H "Authorization: Bearer $XCLOUD_DNS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"record": {
"record_type": "TXT",
"subdomain": "_dmarc",
"content": "v=DMARC1; p=reject; rua=mailto:dmarc@example.com",
"ttl": 3600
}
}'
Ein TLSA-Record für einen Mailserver auf Port 25:
curl -X POST "$XCLOUD_DNS_API/zones/$ZONE_ID/records" \
-H "Authorization: Bearer $XCLOUD_DNS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"record": {
"record_type": "TLSA",
"subdomain": "_25._tcp.mail",
"content": "3 1 1 0c72ac70b745ac19998811b131d662c9ac69dbdbe7cb23e5b514b56664c5d3d6",
"ttl": 3600
}
}'
Die Antwort enthält den angelegten Record in data.
Record ändern
PATCH /records/{id} ändert die Attribute subdomain, content, ttl, prio und
comment. Attribute, die du weglässt, bleiben unverändert. Den Record-Typ kannst du
nicht ändern; lösche dafür den Record und lege einen neuen an. Um einen Kommentar zu
entfernen, schickst du null:
curl -X PATCH "$XCLOUD_DNS_API/records/$RECORD_ID" \
-H "Authorization: Bearer $XCLOUD_DNS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"record": {
"content": "198.51.100.20",
"ttl": 300,
"comment": null
}
}'
Mehrere Records ändern oder löschen
PATCH /zones/{zone_id}/records/bulk_ttl setzt eine gemeinsame TTL für mehrere Records
einer Zone, POST /zones/{zone_id}/records/bulk_destroy löscht mehrere Records einer
Zone. Beide nehmen höchstens 200 Record-IDs pro Anfrage an und sind atomar: Entweder
werden alle Records geändert oder keiner.
Die TTL zweier Records vor einem Umzug senken:
curl -X PATCH "$XCLOUD_DNS_API/zones/$ZONE_ID/records/bulk_ttl" \
-H "Authorization: Bearer $XCLOUD_DNS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"record": {
"ids": [
"5f0c2d6e-8b1a-4f3e-9c2d-1a7b8e9f0c11",
"9a3e7b21-4c5d-4e6f-8a9b-0c1d2e3f4a52"
],
"ttl": 300
}
}'
bulk_destroy nimmt dieselbe Struktur {"record": {"ids": [...]}} ohne ttl an.
DynDNS
DynDNS steht für A- und AAAA-Records zur Verfügung. POST /records/{id}/dyndns
schaltet DynDNS ein und erzeugt eine neue Update-URL, die die Antwort in dyndns_url
liefert. Ein erneuter Aufruf erzeugt eine neue URL und macht die bisherige ungültig.
DELETE /records/{id}/dyndns schaltet DynDNS aus und macht die URL ungültig.
Um den Record zu aktualisieren, rufst du die Update-URL mit einer einfachen
GET-Anfrage von dem Gerät aus auf, auf dessen IP-Adresse der Record zeigen soll. Ein
Token ist nicht nötig, die URL selbst autorisiert die Anfrage:
curl "$DYNDNS_URL"
Der Record wird auf die IP-Adresse gesetzt, von der die Anfrage kommt. Die
Adressfamilie muss zum Record-Typ passen: Ein A-Record erfordert eine IPv4-Anfrage
(z. B. curl -4), ein AAAA-Record eine IPv6-Anfrage (curl -6); sonst wird die
Anfrage mit 422 abgelehnt. Halte die URL geheim: Jeder, der sie kennt, kann den Record
ändern.
Delegierte Subdomains
| Methode | Pfad | Beschreibung |
|---|---|---|
GET |
/zones/{zone_id}/sub_zones |
Delegierte und virtuelle Subdomains auflisten |
POST |
/zones/{zone_id}/sub_zones |
Eine Subdomain anlegen |
DELETE |
/zones/{zone_id}/sub_zones/{id} |
Eine Subdomain löschen |
Eine Subdomain (sub_zone) legt fest, wie ein Teil der Zone verwaltet wird:
delegating: Die Subdomain wird an andere Nameserver delegiert. Darunter sind nurNS-Records erlaubt, also die Delegierung selbst.virtual: Die Subdomain gruppiert Records nur und bleibt Teil der Zone. Darunter sind alle Record-Typen außerNSerlaubt.
Attribute einer Subdomain
| Attribut | Beschreibung |
|---|---|
id |
ID der Subdomain |
zone_id |
ID der Zone |
name |
Name relativ zur Zone, z. B. shop |
function |
delegating oder virtual |
records_count |
Anzahl der Records unterhalb der Subdomain |
created_at |
Zeitpunkt der Erstellung |
Die Subdomains einer Zone abrufen:
curl "$XCLOUD_DNS_API/zones/$ZONE_ID/sub_zones" \
-H "Authorization: Bearer $XCLOUD_DNS_TOKEN"
{
"data": [
{
"id": "c4d5e6f7-0a1b-4c2d-8e3f-4a5b6c7d8e93",
"zone_id": "0b7c4f0e-2a51-4c4e-9a7f-5d3c1e8b9f10",
"name": "shop",
"function": "delegating",
"records_count": 2,
"created_at": "2026-10-02T14:08:44+02:00"
}
]
}
Subdomain anlegen und löschen
Eine delegierte Subdomain shop.example.com anlegen und danach die NS-Records der
Delegierung:
curl -X POST "$XCLOUD_DNS_API/zones/$ZONE_ID/sub_zones" \
-H "Authorization: Bearer $XCLOUD_DNS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"sub_zone": {"name": "shop", "function": "delegating"}}'
for ns in ns1.shop-hosting.example ns2.shop-hosting.example; do
curl -X POST "$XCLOUD_DNS_API/zones/$ZONE_ID/records" \
-H "Authorization: Bearer $XCLOUD_DNS_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"record\": {\"record_type\": \"NS\", \"subdomain\": \"shop\", \"content\": \"$ns\"}}"
done
Der name ist relativ zur Zone und darf nicht die Zone selbst sein. Bereits vorhandene
Records unterhalb der neuen Subdomain werden ihr zugeordnet. Löschst du eine Subdomain,
bleiben ihre Records in der Zone. Eine delegierte Subdomain lässt sich erst löschen,
wenn sie keine NS-Records mehr enthält.