DNS Management
The eleven endpoints behind a domain's DNS records, child nameservers and DNSSEC signatures.
Overview
These eleven endpoints run a domain's name resolution: which name points where, the domain's own nameservers, and signature validation.
Three separate jobs sit together. Child nameservers define the domain's own servers. DNS records say which name goes where. DNSSEC makes those answers signed.
None of it keeps a local copy: every read goes to the registry and every write is live at once.
Reference
Listing the Child Nameservers
Returns the nameservers defined under the domain itself.
curl 'https://panel.example.com/api/v1/admin/services/520/domain/child-nameservers' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/services/520/domain/child-nameservers', {
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/services/520/domain/child-nameservers');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// When the module cannot list them a LOCAL copy is returned, which can drift from the registry.
$response = Api::Services()->GetDomainChildNameservers(['id' => 520]);Adding a Child Nameserver
Defines a new nameserver under the domain.
201.curl -X POST 'https://panel.example.com/api/v1/admin/services/520/domain/child-nameservers' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"ns":"ns1.example.com","ip":"203.0.113.10"}'const res = await fetch('https://panel.example.com/api/v1/admin/services/520/domain/child-nameservers', {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ ns: 'ns1.example.com', ip: '203.0.113.10' }),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/services/520/domain/child-nameservers');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'ns' => 'ns1.example.com',
'ip' => '203.0.113.10',
]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// Defining a child nameserver does not START USING it; point the domain at it separately.
Api::Services()->AddDomainChildNameserver([
'id' => 520,
'ns' => 'ns1.example.com',
'ip' => '203.0.113.10',
]);
Api::Services()->SetDomainNameservers([
'id' => 520,
'ns1' => 'ns1.example.com',
'ns2' => 'ns2.example.com',
]);Updating a Child Nameserver
Finds an existing child nameserver and replaces it with new values.
curl -X PUT 'https://panel.example.com/api/v1/admin/services/520/domain/child-nameservers' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"old_ns":"ns1.example.com","old_ip":"203.0.113.10","new_ns":"ns1.example.com","new_ip":"203.0.113.20"}'const res = await fetch('https://panel.example.com/api/v1/admin/services/520/domain/child-nameservers', {
method: 'PUT',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
old_ns: 'ns1.example.com',
old_ip: '203.0.113.10',
new_ns: 'ns1.example.com',
new_ip: '203.0.113.20',
}),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/services/520/domain/child-nameservers');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'old_ns' => 'ns1.example.com',
'old_ip' => '203.0.113.10',
'new_ns' => 'ns1.example.com',
'new_ip' => '203.0.113.20',
]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// The record is found by its old value, not an id: get the old name wrong and nothing matches.
Api::Services()->UpdateDomainChildNameserver([
'id' => 520,
'old_ns' => 'ns1.example.com',
'old_ip' => '203.0.113.10',
'new_ns' => 'ns1.example.com',
'new_ip' => '203.0.113.20',
]);Deleting a Child Nameserver
Removes a child nameserver definition.
curl -X DELETE 'https://panel.example.com/api/v1/admin/services/520/domain/child-nameservers' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"ns":"ns1.example.com"}'const res = await fetch('https://panel.example.com/api/v1/admin/services/520/domain/child-nameservers', {
method: 'DELETE',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ ns: 'ns1.example.com' }),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/services/520/domain/child-nameservers');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode(['ns' => 'ns1.example.com']),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// Deleting a child nameserver that is in use can leave the domain unreachable.
Api::Services()->DeleteDomainChildNameserver(['id' => 520, 'ns' => 'ns1.example.com']);Listing the DNS Records
Returns the domain's DNS records. No local copy is kept.
curl 'https://panel.example.com/api/v1/admin/services/520/domain/dns-records' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/services/520/domain/dns-records', {
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/services/520/domain/dns-records');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// The 'identity' needed to update or delete comes from HERE; it cannot be produced elsewhere.
$records = Api::Services()->GetDomainDnsRecords(['id' => 520])['data'];
$www = current(array_filter($records, fn (array $r): bool => $r['name'] === 'www'));{
"data": [
{
"identity": "1001",
"type": "A",
"name": "@",
"value": "203.0.113.10",
"ttl": 3600,
"priority": 0
}
]
}Adding a DNS Record
Adds a new DNS record to the domain.
201.added.curl -X POST 'https://panel.example.com/api/v1/admin/services/520/domain/dns-records' \
-H "Authorization: Bearer $API_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/admin/services/520/domain/dns-records', {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
type: 'A',
name: 'www',
value: '203.0.113.10',
ttl: 3600,
}),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/services/520/domain/dns-records');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'type' => 'A',
'name' => 'www',
'value' => '203.0.113.10',
'ttl' => 3600,
]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// The response may NOT carry the record it added; read the list again to learn its identity.
Api::Services()->AddDomainDnsRecord([
'id' => 520,
'type' => 'A',
'name' => 'www',
'value' => '203.0.113.10',
]);
$records = Api::Services()->GetDomainDnsRecords(['id' => 520])['data'];Updating a DNS Record
Changes an existing DNS record. It does not run if the module offers no update.
updated.curl -X PUT 'https://panel.example.com/api/v1/admin/services/520/domain/dns-records' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"type":"A","name":"www","value":"203.0.113.20","identity":"1001"}'const res = await fetch('https://panel.example.com/api/v1/admin/services/520/domain/dns-records', {
method: 'PUT',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
type: 'A',
name: 'www',
value: '203.0.113.20',
identity: '1001',
}),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/services/520/domain/dns-records');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'type' => 'A',
'name' => 'www',
'value' => '203.0.113.20',
'identity' => '1001',
]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// A module with no update answers 'not_supported'; fall back to delete-then-add.
$response = Api::Services()->UpdateDomainDnsRecord([
'id' => 520,
'type' => 'A',
'name' => 'www',
'value' => '203.0.113.20',
'identity' => '1001',
]);Deleting a DNS Record
Removes a DNS record.
curl -X DELETE 'https://panel.example.com/api/v1/admin/services/520/domain/dns-records' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"type":"A","name":"www","identity":"1001"}'const res = await fetch('https://panel.example.com/api/v1/admin/services/520/domain/dns-records', {
method: 'DELETE',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ type: 'A', name: 'www', identity: '1001' }),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/services/520/domain/dns-records');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'type' => 'A',
'name' => 'www',
'identity' => '1001',
]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// Sending only the type can sweep up other records of the SAME TYPE; give the identity too.
Api::Services()->DeleteDomainDnsRecord([
'id' => 520,
'type' => 'A',
'name' => 'www',
'identity' => '1001',
]);Listing the DNSSEC Records
Returns the domain's DNSSEC signing records.
curl 'https://panel.example.com/api/v1/admin/services/520/domain/dnssec' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/services/520/domain/dnssec', {
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/services/520/domain/dnssec');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);$response = Api::Services()->GetDomainDnssecRecords(['id' => 520]);Adding a DNSSEC Record
Adds a DNSSEC signing record to the domain.
201.added.curl -X POST 'https://panel.example.com/api/v1/admin/services/520/domain/dnssec' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"digest":"49FD46E6C4B45C55D4AC","key_tag":12345,"digest_type":2,"algorithm":13}'const res = await fetch('https://panel.example.com/api/v1/admin/services/520/domain/dnssec', {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
digest: '49FD46E6C4B45C55D4AC',
key_tag: 12345,
digest_type: 2,
algorithm: 13,
}),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/services/520/domain/dnssec');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'digest' => '49FD46E6C4B45C55D4AC',
'key_tag' => 12345,
'digest_type' => 2,
'algorithm' => 13,
]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// The allowed digest type and algorithm come from the MODULE SETTINGS, not every value in the standard.
Api::Services()->AddDomainDnssecRecord([
'id' => 520,
'digest' => $digest,
'key_tag' => 12345,
'digest_type' => 2,
'algorithm' => 13,
]);Deleting a DNSSEC Record
Removes a DNSSEC signing record.
curl -X DELETE 'https://panel.example.com/api/v1/admin/services/520/domain/dnssec' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"digest":"49FD46E6C4B45C55D4AC","key_tag":12345}'const res = await fetch('https://panel.example.com/api/v1/admin/services/520/domain/dnssec', {
method: 'DELETE',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ digest, key_tag: 12345 }),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/services/520/domain/dnssec');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'digest' => $digest,
'key_tag' => 12345,
]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// Deleting the last DS record turns off signature validation; add the new one first.
Api::Services()->AddDomainDnssecRecord(['id' => 520] + $newRecord);
Api::Services()->DeleteDomainDnssecRecord(['id' => 520] + $oldRecord);Pitfalls
The identity on the update and delete endpoints is what the list returned. You cannot make one up, and its shape differs between modules. The add response may not carry the record it created, so read the list again to learn the id.
Only the record type is required on the delete. Sent without a name, a value or an id, it can sweep up other records of the same type, because the module does the matching. Pin down which record you mean with an id before deleting.
The update only runs when the module offers it; otherwise it answers not_supported. On such a module the only route is delete then add, which means a brief gap between the two.
The digest type and the algorithm do not accept every value in the standard. The allowed set is defined in the module's own settings, and a value absent from that list answers invalid_algorithm.
There is no draft or approval step here; a change you make reaches the registry and starts propagating. Deleting a child nameserver that is in use can leave the domain unreachable. Deleting the last DNSSEC record turns off signature validation. Undoing a change that went wrong takes as long as the caches hold it.
Related Articles
Thanks for your feedback!
Our support team is here around the clock for anything you can't find above.