Hover.com’s Internal API

I started out looking for a domain provider to replace Hover.com and ended up building on top of Hover’s undocumented and unsupported API. Here’s the how and why I got here.

Last month I mentioned about wanting to build domain controls into CaptainCore. My current domain provider Hover.com doesn’t have an official API so I explored alternative providers. My first pick was Namecheap which seemed like they had everything I wanted. Their API is feature rich and domains are similarly priced if not cheaper then Hover.com. I even went as far as building a workable prototype until I hit a wall with domain authorization codes.

Domain API’s rarely let you fetch auth codes!

Namecheap doesn’t allow the retrieval of domain auth code via their API. This seems like a basic functionality to me. If you’ve ever dealt with transferring domains getting an auth code quickly is the difference between a good domain provider and the bad ones that like to lock you in.

NameSilo, a promising alternative to Namecheap, has Retrieving EPP Authorization Code listed as a capability of their API. However on closer look that only triggers an email to be sent to the primary domain contact. When I asked NameSilo support they said it was a security precaution however that seems like an excuse to me. The extra step dealing with emails is time consuming and unnecessary.

Longterm I have my eyes on Cloudflare Registrar. It’s not currently an option for 2 reasons. You can only transfer in existing domains and only if your already using Cloudflare for DNS, which I’m not. I’m hoping they eventually open it up for everyone to use as I feel Cloudflare could easily become one of the best domain providers if they wanted to be.

Hover.com is better priced then their parent company’s wholesale service OpenSRS.

Hover.com is technically a retail product of Tucows. Within the Tucows family there is OpenSRS a wholesale domain company which does have a proper API. I didn’t get too far into OpenSRS before I realized that OpenSRS is more expensive then Hover. Isn’t wholesale suppose to be cheaper? This makes no sense to me but it’s true. Bulk pricing at Hover.com is cheaper then mega bulk pricing over at OpenSRS. This primarily comes down to the fact that Hover.com includes whois privacy for free while OpenSRS charges $3/domain for that functionality.

Full circle back to Hover.com.

I really like the simplicity of Hover.com’s own interface. Everything is a one click option, even fetching auth codes. Seeing as I couldn’t find a good alternative. searched around and found others who have managed to integrated directly with Hover’s internal API. The code didn’t look all that elaborate. I figured it would only take me maybe a few hours in PHP to recreate just the features that I needed. So what really is the risk?

Building something on an internal API could break at any moment or work for years to come.

Yeah so the biggest risk is you build something and then one day in completely breaks. After looking at the domain alternatives, I’m OK with that risk. Here is what looks like to work with Hover.com directly from WordPress. Start by adding your Hover.com creditntials into your wp-config.php file.

# Hover API Login
define( 'HOVERCOM_USERNAME', 'username' );
define( 'HOVERCOM_PASSWORD', 'password' );

Next we’ll need to do an initial sign in and store the authentication cookies as a WordPress transient.

$data = [ 
    'timeout' => 45,
    'headers' => [
    'Content-Type' => 'application/json; charset=utf-8'
    ],
    'body'        => json_encode( [ 
        "username" => HOVERCOM_USERNAME, 
        'password' => HOVERCOM_PASSWORD 
    ] ), 
    'method'      => 'POST', 
    'data_format' => 'body'
];

$response = wp_remote_post( "https://www.hover.com/api/login", $data );

// Save Hover.com cookies as transient login 
$cookie_data = json_encode( $response["cookies"] );
set_transient( 'captaincore_hovercom_auth', $cookie_data, HOUR_IN_SECONDS * 48 );

Before each request to Hover.com we’ll need to build up the cookies based from the WordPress transient.

$cookie_data = json_decode( get_transient( 'captaincore_hovercom_auth' ) );
$cookies     = [];
foreach ( $cookie_data as $key => $cookie ) {
    $cookies[] = new \WP_Http_Cookie( [
        'name'    => $cookie->name,
        'value'   => $cookie->value,
        'expires' => $cookie->expires,
        'path'    => $cookie->path,
        'domain'  => $cookie->domain,
    ] );
}

Now we can start talking directly to Hover.com. Here is how to fetch an authorization token.

$domain   = "my-domain-name.tld";
$response = wp_remote_get( "https://www.hover.com/api/domains/{$domain}/auth_code", [ 'cookies' => $cookies ] );
if ( is_wp_error( $response ) ) {
    return json_decode( $response->get_error_message() );
}
$response = json_decode( $response['body'] );
if ( empty( $response->auth_code ) ) {
    return "";
}
return $response->auth_code;

Locking a domain:

$domain = "my-domain-name.tld";
$data   = [ 
    'timeout' => 45,
    'headers' => [
        'Content-Type' => 'application/json; charset=utf-8',
    ],
    'body'      => json_encode( [ 
        "field" => "locked", 
        'value' => true
    ] ), 
    'method'      => 'PUT', 
    'data_format' => 'body',
    'cookies'     => $cookies,
];

$response = wp_remote_request( "https://www.hover.com/api/control_panel/domains/domain-{$domain}", $data );
if ( is_wp_error( $response ) ) {
    return json_decode( $response->get_error_message() );
}
return json_decode( $response['body'] );

Unlocking a domain:

$domain = "my-domain-name.tld";
$data   = [ 
    'timeout' => 45,
    'headers' => [
        'Content-Type' => 'application/json; charset=utf-8',
    ],
    'body'      => json_encode( [ 
        "field" => "locked", 
        'value' => false
    ] ), 
    'method'      => 'PUT', 
    'data_format' => 'body',
    'cookies'     => $cookies,
];

$response = wp_remote_request( "https://www.hover.com/api/control_panel/domains/domain-{$domain}", $data );
if ( is_wp_error( $response ) ) {
    return json_decode( $response->get_error_message() );
}
return json_decode( $response['body'] );

These examples are just a few taken from CaptainCore. If you want to see more I recommend checking out the domain class on Github. Using Chrome DevTools and watching network activity with Hover.com I was able to extract and replicate the following functionality:

  • Fetching auth code
  • Domain lock and unlock
  • Domain privacy on and off
  • Domain renew off
  • Domain update contacts

You can see that code in action in this quick screencast video or check out the announcement post for domain controls.