Domain Basics

8 Aufrufe Markdown

The nine endpoints behind a domain's nameservers, transfer lock, ownership details and recovery.

Overview

These nine endpoints run a domain's basics. Where it points, whether it can be moved, who it appears to belong to, and whether it survives expiry.

All of them make a real call to the registry. So they can be slow, they can hit the registry's own rules, and a module may not support an operation at all. Every endpoint shares the same four preconditions. The service must exist, be a domain, have a registrar module attached, and that module must support the operation.

Reference

Setting the Nameservers

put/api/v1/admin/services/{id}/domain/nameservers
Services/SetDomainNameservers admin goes to the registry

Writes which nameservers the domain points at.

Body 4
ns1stringrequiredThe primary nameserver. It has to be a valid host name.
ns2stringrequiredThe secondary nameserver.
ns3stringA third nameserver.
ns4stringA fourth nameserver.
Response fields data — 2
nameserversstring[]The nameservers written. Ones left empty are not in the list.
idintService id.
Errors 7
not_found404No such service.
not_domain422The service is not a domain.
no_module422No registrar module is attached.
not_supported422The module does not support this operation.
ns_required422One of the first two nameservers was empty.
ns_invalid422A nameserver is not a valid host name.
insufficient_scope403The key lacks the required scope.
Request
curl -X PUT 'https://panel.example.com/api/v1/admin/services/520/domain/nameservers' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"ns1":"ns1.example.com","ns2":"ns2.example.com"}'
const res = await fetch('https://panel.example.com/api/v1/admin/services/520/domain/nameservers', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    ns1: 'ns1.example.com',
    ns2: 'ns2.example.com',
  }),
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/services/520/domain/nameservers');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PUT',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'ns1' => 'ns1.example.com',
        'ns2' => 'ns2.example.com',
    ]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// The list is written WHOLE: leave ns3 and ns4 out and any existing ones are cleared.
$response = Api::Services()->SetDomainNameservers([
    'id'  => 520,
    'ns1' => 'ns1.example.com',
    'ns2' => 'ns2.example.com',
]);

Reading the Transfer Lock

get/api/v1/admin/services/{id}/domain/transfer-lock
Services/GetDomainTransferLock admin

Returns whether the domain is locked against being moved to another registrar.

Response fields data — 1
transfer_lockstringThe lock state. The value comes raw from the registry and differs between them.
Errors 6
not_found404No such service.
not_domain422The service is not a domain.
no_module422No registrar module is attached.
not_supported422The module does not support this operation.
module_failed500The registry could not complete the operation.
insufficient_scope403The key lacks the required scope.
Request
curl 'https://panel.example.com/api/v1/admin/services/520/domain/transfer-lock' \
  -H "Authorization: Bearer $API_KEY"
const res  = await fetch('https://panel.example.com/api/v1/admin/services/520/domain/transfer-lock', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/services/520/domain/transfer-lock');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// Reading returns a RAW value while writing returns 'enabled'/'disabled': not the same vocabulary.
$response = Api::Services()->GetDomainTransferLock(['id' => 520]);

Changing the Transfer Lock

put/api/v1/admin/services/{id}/domain/transfer-lock
Services/SetDomainTransferLock admin

Locks the domain against being moved, or unlocks it.

Body 1
statusstringrequiredenable locks it, disable unlocks it.
Response fields data — 2
transfer_lockstringThe lock state afterwards.
idintService id.
Errors 7
not_found404No such service.
not_domain422The service is not a domain.
no_module422No registrar module is attached.
not_supported422The module does not support this operation.
invalid_status422The status is neither enable nor disable.
module_failed500The registry could not complete the operation.
insufficient_scope403The key lacks the required scope.
Request
curl -X PUT 'https://panel.example.com/api/v1/admin/services/520/domain/transfer-lock' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"status":"enable"}'
const res = await fetch('https://panel.example.com/api/v1/admin/services/520/domain/transfer-lock', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ status: 'enable' }),
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/services/520/domain/transfer-lock');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PUT',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(['status' => 'enable']),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// While the lock is ON the domain cannot move: unlock it before the client leaves for another registrar.
Api::Services()->SetDomainTransferLock(['id' => 520, 'status' => 'disable']);
$code = Api::Services()->GetDomainAuthCode(['id' => 520]);

Getting the Authorisation Code

get/api/v1/admin/services/{id}/domain/auth-code
Services/GetDomainAuthCode admin may go by e-mail

Asks for the code needed to move the domain to another registrar.

Response fields data — 2
auth_codestringThe authorisation code. Present only when the module hands it over directly.
sentboolThe code was e-mailed to the registrant. In that case the code itself is not in the response.
Errors 6
not_found404No such service.
not_domain422The service is not a domain.
no_module422No registrar module is attached.
not_supported422The module does not support this operation.
module_failed500The registry could not complete the operation.
insufficient_scope403The key lacks the required scope.
Request
curl 'https://panel.example.com/api/v1/admin/services/520/domain/auth-code' \
  -H "Authorization: Bearer $API_KEY"
const res  = await fetch('https://panel.example.com/api/v1/admin/services/520/domain/auth-code', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();

if (body.data.sent) {
  // it went by e-mail, the code is not here
}
$ch = curl_init('https://panel.example.com/api/v1/admin/services/520/domain/auth-code');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// There are two response shapes; do NOT assume the code arrived.
$response = Api::Services()->GetDomainAuthCode(['id' => 520])['data'];

$code = $response['auth_code'] ?? null;
$mailed = $response['sent'] ?? false;
Response
{
  "data": {
    "auth_code": "EXAMPLE-AUTH-CODE"
  }
}
{
  "data": {
    "sent": true
  }
}

Restoring the Domain

post/api/v1/admin/services/{id}/domain/restore
Services/RestoreDomain admin time-bound

Recovers an expired domain. It only works while the recovery window is open.

Body
No body is needed; send an empty one. The domain is addressed by the service id in the path.
Response fields data — 2
restoredboolWhether the recovery succeeded.
idintService id.
Errors 7
not_found404No such service.
not_domain422The service is not a domain.
no_module422No registrar module is attached.
not_supported422The module does not support this operation.
not_in_window422The domain is not in the recovery window. Once it closes the domain may have been released.
module_failed500The registry could not complete the operation.
insufficient_scope403The key lacks the required scope.
Request
curl -X POST 'https://panel.example.com/api/v1/admin/services/520/domain/restore' \
  -H "Authorization: Bearer $API_KEY"
const res = await fetch('https://panel.example.com/api/v1/admin/services/520/domain/restore', {
  method: 'POST',
  headers: { Authorization: `Bearer ${apiKey}` },
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/services/520/domain/restore');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// Recovery costs a FEE at the registry, and it has to be called before the window closes.
$response = Api::Services()->RestoreDomain(['id' => 520]);

Checking a Transfer

post/api/v1/admin/services/{id}/domain/check-transfer
Services/CheckDomainTransfer admin

Asks the registry where a domain transfer in progress has got to.

Body
No body is needed; send an empty one. The transfer is addressed by the service id in the path.
Response fields data — 2
transfer_statusstringThe transfer status. A service that is not a transfer comes back with the error value.
messagestring | nullAn explanation from the registry.
Errors 6
not_found404No such service.
not_domain422The service is not a domain.
no_module422No registrar module is attached.
not_supported422The module does not support this operation.
module_failed500The registry could not complete the operation.
insufficient_scope403The key lacks the required scope.
Request
curl -X POST 'https://panel.example.com/api/v1/admin/services/520/domain/check-transfer' \
  -H "Authorization: Bearer $API_KEY"
const res = await fetch('https://panel.example.com/api/v1/admin/services/520/domain/check-transfer', {
  method: 'POST',
  headers: { Authorization: `Bearer ${apiKey}` },
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/services/520/domain/check-transfer');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// The error state comes back inside a 200, not as an HTTP error: read the status before assuming success.
$check = Api::Services()->CheckDomainTransfer(['id' => 520])['data'];

$stuck = $check['transfer_status'] === 'error';

Reading the WHOIS Contacts

get/api/v1/admin/services/{id}/domain/whois
Services/GetDomainWhois admin four contacts

Fetches the domain's contact details from the registry.

Response fields data — 4
registrantobjectThe registrant's contact. This is who legally holds the domain.
first_namestringFirst name.
last_namestringLast name.
companystringCompany name.
emailstringE-mail address.
phonestringPhone number.
phone_ccstringCountry code for the phone.
faxstringFax number.
fax_ccstringCountry code for the fax.
address_line1stringFirst line of the address.
address_line2stringSecond line of the address.
citystringCity.
statestringState or region.
zipcodestringPostcode.
countrystringCountry. The two-letter ISO code.
administrativeobjectThe administrative contact.
first_namestringFirst name.
last_namestringLast name.
companystringCompany name.
emailstringE-mail address.
phonestringPhone number.
phone_ccstringCountry code for the phone.
faxstringFax number.
fax_ccstringCountry code for the fax.
address_line1stringFirst line of the address.
address_line2stringSecond line of the address.
citystringCity.
statestringState or region.
zipcodestringPostcode.
countrystringCountry. The two-letter ISO code.
technicalobjectThe technical contact.
first_namestringFirst name.
last_namestringLast name.
companystringCompany name.
emailstringE-mail address.
phonestringPhone number.
phone_ccstringCountry code for the phone.
faxstringFax number.
fax_ccstringCountry code for the fax.
address_line1stringFirst line of the address.
address_line2stringSecond line of the address.
citystringCity.
statestringState or region.
zipcodestringPostcode.
countrystringCountry. The two-letter ISO code.
billingobjectThe billing contact.
first_namestringFirst name.
last_namestringLast name.
companystringCompany name.
emailstringE-mail address.
phonestringPhone number.
phone_ccstringCountry code for the phone.
faxstringFax number.
fax_ccstringCountry code for the fax.
address_line1stringFirst line of the address.
address_line2stringSecond line of the address.
citystringCity.
statestringState or region.
zipcodestringPostcode.
countrystringCountry. The two-letter ISO code.
Errors 6
not_found404No such service.
not_domain422The service is not a domain.
no_module422No registrar module is attached.
not_supported422The module does not support this operation.
module_failed500The registry could not complete the operation.
insufficient_scope403The key lacks the required scope.
Request
curl 'https://panel.example.com/api/v1/admin/services/520/domain/whois' \
  -H "Authorization: Bearer $API_KEY"
const res  = await fetch('https://panel.example.com/api/v1/admin/services/520/domain/whois', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/services/520/domain/whois');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// The read goes to the registry and refreshes the local copy too, so it can be slow.
$whois = Api::Services()->GetDomainWhois(['id' => 520])['data'];
$owner = $whois['registrant'];
Response
{
  "data": {
    "registrant": {
      "first_name": "John",
      "last_name": "Doe",
      "company": "",
      "email": "[email protected]",
      "phone": "5550100",
      "phone_cc": "+1",
      "fax": "",
      "fax_cc": "",
      "address_line1": "123 Market Street",
      "address_line2": "",
      "city": "San Francisco",
      "state": "California",
      "zipcode": "94105",
      "country": "US"
    },
    "administrative": { "first_name": "John", "last_name": "Doe", "email": "[email protected]" },
    "technical": { "first_name": "John", "last_name": "Doe", "email": "[email protected]" },
    "billing": { "first_name": "John", "last_name": "Doe", "email": "[email protected]" }
  }
}

Writing the WHOIS Contacts

put/api/v1/admin/services/{id}/domain/whois
Services/SetDomainWhois admin ownership is affected

Writes the contact details to the registry.

Body 4
registrantobjectThe registrant's contact. This is who legally holds the domain.
first_namestringFirst name.
last_namestringLast name.
companystringCompany name.
emailstringE-mail address.
phonestringPhone number.
phone_ccstringCountry code for the phone.
faxstringFax number.
fax_ccstringCountry code for the fax.
address_line1stringFirst line of the address.
address_line2stringSecond line of the address.
citystringCity.
statestringState or region.
zipcodestringPostcode.
countrystringCountry. The two-letter ISO code.
administrativeobjectThe administrative contact.
first_namestringFirst name.
last_namestringLast name.
companystringCompany name.
emailstringE-mail address.
phonestringPhone number.
phone_ccstringCountry code for the phone.
faxstringFax number.
fax_ccstringCountry code for the fax.
address_line1stringFirst line of the address.
address_line2stringSecond line of the address.
citystringCity.
statestringState or region.
zipcodestringPostcode.
countrystringCountry. The two-letter ISO code.
technicalobjectThe technical contact.
first_namestringFirst name.
last_namestringLast name.
companystringCompany name.
emailstringE-mail address.
phonestringPhone number.
phone_ccstringCountry code for the phone.
faxstringFax number.
fax_ccstringCountry code for the fax.
address_line1stringFirst line of the address.
address_line2stringSecond line of the address.
citystringCity.
statestringState or region.
zipcodestringPostcode.
countrystringCountry. The two-letter ISO code.
billingobjectThe billing contact.
first_namestringFirst name.
last_namestringLast name.
companystringCompany name.
emailstringE-mail address.
phonestringPhone number.
phone_ccstringCountry code for the phone.
faxstringFax number.
fax_ccstringCountry code for the fax.
address_line1stringFirst line of the address.
address_line2stringSecond line of the address.
citystringCity.
statestringState or region.
zipcodestringPostcode.
countrystringCountry. The two-letter ISO code.
Response fields data — 1
savedboolWhether the save succeeded.
Errors 6
not_found404No such service.
not_domain422The service is not a domain.
no_module422No registrar module is attached.
not_supported422The module does not support this operation.
module_failed500The registry could not complete the operation.
insufficient_scope403The key lacks the required scope.
Request
curl -X PUT 'https://panel.example.com/api/v1/admin/services/520/domain/whois' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"registrant":{"first_name":"John","last_name":"Doe","email":"[email protected]","phone":"5550100","phone_cc":"+1","address_line1":"123 Market Street","city":"San Francisco","state":"California","zipcode":"94105","country":"US"}}'
const res = await fetch('https://panel.example.com/api/v1/admin/services/520/domain/whois', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    registrant: {
      first_name: 'John',
      last_name: 'Doe',
      email: '[email protected]',
      phone: '5550100',
      phone_cc: '+1',
      address_line1: '123 Market Street',
      city: 'San Francisco',
      state: 'California',
      zipcode: '94105',
      country: 'US',
    },
  }),
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/services/520/domain/whois');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PUT',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'registrant' => [
            'first_name'    => 'John',
            'last_name'     => 'Doe',
            'email'         => '[email protected]',
            'address_line1' => '123 Market Street',
            'city'          => 'San Francisco',
            'country'       => 'US',
        ],
    ]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// Read first and write on top: fields left out can end up empty at the registry.
$whois = Api::Services()->GetDomainWhois(['id' => 520])['data'];

$whois['registrant']['email'] = '[email protected]';

Api::Services()->SetDomainWhois(['id' => 520] + $whois);

Changing WHOIS Privacy

put/api/v1/admin/services/{id}/domain/whois-privacy
Services/SetDomainWhoisPrivacy admin

Turns on or off the hiding of contact details in public lookups.

Body 1
statusstringrequiredenable hides them, disable reveals them.
Response fields data — 1
whois_privacystringThe privacy state afterwards. Either enabled or disabled.
Errors 7
not_found404No such service.
not_domain422The service is not a domain.
no_module422No registrar module is attached.
not_supported422The module does not support this operation.
invalid_status422The status is neither enable nor disable.
module_failed500The registry could not complete the operation.
insufficient_scope403The key lacks the required scope.
Request
curl -X PUT 'https://panel.example.com/api/v1/admin/services/520/domain/whois-privacy' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"status":"enable"}'
const res = await fetch('https://panel.example.com/api/v1/admin/services/520/domain/whois-privacy', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ status: 'enable' }),
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/services/520/domain/whois-privacy');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PUT',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(['status' => 'enable']),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// On most extensions privacy is a PAID add-on, so turning it on can raise an invoice.
$response = Api::Services()->SetDomainWhoisPrivacy([
    'id'     => 520,
    'status' => 'enable',
]);

Pitfalls

The authorisation code has two response shapes

Some registries hand the code over directly while others e-mail it to the registrant. In the second case the response says only that it was sent and carries no code. A client that assumes the code arrived reads an empty value here.

The nameserver list is written whole

What you send becomes the truth: leave the third and fourth out and any existing ones are cleared. Even to change only the primary, the others have to go with it.

Changing the registrant changes ownership

The WHOIS write is more than updating contact details: the registrant field decides who legally holds the domain. On most extensions that change starts an approval process and locks the domain out of transfers for a while. Fields left out can also end up empty at the registry, so read first and write on top.

The recovery window closes

An expired domain first passes through a period where it can be recovered, then it is released. Once the window closes this endpoint answers not_in_window and there is nothing left to do. Recovery also tends to cost a steep fee at the registry.

The transfer check returns its error inside a 200

A service that is not a transfer, or a transfer that is stuck, shows up in the status field of the response rather than as an HTTP error. A client reading only the status code counts a failed transfer as a success.

War das hilfreich?

Vielen Dank für Ihre Rückmeldung!

Brauchen Sie weitere Hilfe?

Unser Support-Team ist rund um die Uhr für Sie da, wenn Sie oben nicht fündig werden.