Domain Verification Hooks
The nine hooks over registrant verification and reading from the provider — even a read has a gate of its own.
Overview
Some extensions ask the registrant to prove who they are with a document. An unverified name can be suspended, so that flow has hooks of its own: a gate stopping the submission, an event reporting the outcome, and a filter handing you the whole screen.
The second group is less known: read gates. Reading name servers or contact details means a real request to the provider, so a gate stands in front of a read as well.
Reference
Stopping a verification submission
Runs before the submitted documents are handled and nothing is saved yet.
key, type, name, required, options. They differ by extension and module.Hook::add('gate:domain.verification_submit', 10, function ($service, $defs, $tld) {
// A second submission while a review is open only causes confusion.
if (Acme::reviewOpen((int) ($service['id'] ?? 0)))
return 'Your earlier submission is still under review.';
return null;
});Following a verification submission
Runs after the documents were handled and the fields saved.
Hook::add('action:domain.verification_submitted', 10,
function ($service, $submitted, $defs) {
// Zero fields means the submission was empty: keep it out of the queue.
if ($submitted > 0) Ops::queue('registrant-review', $service['id'] ?? 0);
});Changing the verification screen
Runs after the verification screen's whole payload was built, before it appears.
state (none, form, review, rejected, verified), fields, operator_note. state picks which shell is shown; leave all three keys in place.Hook::add('filter:domain.verification_state', 10, function (&$data, $service) {
// Leave state, fields and operator_note in place; the shell follows state.
if (($data['state'] ?? '') === 'rejected')
$data['operator_note'] = Acme::helpText($data['operator_note'] ?? '');
});Stopping a contact read
Runs before the contact details are read from the provider.
Hook::add('gate:domain.contacts_get', 10, function ($service, $serviceId) {
// Where the provider charges per query, hold the reads down.
if (Acme::readQuotaSpent($serviceId)) return 'Today\'s query allowance is spent.';
return null;
});Following contact details that were read
Runs after the contact details came back from the provider.
Hook::add('action:domain.contacts_fetched', 10, function ($service, $whois) {
// Personal data: do not log it, only check it against our mirror.
Acme::compareMirror((int) ($service['id'] ?? 0), $whois);
});Stopping a name server read
Runs before the name servers are read from the provider.
Hook::add('gate:domain.nameservers_get', 10, function ($service, $serviceId) {
if (($service['status'] ?? '') === 'transfer')
return 'Name servers cannot be read while a transfer runs.';
return null;
});Following name servers that were read
Runs after the name servers came back from the provider.
Hook::add('action:domain.nameservers_fetched', 10, function ($service, $nameservers) {
// A provider value different from ours means the two have drifted.
Acme::driftCheck((int) ($service['id'] ?? 0), $nameservers);
});Stopping a DNS record read
Runs before the DNS records are read from the provider.
Hook::add('gate:domain.dns_records_get', 10, function ($service, $serviceId) {
// Without the DNS management add-on, reading makes no sense either.
if (!Acme::addonActive($serviceId, 'dns-manage')) return 'DNS management is off.';
return null;
});Pitfalls
Stopping a read does more than cut the request: that part of the screen never fills, and the customer or operator may not see why. The text you return is shown to them, so say what was stopped and why in that sentence.
The contact read hook hands you names, addresses, phone numbers and e-mail. Do not put those in logs, outside systems or notification bodies. Where you need a comparison, keep whether a difference exists rather than the values.
state picks the shell, fields fills it, and operator_note carries the rejection reason. Dropping one breaks the screen: without state, for one, there is no telling which shell to draw.
The verification event also runs where no field landed, with the counter at 0. Assuming "a document arrived" without reading the number drops an empty submission into the review queue.
Related Articles
- Domain Contact Hooks
- Domain DNS Hooks
- Domain Hooks
Thanks for your feedback!
Our support team is here around the clock for anything you can't find above.