# Domain Profile Hooks

https://dev.wisecp.com/es/domain-profile-hooks

Saved contact profiles, default name servers and the renewal invoice — the last eight hooks of the domain area.

## Overview

Most hooks here belong to **an account** rather than to one domain. Contact profiles and default name servers are templates a customer fills once and uses on every name.

The last two sit on the money side: where a customer renews a domain by hand, a gate stands in front of the invoice and an event behind it.

## Reference

### Following a profile delete

actiondomain.whois_profile_deleted

`ClientDomains` a last snapshot

Runs after a saved contact profile was deleted.

Parameters 3

$uidintThe account id. A sub-user's action is recorded against **the owner**.

$profileIdintThe id of the deleted profile.

$profilearrayThe profile **as it was before**: `id`, `name`, `information`, `detouse`. Take what you need from here; the record is gone.

Return 1

voidThe return is ignored.

Listener PHP

```php
Hook::add('action:domain.whois_profile_deleted', 10,
    function ($uid, $profileId, $profile) {
        // The record is gone: everything you need is in the third parameter.
        Acme::dropProfileIndex($uid, $profileId);
    });
```

### Following the default profile

actiondomain.whois_profile_default_set

`ClientDomains` the record holds the OLD value

Runs after a profile was made the default.

Parameters 3

$uidintThe account id. A sub-user's action is recorded against **the owner**.

$profileIdintThe id of the profile made default.

$profilearrayThe profile record **from before the change**. Its default field still holds the **old** value, so do not read the new state from it.

Return 1

voidThe return is ignored.

Listener PHP

```php
Hook::add('action:domain.whois_profile_default_set', 10,
    function ($uid, $profileId, $profile) {
        // The new default is the SECOND parameter; the third is the old record.
        Acme::defaultProfile($uid, $profileId);
    });
```

### Changing the profile form

filterdomain.whois_profile_data

`Hook::runRefs` the key names are fixed

Runs before a saved profile is loaded into the form.

Parameters 3

$dataarrayrefThe fields going to the form: `id`, `name`, `first`, `last`, `org`, `email`, `phone`, `address`, `postal`, `city`, `country`. Keep the key names; the form fills by them.

$profilearrayThe raw database record. Fields the form leaves out (the state, a second address line) are **in here**.

$uidintThe account id. A sub-user's action is recorded against **the owner**.

Return 1

voidThe value changes **by reference**; the return is not read.

Listener PHP

```php
Hook::add('filter:domain.whois_profile_data', 10,
    function (&$data, $profile, $uid) {
        // A field the form leaves out sits in the raw record: take it from there.
        $data['state'] = $profile['information']['State'] ?? '';
    });
```

### Following the default name servers

actiondomain.default_ns_saved

`ClientDomains` account-wide

Runs after the customer's default name server set was saved. The set belongs to the whole account, **not to one name**.

Parameters 2

$uidintThe account id. A sub-user's action is recorded against **the owner**.

$nsarrayThe saved set: the `ns1` … `ns4` keys, filled ones only. At least two are present.

Return 1

voidThe return is ignored.

Listener PHP

```php
Hook::add('action:domain.default_ns_saved', 10, function ($uid, $ns) {
    // This set applies to EVERY new name on the account, not to one.
    Acme::rememberDefaults($uid, $ns);
});
```

### Following provider settings

actiondomain.registrar_settings_saved

`AdminProducts` an operator setting

Runs after a domain provider's settings were saved.

Parameters 2

$modulestringThe provider module whose settings were saved.

$settingsarrayThe saved settings. They can hold credentials; do not log them.

Return 1

voidThe return is ignored.

Listener PHP

```php
Hook::add('action:domain.registrar_settings_saved', 10, function ($module, $settings) {
    // Record that they changed, never what is inside them.
    Audit::note('registrar-settings', $module, 'updated');
});
```

### Stopping a renewal invoice

gatedomain.renewal_invoice_create

`ClientDomains` before the invoice

Runs where a customer starts a manual renewal, before the invoice is raised. Stopping it means **no invoice and no line** is created.

Parameters 5

$servicearrayThe domain service being renewed.

$yearsintThe number of years chosen.

$subtotalfloatThe subtotal without tax. In the service's own currency.

$tldstringThe extension, **without a dot and lower case**.

$uidintThe account id.

Return 1

stringA non-empty string **stops** the invoice; the text reaches the customer as the error.

Listener PHP

```php
Hook::add('gate:domain.renewal_invoice_create', 10,
    function ($service, $years, $subtotal, $tld, $uid) {
        // Some extensions take no renewal longer than ten years.
        if ($years > 10) return 'Renewals run to ten years at most.';

        return null;
    });
```

### Following a renewal invoice

actiondomain.renewal_invoice_created

`ClientDomains` the invoice is unpaid

Runs after the renewal invoice was raised. The invoice is **unpaid** here and the domain is not renewed yet.

Parameters 5

$servicearrayThe domain service being renewed.

$yearsintThe number of years chosen.

$invoiceIdintThe id of the **unpaid** invoice.

$subtotalfloatThe subtotal without tax.

$duedateFullstringThe domain's **current** due date. Not the new one: the renewal lands after payment.

Return 1

voidThe return is ignored.

Listener PHP

```php
Hook::add('action:domain.renewal_invoice_created', 10,
    function ($service, $years, $invoiceId, $subtotal, $duedateFull) {
        // The domain is NOT renewed yet; that follows the payment.
        Crm::pendingRenewal($invoiceId, $service['name'] ?? '', $years);
    });
```

### Following DNS records that were read

actiondomain.dns_records_fetched

`AdminServices` straight from the provider

Runs after the DNS records came back from the provider.

Parameters 2

$servicearrayThe domain service record.

$recordsarrayThe records that were read, normalised.

Return 1

voidThe return is ignored.

Listener PHP

```php
Hook::add('action:domain.dns_records_fetched', 10, function ($service, $records) {
    Acme::snapshotZone((int) ($service['id'] ?? 0), $records);
});
```

### Following the detail page opening

actiondomain.detail.viewed

`website/domains` on every opening

Runs when a customer opens the management page of their own domain. Access checks are already behind you: the opener is confirmed as the owner.

Parameters 2

$servicearrayThe domain record: `id`, `name`, `owner_id`, `status`, `duedate` and the rest.

$serviceIdintThe id of the domain.

Return 1

voidThe return is ignored. It runs while the page opens, so whatever you do here is added to the customer's wait. Hand a slow call to the queue.

Listener PHP

```php
Hook::add('action:domain.detail.viewed', 10, function ($service, $serviceId) {
    // Keep it light: the customer is waiting for the page.
    Acme::touchLastSeen($serviceId);
});
```

## Pitfalls

> **The default-profile record holds the OLD state**
> 
> On the default hook the third parameter is the profile record **from before the change**: its default field still holds the old value. Which profile is now the default is **the second parameter**. Reading the record and concluding "this one is not the default" comes from here.

> **These hooks belong to an account, not a domain**
> 
> Profiles and default name servers are **account-wide** templates. The hooks hand you an account id rather than a service record, so a listener reaching for domain details finds nothing. A sub-user's action is recorded against **the owner**.

> **The date on the invoice is the old due date**
> 
> The date field on the renewal invoice hook is the domain's **current** due date, not the one after renewing. The new date exists only once the **payment** lands. Using this one as "the new end" shows the customer the wrong day.

> **Provider settings carry credentials**
> 
> The settings hook can hand you the **keys and passwords** used to reach the provider. Recording that they changed is fair; recording **what is in them** is not. Log which module was updated and nothing more.

## Related Articles

- [Domain Contact Hooks](https://dev.wisecp.com/en/domain-contact-hooks)
- Invoice and Payment Hooks
- Domain Hooks
