Domain Acquisition Hooks

4 vues Markdown

The eight hooks on the path to the domain provider: the gates before a register, transfer or renew call, and the events behind them.

Overview

Getting a domain is a paid and irreversible call. Once the provider opened the registration there is no taking it back, so every step of this path has a gate in front of it and an event behind it.

Gates run before the call and can stop it. Events run after, separately for success and for failure. Below is the full contract of all eight: which values arrive, in what order, and what you have to return.

Reference

Stopping a register or transfer request

gatedomain.create
RegistrarModule::create() before a paid call

Runs immediately before the register or transfer request reaches the provider; the method was checked and the arguments are not built yet.

Parameters 3
$servicearrayThe service record being provisioned. Owner, product and term live here.
$optionsarrayThe parameters going to the provider: sld, tld, year, dns, whois, tcode.
$methodstringThe method about to run: register or transfer. With a transfer code present it is a transfer.
Return 1
stringA non-empty string stops the action; the text is thrown as the error and the provider is never called. null or an empty string lets it carry on.
Listener
Hook::add('gate:domain.create', 10, function ($service, $options, $method) {
    if ($method === 'transfer') return null;              // leave transfers alone

    $years = (int) ($options['year'] ?? 1);
    if ($years > 5) return 'We register at most 5 years at a time.';

    return null;
});

Taking the register or transfer result

actiondomain.created
RegistrarModule::create():122 once per call

Runs right after the provider call returned. It is no promise of success: the result value can carry a failure too.

Parameters 3
$servicearrayThe service record being provisioned.
$resultarray|boolWhat the provider returned: a config and status array, or false on failure. This is the value to read first.
$methodstringThe method that ran: register or transfer.
Return 1
voidThe return is ignored.
Listener
Hook::add('action:domain.created', 10, function ($service, $result, $method) {
    if ($result === false) return;                        // failure has its own hook

    if ($method === 'register') Dns::applyTemplate($service['name'] ?? '');
});

Catching a failed registration

actiondomain.register_failed
RegistrarModule::create() on failure only

Runs where the provider call came back a failure, right after the previous hook.

Parameters 4
$servicearrayThe service record the provisioning was attempted for.
$optionsarrayThe parameters that were sent to the provider.
$methodstringThe method that ran.
$errorstringThe error message the module reported. It can be empty.
Return 1
voidThe return is ignored.
Listener
Hook::add('action:domain.register_failed', 10,
    function ($service, $options, $method, $error) {
        Ops::alert('domain-provision', [
            'name'   => $service['name'] ?? '',
            'method' => $method,
            'error'  => $error ?: 'the provider gave no reason',
        ]);
    });

Stopping a renewal request

gatedomain.renew
RegistrarModule::renew():144 before a paid call

Runs before the renewal request reaches the provider.

Parameters 2
$servicearrayThe service being renewed. Its end date and term are in here.
$optionsarrayThe renewal parameters: sld, tld, year.
Return 1
stringA non-empty string stops the renewal. This hook is also on the path of overnight jobs — stopping it leaves the domain unrenewed.
Listener
Hook::add('gate:domain.renew', 10, function ($service, $options) {
    // Renewing spends money where the customer already asked to cancel.
    if (Acme::cancelRequested((int) ($service['id'] ?? 0)))
        return 'A cancellation is open, so the renewal was stopped.';

    return null;
});

Learning that a renewal landed

actiondomain.renewed
Invoices::handle_renewal_domain_paid():1040 from the payment path

Runs after a paid renewal item extended the end date and the provider was updated.

Parameters 1
$servicearrayThe renewed service record. The end date is the new one.
Return 1
voidThe return is ignored.
Listener
Hook::add('action:domain.renewed', 10, function ($service) {
    ExternalDns::syncExpiry($service['name'] ?? '', $service['duedate'] ?? '');
});

Catching a failed renewal

actiondomain.renew_failed
RegistrarModule::renew() expiry at risk

Runs where the provider's renewal call came back a failure.

Parameters 3
$servicearrayThe service the renewal was attempted for.
$optionsarrayThe renewal parameters.
$errorstringThe error message the module reported; it can be empty.
Return 1
voidThe return is ignored.
Listener
Hook::add('action:domain.renew_failed', 10, function ($service, $options, $error) {
    // The customer paid and the domain did not renew: this wants a person.
    Ops::page('domain-renew-failed', $service['name'] ?? '', $error);
});

Following a transfer through

actiondomain.transfer.completed
Services::check_transfer_status():686 the service is live now

Runs after the provider reported the transfer done, the service went live and word was sent.

Parameters 1
$servicearrayThe service record read afresh after activation; its start and end dates are current.
Return 1
voidThe return is ignored.
Listener
Hook::add('action:domain.transfer.completed', 10, function ($service) {
    ExternalDns::provision($service['name'] ?? '');
});

Catching a failed transfer check

actiondomain.transfer.failed
Services::check_transfer_status():659 the check repeats

Runs where the provider's transfer status check failed, right before the error is thrown.

Parameters 1
$servicearrayThe domain service whose transfer check failed.
Return 1
voidThe return is ignored.
Listener
Hook::add('action:domain.transfer.failed', 10, function ($service) {
    // The check repeats on a schedule: alert on a streak, not on one failure.
    if (Acme::failStreak((int) ($service['id'] ?? 0)) >= 3)
        Ops::alert('domain-transfer-stuck', $service['name'] ?? '');
});

Following the transfer code being saved

actiondomain.transfer_authcode_saved
ClientDomains secret value

Runs after a customer saves the authorisation code for an incoming transfer. This is where you tell the outside system that drives the transfer.

Parameters 2
$servicearrayThe domain record.
$codestringThe saved authorisation code, in the clear. Whoever holds this code can move the domain elsewhere: keep it out of your own records and out of your logs.
Return 1
voidThe return is ignored. The code is already saved.
Listener
Hook::add('action:domain.transfer_authcode_saved', 10, function ($service, $code) {
    // Carry the fact that a code arrived, NOT the code itself.
    Acme::transferReady((int) ($service['id'] ?? 0), $service['name'] ?? '');
});

Pitfalls

The result hook is no promise of success

The register hook runs when the provider call returned, not when it succeeded. Where the second parameter is false the work did not land. Setting up DNS or telling the customer "your domain is ready" without checking treats a record that does not exist as real.

The renewal gate is also on the overnight path

Renewals do not run from an operator's hand alone: the post-payment flow and scheduled jobs pass the same gate. A condition you put there can leave a domain unrenewed with nobody noticing. Record it somewhere when you stop the gate; a silent veto is the costliest kind.

The transfer check repeats

The transfer status is asked on a schedule, and every failed check runs the failure hook again. A listener that alerts on each call produces dozens of messages for one pending transfer. Count the streak rather than reacting to a single failure.

The gate is the last stop before a paid call

The register and renew gates are the last point before money is spent. Fraud checks, quota limits and premium confirmations belong here. The same check made after the call does not bring the money back.

Cet article vous a-t-il été utile ?

Merci pour votre retour !

Besoin d'aide supplémentaire ?

Notre équipe d'assistance est disponible 24h/24 pour tout ce que vous ne trouvez pas ci-dessus.