# Domain availability

Check whether a domain is available to register and generate alternative domain suggestions.

Use these two endpoints to look up a domain before ordering it and to suggest alternatives when a name is taken.

Both endpoints authenticate with the `username` and `token` headers described in [Authentication](/guides/authentication), and both accept an `application/x-www-form-urlencoded` body.

## Check availability

Look up one or more domains built from a search term and a list of TLDs.

`POST /domains/lookup`

### Parameters

<ParamField body="searchTerm" type="text">
  The domain label to check, without a TLD (for example `hostraha-demo-42`).
</ParamField>

<ParamField body="punyCodeSearchTerm" type="text">
  The Punycode (ASCII) form of the search term. Use this when checking an internationalized domain name.
</ParamField>

<ParamField body="tldsToInclude" type="array">
  One or more TLDs to check, each sent as a repeated `tldsToInclude[]` value (for example `tldsToInclude[]=.com`). Include the leading dot.
</ParamField>

<ParamField body="isIdnDomain" type="boolean">
  Set to `true` when the lookup is for an internationalized domain name.
</ParamField>

<ParamField body="premiumEnabled" type="boolean">
  Set to `true` to include premium domains in the results.
</ParamField>

### Request

<CodeGroup>
```bash cURL
API_KEY="your-api-key"
EMAIL="you@example.com"
ENDPOINT="https://portal.hostraha.com/modules/addons/DomainsReseller/api/index.php"
TS=$(date -u +"%y-%m-%d %H")
TOKEN=$(printf '%s' "$API_KEY" \
  | openssl dgst -sha256 -hmac "$EMAIL:$TS" -hex \
  | sed 's/^.*= //' | tr -d '\n' | base64 -w0)

curl -s "$ENDPOINT/domains/lookup" \
  -H "username: $EMAIL" \
  -H "token: $TOKEN" \
  --data "searchTerm=hostraha-demo-42" \
  --data "tldsToInclude[]=.com"
```

```php PHP
<?php
$apiKey   = "your-api-key";
$email    = "you@example.com";
$endpoint = "https://portal.hostraha.com/modules/addons/DomainsReseller/api/index.php";

$token = base64_encode(hash_hmac("sha256", $apiKey, "{$email}:" . gmdate("y-m-d H")));

$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, "{$endpoint}/domains/lookup");
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query([
    "searchTerm"     => "hostraha-demo-42",
    "tldsToInclude"  => [".com"],
]));
curl_setopt($curl, CURLOPT_HTTPHEADER, [
    "username: {$email}",
    "token: {$token}",
]);
$response = curl_exec($curl);
curl_close($curl);
echo $response;
```

```python Python
from datetime import datetime, timezone

API_KEY  = "your-api-key"
EMAIL    = "you@example.com"
ENDPOINT = "https://portal.hostraha.com/modules/addons/DomainsReseller/api/index.php"

def token() -> str:
    ts = datetime.now(timezone.utc).strftime("%y-%m-%d %H")
    digest = hmac.new(f"{EMAIL}:{ts}".encode(), API_KEY.encode(), hashlib.sha256).hexdigest()
    return base64.b64encode(digest.encode()).decode()

resp = requests.post(
    f"{ENDPOINT}/domains/lookup",
    headers={"username": EMAIL, "token": token()},
    data={"searchTerm": "hostraha-demo-42", "tldsToInclude[]": ".com"},
)
print(resp.json())
```

```javascript Node.js

const API_KEY  = "your-api-key";
const EMAIL    = "you@example.com";
const ENDPOINT = "https://portal.hostraha.com/modules/addons/DomainsReseller/api/index.php";

function token() {
  const ts = new Date().toISOString().slice(2, 13).replace("T", " "); // "yy-mm-dd HH" UTC
  const digest = crypto.createHmac("sha256", `${EMAIL}:${ts}`).update(API_KEY).digest("hex");
  return Buffer.from(digest, "utf8").toString("base64");
}

const body = new URLSearchParams();
body.append("searchTerm", "hostraha-demo-42");
body.append("tldsToInclude[]", ".com");

const res = await fetch(`${ENDPOINT}/domains/lookup`, {
  method: "POST",
  headers: { username: EMAIL, token: token() },
  body,
});
console.log(await res.json());
```

```go Go
package main

	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"encoding/hex"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"
	"time"
)

const (
	apiKey   = "your-api-key"
	email    = "you@example.com"
	endpoint = "https://portal.hostraha.com/modules/addons/DomainsReseller/api/index.php"
)

func token() string {
	ts := time.Now().UTC().Format("06-01-02 15") // yy-mm-dd HH
	mac := hmac.New(sha256.New, []byte(email+":"+ts))
	mac.Write([]byte(apiKey))
	return base64.StdEncoding.EncodeToString([]byte(hex.EncodeToString(mac.Sum(nil))))
}

func main() {
	form := url.Values{}
	form.Set("searchTerm", "hostraha-demo-42")
	form.Add("tldsToInclude[]", ".com")

	req, _ := http.NewRequest("POST", endpoint+"/domains/lookup", strings.NewReader(form.Encode()))
	req.Header.Set("username", email)
	req.Header.Set("token", token())
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	body, _ := io.ReadAll(resp.Body)
	fmt.Println(string(body))
}
```
</CodeGroup>

### Response

The response is an array with one element per checked domain. A single element looks like this:

```json
{
  "domainName": "hostraha-demo-42.com",
  "idnDomainName": "hostraha-demo-42.com",
  "tld": "com",
  "tldNoDots": "com",
  "sld": "hostraha-demo-42",
  "idnSld": "hostraha-demo-42",
  "status": "available for registration",
  "legacyStatus": "available",
  "score": 1,
  "isRegistered": false,
  "isAvailable": true,
  "isValidDomain": true,
  "domainErrorMessage": "",
  "pricing": {
    "1": { "register": {}, "transfer": {}, "renew": {} },
    "2": { "register": {}, "renew": {} },
    "10": { "register": {} }
  },
  "shortestPeriod": {
    "period": 1,
    "register": {},
    "transfer": {},
    "renew": {}
  },
  "group": "",
  "minLength": 3,
  "maxLength": 63,
  "isPremium": false,
  "premiumCostPricing": []
}
```

<ResponseField name="domainName" type="string">
  The full domain that was checked.
</ResponseField>

<ResponseField name="tld" type="string">
  The TLD portion of the domain, without a leading dot.
</ResponseField>

<ResponseField name="sld" type="string">
  The second-level label of the domain.
</ResponseField>

<ResponseField name="status" type="string">
  Human-readable availability status, for example `available for registration` or `unknown`.
</ResponseField>

<ResponseField name="legacyStatus" type="string">
  Short status code: `available`, `unavailable`, or `error`.
</ResponseField>

<ResponseField name="isRegistered" type="boolean">
  `true` when the domain is already registered.
</ResponseField>

<ResponseField name="isAvailable" type="boolean">
  `true` when the domain can be ordered.
</ResponseField>

<ResponseField name="isValidDomain" type="boolean">
  `true` when the search produced a syntactically valid domain.
</ResponseField>

<ResponseField name="pricing" type="object">
  Pricing keyed by registration period (in years), each with `register`, `renew`, and where applicable `transfer` sub-objects. For full price figures, call [Domain pricing](/api-reference/pricing).
</ResponseField>

<ResponseField name="isPremium" type="boolean">
  `true` when the domain is a premium name. Premium results are only returned when `premiumEnabled` is set.
</ResponseField>

## Get domain suggestions

Return alternative domains for a search term across the configured TLDs.

`POST /domains/lookup/suggestions`

<Warning>
  `suggestionSettings` is required in practice. Send at least `suggestionSettings[maxResults]=6`. Omitting it returns `{"error":"Request validation error - Please contact administration"}`.
</Warning>

### Parameters

<ParamField body="searchTerm" type="text">
  The base label to generate suggestions from.
</ParamField>

<ParamField body="punyCodeSearchTerm" type="text">
  The Punycode form of the search term, for internationalized names.
</ParamField>

<ParamField body="tldsToInclude" type="array">
  TLDs to include in the suggestions, each sent as `tldsToInclude[]`.
</ParamField>

<ParamField body="isIdnDomain" type="boolean">
  Set to `true` for internationalized domain names.
</ParamField>

<ParamField body="premiumEnabled" type="boolean">
  Set to `true` to include premium suggestions.
</ParamField>

<ParamField body="suggestionSettings" type="array" required>
  Suggestion controls sent as nested keys, for example `suggestionSettings[maxResults]=6`. This field is required.
</ParamField>

### Request

<CodeGroup>
```bash cURL
API_KEY="your-api-key"
EMAIL="you@example.com"
ENDPOINT="https://portal.hostraha.com/modules/addons/DomainsReseller/api/index.php"
TS=$(date -u +"%y-%m-%d %H")
TOKEN=$(printf '%s' "$API_KEY" \
  | openssl dgst -sha256 -hmac "$EMAIL:$TS" -hex \
  | sed 's/^.*= //' | tr -d '\n' | base64 -w0)

curl -s "$ENDPOINT/domains/lookup/suggestions" \
  -H "username: $EMAIL" \
  -H "token: $TOKEN" \
  --data "searchTerm=hostraha" \
  --data "suggestionSettings[maxResults]=6"
```

```php PHP
<?php
$apiKey   = "your-api-key";
$email    = "you@example.com";
$endpoint = "https://portal.hostraha.com/modules/addons/DomainsReseller/api/index.php";

$token = base64_encode(hash_hmac("sha256", $apiKey, "{$email}:" . gmdate("y-m-d H")));

$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, "{$endpoint}/domains/lookup/suggestions");
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query([
    "searchTerm"         => "hostraha",
    "suggestionSettings" => ["maxResults" => 6],
]));
curl_setopt($curl, CURLOPT_HTTPHEADER, [
    "username: {$email}",
    "token: {$token}",
]);
$response = curl_exec($curl);
curl_close($curl);
echo $response;
```

```python Python
from datetime import datetime, timezone

API_KEY  = "your-api-key"
EMAIL    = "you@example.com"
ENDPOINT = "https://portal.hostraha.com/modules/addons/DomainsReseller/api/index.php"

def token() -> str:
    ts = datetime.now(timezone.utc).strftime("%y-%m-%d %H")
    digest = hmac.new(f"{EMAIL}:{ts}".encode(), API_KEY.encode(), hashlib.sha256).hexdigest()
    return base64.b64encode(digest.encode()).decode()

resp = requests.post(
    f"{ENDPOINT}/domains/lookup/suggestions",
    headers={"username": EMAIL, "token": token()},
    data={"searchTerm": "hostraha", "suggestionSettings[maxResults]": 6},
)
print(resp.json())
```

```javascript Node.js

const API_KEY  = "your-api-key";
const EMAIL    = "you@example.com";
const ENDPOINT = "https://portal.hostraha.com/modules/addons/DomainsReseller/api/index.php";

function token() {
  const ts = new Date().toISOString().slice(2, 13).replace("T", " "); // "yy-mm-dd HH" UTC
  const digest = crypto.createHmac("sha256", `${EMAIL}:${ts}`).update(API_KEY).digest("hex");
  return Buffer.from(digest, "utf8").toString("base64");
}

const body = new URLSearchParams();
body.append("searchTerm", "hostraha");
body.append("suggestionSettings[maxResults]", "6");

const res = await fetch(`${ENDPOINT}/domains/lookup/suggestions`, {
  method: "POST",
  headers: { username: EMAIL, token: token() },
  body,
});
console.log(await res.json());
```

```go Go
package main

	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"encoding/hex"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"
	"time"
)

const (
	apiKey   = "your-api-key"
	email    = "you@example.com"
	endpoint = "https://portal.hostraha.com/modules/addons/DomainsReseller/api/index.php"
)

func token() string {
	ts := time.Now().UTC().Format("06-01-02 15") // yy-mm-dd HH
	mac := hmac.New(sha256.New, []byte(email+":"+ts))
	mac.Write([]byte(apiKey))
	return base64.StdEncoding.EncodeToString([]byte(hex.EncodeToString(mac.Sum(nil))))
}

func main() {
	form := url.Values{}
	form.Set("searchTerm", "hostraha")
	form.Set("suggestionSettings[maxResults]", "6")

	req, _ := http.NewRequest("POST", endpoint+"/domains/lookup/suggestions", strings.NewReader(form.Encode()))
	req.Header.Set("username", email)
	req.Header.Set("token", token())
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	body, _ := io.ReadAll(resp.Body)
	fmt.Println(string(body))
}
```
</CodeGroup>

### Response

The response is an array of suggested domains. Each element uses the same shape as a lookup result. One element:

```json
{
  "domainName": "hostraha.de",
  "idnDomainName": "hostraha.de",
  "tld": "de",
  "tldNoDots": "de",
  "sld": "hostraha",
  "idnSld": "hostraha",
  "status": "unknown",
  "legacyStatus": "error",
  "score": 1,
  "isRegistered": false,
  "isAvailable": false,
  "isValidDomain": true,
  "domainErrorMessage": "",
  "pricing": {
    "1": { "register": {}, "transfer": {}, "renew": {} }
  },
  "shortestPeriod": {
    "period": 1,
    "register": {},
    "transfer": {},
    "renew": {}
  },
  "group": "",
  "minLength": 3,
  "maxLength": 63,
  "isPremium": false,
  "premiumCostPricing": []
}
```

The fields match [Check availability](#check-availability). Use `isAvailable` and `legacyStatus` to filter the suggestions you present.
