Name Servers and Records
The fourteen endpoints deciding where a domain points.
Overview
Where a domain points is decided in two layers. The name servers say which server answers the questions, and the records on that server say what the answer is.
That split reaches the endpoints: changing name servers is open on every domain, while managing the records here wants the name management add-on.
Three more endpoints go further. Running your own name servers means defining them under the domain, and the signature records prove the answers were not changed on the way.
Reference
Reading the Name Servers
Returns a domain's name servers and the account's default set.
curl 'https://panel.example.com/api/v1/client/domains/example.com/nameservers' \
-H "Authorization: Bearer $CLIENT_KEY"const res = await fetch(`https://panel.example.com/api/v1/client/domains/${domain}/nameservers`, {
headers: { Authorization: `Bearer ${clientKey}` },
});
const { data } = await res.json();
if (data.is_custom) showResetToDefault(data.default);$ch = curl_init('https://panel.example.com/api/v1/client/domains/' . $domain . '/nameservers');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $clientKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// This endpoint wants NO ADD-ON: changing name servers is open on every domain, unlike the records.
$n = Kernel::internal('client:Domains/GetNameservers',
['owner_id' => $uid, 'domain' => $domain])['data'];
$set = $n['nameservers'];Changing the Name Servers
Changes a domain's name servers at the provider.
curl -X PUT 'https://panel.example.com/api/v1/client/domains/example.com/nameservers' \
-H "Authorization: Bearer $CLIENT_KEY" \
-H 'Content-Type: application/json' \
-d '{"nameservers":["ns1.example.net","ns2.example.net"]}'const res = await fetch(`https://panel.example.com/api/v1/client/domains/${domain}/nameservers`, {
method: 'PUT',
headers: {
Authorization: `Bearer ${clientKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ nameservers: list }),
});
const { data } = await res.json();$ch = curl_init('https://panel.example.com/api/v1/client/domains/' . $domain . '/nameservers');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $clientKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode(['nameservers' => $list]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// Changing the name servers MOVES THE SITE: the records on the old ones stop counting.
// Confirm the records are ready on the new servers first.
Kernel::internal('client:Domains/UpdateNameservers',
['owner_id' => $uid, 'domain' => $domain, 'nameservers' => $list]);Reading the Default Name Servers
Returns the default set the account applies to new domains.
curl 'https://panel.example.com/api/v1/client/domains/default-nameservers' \
-H "Authorization: Bearer $CLIENT_KEY"const res = await fetch('https://panel.example.com/api/v1/client/domains/default-nameservers', {
headers: { Authorization: `Bearer ${clientKey}` },
});
const { data } = await res.json();
if (! data.nameservers.length) promptToSetDefaults();$ch = curl_init('https://panel.example.com/api/v1/client/domains/default-nameservers');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $clientKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// The default set applies to NEW registrations and never reaches back to the domains you hold.
$d = Kernel::internal('client:Domains/GetDefaultNameservers', ['owner_id' => $uid])['data'];Saving the Default Name Servers
Saves the default set for new domains.
curl -X PUT 'https://panel.example.com/api/v1/client/domains/default-nameservers' \
-H "Authorization: Bearer $CLIENT_KEY" \
-H 'Content-Type: application/json' \
-d '{"nameservers":["ns1.example.net","ns2.example.net"]}'const res = await fetch('https://panel.example.com/api/v1/client/domains/default-nameservers', {
method: 'PUT',
headers: {
Authorization: `Bearer ${clientKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ nameservers: list }),
});
const { data } = await res.json();$ch = curl_init('https://panel.example.com/api/v1/client/domains/default-nameservers');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $clientKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode(['nameservers' => $list]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// This setting touches NO domain: it is the starting value for the registrations that follow.
Kernel::internal('client:Domains/UpdateDefaultNameservers',
['owner_id' => $uid, 'nameservers' => $list]);Listing Your Own Name Servers
Returns the name servers defined under the domain.
curl 'https://panel.example.com/api/v1/client/domains/example.com/child-nameservers' \
-H "Authorization: Bearer $CLIENT_KEY"const res = await fetch(`https://panel.example.com/api/v1/client/domains/${domain}/child-nameservers`, {
headers: { Authorization: `Bearer ${clientKey}` },
});
const { data } = await res.json();$ch = curl_init('https://panel.example.com/api/v1/client/domains/' . $domain . '/child-nameservers');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $clientKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// These records are for running YOUR OWN name servers; an ordinary domain wants none.
$g = Kernel::internal('client:Domains/GetChildNameservers',
['owner_id' => $uid, 'domain' => $domain])['data'];Defining Your Own Name Server
Defines a name server under the domain.
curl -X POST 'https://panel.example.com/api/v1/client/domains/example.com/child-nameservers' \
-H "Authorization: Bearer $CLIENT_KEY" \
-H 'Content-Type: application/json' \
-d '{"host":"ns1.example.com","ip":"203.0.113.10"}'const res = await fetch(`https://panel.example.com/api/v1/client/domains/${domain}/child-nameservers`, {
method: 'POST',
headers: {
Authorization: `Bearer ${clientKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ host, ip }),
});
const { data } = await res.json();$ch = curl_init('https://panel.example.com/api/v1/client/domains/' . $domain . '/child-nameservers');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $clientKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode(compact('host', 'ip')),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// Defining one is not enough: write the name server set too to POINT the domain at it.
Kernel::internal('client:Domains/CreateChildNameserver',
['owner_id' => $uid, 'domain' => $domain, 'host' => $host, 'ip' => $ip]);
Kernel::internal('client:Domains/UpdateNameservers',
['owner_id' => $uid, 'domain' => $domain, 'nameservers' => [$host, $host2]]);Removing Your Own Name Server
Removes a name server defined under the domain.
curl -X DELETE 'https://panel.example.com/api/v1/client/domains/example.com/child-nameservers' \
-H "Authorization: Bearer $CLIENT_KEY" \
-H 'Content-Type: application/json' \
-d '{"host":"ns1.example.com"}'const res = await fetch(`https://panel.example.com/api/v1/client/domains/${domain}/child-nameservers`, {
method: 'DELETE',
headers: {
Authorization: `Bearer ${clientKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ host }),
});
const { data } = await res.json();$ch = curl_init('https://panel.example.com/api/v1/client/domains/' . $domain . '/child-nameservers');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $clientKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode(['host' => $host]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// Removing a server that is STILL IN USE can leave other domains unreachable.
Kernel::internal('client:Domains/DeleteChildNameserver',
['owner_id' => $uid, 'domain' => $domain, 'host' => $host]);Listing the DNS Records
Reads a domain's DNS records from the provider.
curl 'https://panel.example.com/api/v1/client/domains/example.com/dns-records' \
-H "Authorization: Bearer $CLIENT_KEY"const res = await fetch(`https://panel.example.com/api/v1/client/domains/${domain}/dns-records`, {
headers: { Authorization: `Bearer ${clientKey}` },
});
if (res.status === 422) return offerAddon(await res.json());
const { data } = await res.json();$ch = curl_init('https://panel.example.com/api/v1/client/domains/' . $domain . '/dns-records');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $clientKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// The record id can come EMPTY: that provider knows a record by its type, name and value.
$rows = Kernel::internal('client:Domains/GetDnsRecords',
['owner_id' => $uid, 'domain' => $domain])['data'];
$keyed = (bool) ($rows[0]['identity'] ?? '');Adding a DNS Record
Adds a new DNS record to the domain.
curl -X POST 'https://panel.example.com/api/v1/client/domains/example.com/dns-records' \
-H "Authorization: Bearer $CLIENT_KEY" \
-H 'Content-Type: application/json' \
-d '{"type":"A","name":"www","value":"203.0.113.10","ttl":3600}'const res = await fetch(`https://panel.example.com/api/v1/client/domains/${domain}/dns-records`, {
method: 'POST',
headers: {
Authorization: `Bearer ${clientKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ type: 'A', name: 'www', value: ip }),
});
const { data } = await res.json();
renderRecords(data);$ch = curl_init('https://panel.example.com/api/v1/client/domains/' . $domain . '/dns-records');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $clientKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode($record),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// The answer returns THE FRESH LIST: refresh the screen from it rather than reading again.
$rows = Kernel::internal('client:Domains/CreateDnsRecord',
['owner_id' => $uid, 'domain' => $domain] + $record)['data'];Editing a DNS Record
Changes a DNS record that exists.
curl -X PUT 'https://panel.example.com/api/v1/client/domains/example.com/dns-records' \
-H "Authorization: Bearer $CLIENT_KEY" \
-H 'Content-Type: application/json' \
-d '{"identity":"42","type":"A","name":"www","value":"203.0.113.20"}'const res = await fetch(`https://panel.example.com/api/v1/client/domains/${domain}/dns-records`, {
method: 'PUT',
headers: {
Authorization: `Bearer ${clientKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ identity: rec.identity, ...next }),
});
const { data } = await res.json();$ch = curl_init('https://panel.example.com/api/v1/client/domains/' . $domain . '/dns-records');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $clientKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode($record),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// Editing is ABSENT on some providers: remove and add again where the capability list closes it.
$d = Kernel::internal('client:Domains/GetDomain',
['owner_id' => $uid, 'domain' => $domain])['data'];
if (! $d['capabilities']['dns_edit']) { /* delete + create */ }Removing a DNS Record
Removes a DNS record.
curl -X DELETE 'https://panel.example.com/api/v1/client/domains/example.com/dns-records' \
-H "Authorization: Bearer $CLIENT_KEY" \
-H 'Content-Type: application/json' \
-d '{"identity":"42","type":"A","name":"www"}'const res = await fetch(`https://panel.example.com/api/v1/client/domains/${domain}/dns-records`, {
method: 'DELETE',
headers: {
Authorization: `Bearer ${clientKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ identity: rec.identity, type: rec.type, name: rec.name }),
});
const { data } = await res.json();$ch = curl_init('https://panel.example.com/api/v1/client/domains/' . $domain . '/dns-records');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $clientKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode($selector),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// Sending the TYPE ALONE can remove MORE THAN ONE record of it: add the id, or the name and value.
Kernel::internal('client:Domains/DeleteDnsRecord', ['owner_id' => $uid, 'domain' => $domain,
'identity' => $rec['identity'], 'type' => $rec['type'],
'name' => $rec['name'], 'value' => $rec['value']]);Listing the Signature Records
Returns a domain's signature verification records.
curl 'https://panel.example.com/api/v1/client/domains/example.com/dnssec' \
-H "Authorization: Bearer $CLIENT_KEY"const res = await fetch(`https://panel.example.com/api/v1/client/domains/${domain}/dnssec`, {
headers: { Authorization: `Bearer ${clientKey}` },
});
const { data } = await res.json();
const signed = data.length > 0;$ch = curl_init('https://panel.example.com/api/v1/client/domains/' . $domain . '/dnssec');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $clientKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// These want NO ADD-ON and do want provider support; confirm it from the capability list.
$ds = Kernel::internal('client:Domains/GetDnssecRecords',
['owner_id' => $uid, 'domain' => $domain])['data'];Adding a Signature Record
Adds a signature verification record to the domain.
curl -X POST 'https://panel.example.com/api/v1/client/domains/example.com/dnssec' \
-H "Authorization: Bearer $CLIENT_KEY" \
-H 'Content-Type: application/json' \
-d '{"key_tag":12345,"algorithm":13,"digest_type":2,"digest":"A1B2C3"}'const res = await fetch(`https://panel.example.com/api/v1/client/domains/${domain}/dnssec`, {
method: 'POST',
headers: {
Authorization: `Bearer ${clientKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(ds),
});
if (res.status === 422) showAllowed(await res.json());$ch = curl_init('https://panel.example.com/api/v1/client/domains/' . $domain . '/dnssec');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $clientKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode($ds),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// The set of algorithms allowed follows THE PROVIDER: read the refusal and show the allowed list.
try { Kernel::internal('client:Domains/CreateDnssecRecord',
['owner_id' => $uid, 'domain' => $domain] + $ds); }
catch (\Throwable $e) { $allowed = $e->details['allowed'] ?? []; }Removing a Signature Record
Removes a signature verification record.
curl -X DELETE 'https://panel.example.com/api/v1/client/domains/example.com/dnssec' \
-H "Authorization: Bearer $CLIENT_KEY" \
-H 'Content-Type: application/json' \
-d '{"key_tag":12345,"digest":"A1B2C3"}'const res = await fetch(`https://panel.example.com/api/v1/client/domains/${domain}/dnssec`, {
method: 'DELETE',
headers: {
Authorization: `Bearer ${clientKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ key_tag: ds.key_tag, digest: ds.digest }),
});
const { data } = await res.json();$ch = curl_init('https://panel.example.com/api/v1/client/domains/' . $domain . '/dnssec');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $clientKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode($selector),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// Unsign the zone BEFORE removing the last record: the wrong order leaves the domain unresolvable.
$ds = Kernel::internal('client:Domains/GetDnssecRecords',
['owner_id' => $uid, 'domain' => $domain])['data'];
$isLast = count($ds) === 1;Pitfalls
The DNS record endpoints sit behind the name management add-on. Unbought, or with its invoice unpaid, they all refuse. The answer says which case it is. The name server endpoints pass no such gate and work on every domain.
Changing the name server set sends the domain's questions to a different server. The records you entered here stay on the old one and nobody asks them any more. Do not change the set before confirming the records are ready on the new servers.
Some providers key a record by an id and others know it by its type, name and value. In the second case the id comes empty. Always send the id on an edit or a removal where one exists. Give the full triple where none does, or the wrong record can be picked.
Only the record type is required on a removal, while the name and the value narrow the match. Sending the type alone can take several records of that type at once. Add the name and the value even where you hold no id.
While signature verification is on, the record at the registry and the signature in the zone have to agree. Removing the last record while the zone is still signed, or unsigning the zone while the record stands, leaves the domain unresolvable. Unsign the zone first and remove the record after.
Defining a name server under the domain only brings it into being. The domain uses it once you write the name server set as well. Skipping that second step leaves the definition at the registry with nothing changed.
Related Articles
Thanks for your feedback!
Our support team is here around the clock for anything you can't find above.