# DNA Rest API — full reseller integration guide
---
# Introduction
> What the DNA Rest API does, its base URL and versioning, the test environment, and four decisions to make before you write any code.
The DNA Rest API lets you register and manage domain names, contacts, DNS, SSL certificates and hosting from your own system. Everything is JSON over HTTPS. There is no SDK to install — any HTTP client will do.
## Base URL and versioning
```text
https://api.domainresellerapi.com/api/v1/...
```
The version is part of the path. `v1` is the current version. When a future version arrives, `v1` keeps working — we do not change the meaning of an existing endpoint or error code.
## Test environment
Your reseller panel issues a separate **test API key** alongside your live key. Use it to build and test against the operational test environment, where registry operations are simulated and your balance is not charged.
| | Live | Test |
| --- | --- | --- |
| Base URL | `https://api.domainresellerapi.com` | `https://ote.domainresellerapi.com` |
| `X-API-KEY` | Your API key | Your **test** API key |
| `__reseller` | Your reseller ID | The **same** reseller ID |
Paths and request formats are the same in both, so switching is a configuration change. Each key works only at its own address: the test key sent to the live URL, or the live key sent to the test URL, gets `Unauthorized! Invalid API Key.`
Not every TLD exists in the test environment. The catalogue field `availableInTestEnvironment` tells you which ones do — see the [TLD catalogue](https://www.domainnameapi.com/docs/catalogue/).
## Before you write any code
1. **Fetch the TLD catalogue once** (`GET /api/v1/products/tlds`) and cache it. It answers "how many years can I sell this for", "does it support privacy / DNSSEC / transfer", "which extra fields are required" and "what does it cost" — in one free call. Most integration bugs come from guessing these instead of reading them.
2. **Decide how you will store handle codes.** Contacts are addressed by a handle code. If you plan to register more than a handful of domains, create contacts once and reuse their handles.
3. **Plan for asynchronous outcomes.** A successful call does not always mean a finished operation. Transfers wait for approval, SSL waits for validation, hosting provisions in the background, and some registrations wait for documents. Each section says what to poll.
4. **Log the correlation ID and the balance transaction ID** for every paid operation. These two make support investigations quick.
---
# Authentication
> The two headers every request needs (X-API-KEY and __reseller), what authentication failures look like, and what your key can reach.
Every request needs **two headers**. Both are mandatory on every call.
| Header | Required | What to send |
| --- | --- | --- |
| `X-API-KEY` | required | Your API key. Find it in your reseller panel under API settings. |
| `__reseller` | required | Your reseller ID (a GUID). Also shown in your reseller panel next to the API key. |
| `Content-Type` | for writes | `application/json` on POST, PUT and DELETE requests that carry a body. |
| `X-Correlation-ID` | recommended | Any unique string you generate per request. We log it. Quoting it in a support ticket makes the request findable in seconds instead of minutes. |
**A complete request**
```bash
curl -X POST https://api.domainresellerapi.com/api/v1/domains/search \
-H 'X-API-KEY: 8f2c41d7a9e5b3104c6f8a2d9b7e1c35' \
-H '__reseller: 7f3c1a28-9e4b-4c51-b1d2-0a6e5f8c3d94' \
-H 'X-Correlation-ID: my-app-2026-10-30-000142' \
-H 'Content-Type: application/json' \
-d '{"domainName":"apiname.com"}'
```
:::caution[Keep your API key secret]
The key authenticates every action on your account, including purchases that debit your balance. Never put it in browser-side JavaScript, a mobile app bundle, or a public repository. Call the API from your server only. If you think the key has leaked, regenerate it in your reseller panel immediately — the old key stops working the moment you do.
:::
## Authentication failures
These come back as **plain text**, not JSON, with HTTP 401.
| Body | What went wrong |
| --- | --- |
| `Unauthorized! API Key is missing.` | No `X-API-KEY` header. Check your client is actually sending it — some HTTP libraries drop headers on redirect. |
| `Unauthorized! ResellerId is missing.` | No `__reseller` header. Note the two leading underscores. |
| `Unauthorized! Invalid API Key.` | The key does not match the reseller ID. The usual cause is sending the test key to the live address, or the live key to the test address — see [Test environment](https://www.domainnameapi.com/docs/getting-started/#test-environment). |
| `Unauthorized! You do not have authorisation for this operation.` | The account is a sub-reseller. Only top-level reseller accounts can use this API. Your parent reseller must call it on your behalf. |
## What your key can reach
There are no scopes or permissions to configure. Your reseller ID defines what you can see: you can act on your own domains, contacts, certificates and hostings and nothing else. Asking about somebody else's domain does not return "forbidden" — it returns **not found**, because from your key's point of view it does not exist.
---
# Requests and responses
> How to format requests, what each HTTP status means, and why you should branch on the error code rather than the status.
## Request format
- **POST, PUT, DELETE** take a JSON body, with two exceptions noted in their sections (zone and some DNSSEC calls also take query-string parameters).
- **GET** takes query-string parameters.
- Field names are **camelCase**: `domainName`, `authCode`, `nameServers`.
- Domain names may be sent in Unicode or in punycode. `örnek.com` and `xn--rnek-hra.com` are the same domain to us.
- Dates are ISO 8601.
- Do not send fields you do not mean to set. For several fields, "absent" and "empty" mean different things — the field reference says so where it matters.
## Response format
A successful call returns the endpoint's JSON object. Some endpoints have nothing to return and answer with **HTTP 204 and an empty body** — that is success, not a problem. Each endpoint below states which it is.
| Status | Meaning |
| --- | --- |
| 200 | Success, with a body. |
| 202 | Accepted — the work continues in the background. Only hosting creation returns this. |
| 204 | Success, no body. |
| 400 | The input was rejected — a malformed field, an invalid domain name or auth code. Field validation errors carry `validationErrors`. |
| 401 | Authentication problem. Plain text body. |
| 402 | Insufficient balance (`Dna.DomainService:Deposit:10001`). |
| 403 | A business rule refused the operation. Most error codes arrive with this status. |
| 404 | The domain, host, DNS record or forward does not exist or is not yours (`Dna.DomainService:Domain:10007` and similar) — **or** the URL itself is wrong. |
| 409 | Conflict: the domain already exists or is already yours, a host already exists, a transfer lock is set or a transfer is already pending. |
| 422 | Domain name too short or too long. |
| 429 | More requests per second than your limit allows. See [Rate limits](https://www.domainnameapi.com/docs/getting-started/rate-limits/). |
| 500 | Something broke on our side. Safe to retry once after a short pause; if it persists, open a ticket with your correlation ID. |
:::note[Branch on the error code, not the status]
Several error codes share a status, so the status alone does not tell you what happened. Read `error.code` from the body. A **404 with no error code** means the URL was wrong; a 404 with `Dna.DomainService:Domain:10007` means the domain does not exist or is not yours.
:::
---
# Error format
> The envelope every error uses, how validation and insufficient-balance errors look, and how to read an error code.
Every error carries the same envelope:
```json
{
"error": {
"code": "Dna.DomainService:Domain:10007",
"message": "The domain name you requested could not be found. Please check and try again.",
"details": "apiname.com was not found"
}
}
```
| Field | Use it for |
| --- | --- |
| `code` | **Your logic.** Stable and contractual — it does not change. |
| `message` | **Showing the user.** Localised, and we reword it over time. |
| `details` | **Your logs.** Says which domain, which field, which limit. |
:::danger[Branch on `code`, never on `message`]
Messages are translated and get reworded for clarity. Code that matches on message text will break without warning. Match on `code`, log `details`, show `message`.
:::
## Validation errors
When a request fails field validation, the envelope gains a `validationErrors` array telling you exactly which fields were wrong. The `members` entry is prefixed with the contact role when the problem is in a contact, so you can map it straight onto your form.
```json
{
"error": {
"code": "Dna.DomainService:ValidationError",
"message": "Validation failed. Please check the provided information.",
"validationErrors": [
{
"message": "Registrant Country is required.",
"members": ["Registrant.Country"]
},
{
"message": "Admin PhoneCountryCode must contain only digits (e.g., 90). Please do not use the '+' sign.",
"members": ["Admin.PhoneCountryCode"]
}
]
}
}
```
## Insufficient balance
Balance errors add a `data` object so you can tell the user exactly how much to top up, without a second API call.
```json
{
"error": {
"code": "Dna.DomainService:Deposit:10001",
"message": "Insufficient balance",
"details": "Your balance is insufficient to complete this transaction.",
"data": {
"tryBalance": 120.50,
"usdBalance": 3.10,
"requiredAmount": 11.40,
"requiredAmountCurrency": "USD"
}
}
}
```
## Reading error codes
Codes are structured as `Service:Area:Number`. The area tells you where to look first:
- `…:Domain:` — domain operations
- `…:Contact:` — contact data
- `…:Contact:Verification:` — e-mail / ownership verification
- `…:Dns:` — name servers and glue
- `…:Dnssec:` — DNSSEC
- `…:TldAttribute:` — TLD-specific extra fields
- `…:Deposit:` — balance
- `…:Reseller:` — account state
- `ZoneClient:` — DNS records
- `Ssl:` — certificates
The full catalogue is in [Error codes](https://www.domainnameapi.com/docs/reference/errors/).
:::caution[A handful of codes carry two meanings]
For a small number of codes the same code string is used for two different conditions. The important one is `Dna.DomainService:Domain:10058`, which can mean either "the domain name mixes multiple alphabets" (your input was rejected, nothing happened) or "the domain was created at the registry but we could not record it" (**do not retry**). Where this applies the error reference says so — for those specific codes, read `message` as well as `code`.
:::
---
# Rate limits
> The two limits on your API key: a per-second cap that answers HTTP 429, and a per-minute points budget that slows responses down.
Two independent limits apply to your API key. The first caps **bursts** and rejects; the second watches **sustained volume** and slows you down.
| Limit | Measured over | What happens when you exceed it |
| --- | --- | --- |
| Request rate | Each second | HTTP **429**, empty body, `Retry-After` header |
| Points quota | Minutes, per area | The response is **delayed** by up to 5 seconds, never rejected |
## Requests per second
Counted per API key, in one-second windows:
| Requests | Limit |
| --- | --- |
| All endpoints together | **5 per second** |
| `POST /api/v1/domains/search` and `POST /api/v1/domains/bulk-search` | **2 per second**, within the 5 |
| `/api/v1/domains/zones` and everything under it | **20 per second**, a budget of its own that does not use up the 5 |
| `GET /api/v1/domains/info` and `GET /api/v1/products/tlds` | No per-second limit |
A request over the limit gets **HTTP 429** with an empty body and a `Retry-After` header: the whole seconds to wait, at least `1`. Wait that long, then retry. A rejected request costs no quota points.
:::tip[Pace instead of retrying]
Five requests per second is plenty for an integration that works through a queue. If you loop over a list of domains, send them one after another, not all at once, and use `bulk-search` (up to 30 domains per call) instead of one `search` per domain.
:::
## Points quota
On top of the per-second cap, a points budget decides whether your requests are answered at full speed or deliberately slowed down. Nothing is rejected by this limit.
- Each request costs **points**: **1 point** for a lookup — `POST /domains/search`, `GET /domains/info`, `GET /products/info` — and **10 points** for everything else.
- Points are tracked **separately per area** — domains (including name servers, DNSSEC and DNS records), contacts, SSL, hosting, products, orders, balance. Heavy domain searching does not slow your SSL calls.
- Your points **decay continuously, by 20% per minute**.
- Below **200 points** nothing happens at all.
- Above 200, responses are delayed — starting at half a second and rising to a ceiling of **5 seconds**.
In round numbers, per area: from a standing start you can make about **20 write operations or 200 lookups** before any slowdown begins. At a steady pace, about **4 write operations or 45 lookups per minute** stay at full speed indefinitely.
**Every response tells you where you stand**
| Header | Meaning |
| --- | --- |
| `X-Quota-Scope` | Which area this request counted against. |
| `X-Quota-Cost` | What it cost — `1` or `10`. |
| `X-Quota-Used` | Your current total in that area. |
| `X-Quota-Limit` | The threshold where slowing begins (`200`). |
| `X-Quota-Delay` | Seconds of delay applied to this request. `0` means full speed. |
| `X-Quota-Reset` | Seconds until decay brings you back under the threshold. |
:::caution[If `X-Quota-Delay` is not zero, slow down — do not retry harder]
Retrying adds more points and deepens the delay. Watch the header and pace yourself. Two specifics worth knowing:
- `bulk-search` costs **10 points, not 1** — it is a bulk operation, not a lookup. Thirty domains in one `bulk-search` still costs far less than thirty separate `search` calls, so prefer it for lists.
- The TLD catalogue (`/products/tlds`) is **free** — it never costs points. Cache it on your side anyway; it changes rarely.
:::
:::note[Set your client timeout above the delay]
A delayed response is still a successful response. Give your HTTP client a timeout comfortably above 5 seconds plus the time the operation itself takes, or a slowed-down request will look like a failure to your code and tempt it to retry.
:::
---
# Contacts
> The four contact roles, handle codes, and the field-by-field rules for contact data, including phone number format.
A contact is the person or organisation behind a domain name. Every domain has four contact roles, and registries publish some of this data. Contacts are addressed by a **handle code** — a short identifier you can reuse across many domains.
## The four roles
| Value | Name | Who this is |
| --- | --- | --- |
| 1 | `Registrant` | **The legal owner of the domain.** The most important role — ownership disputes and transfer approvals go to this contact. |
| 0 | `Admin` | The administrative contact, authorised to make changes. |
| 3 | `Tech` | The technical contact, for DNS and operational matters. |
| 2 | `Billing` | The billing contact. |
:::note[You can use one contact for all four roles]
Most resellers do. The registry requires four roles to be filled, not four different people. Where you send contact details inline, we fill the remaining roles for you — see [Registering with contact details](https://www.domainnameapi.com/docs/domains/register/#registering-with-contact-details).
:::
## Handle codes
A handle code looks like this:
```text
D-174829301847
```
- Always starts with `D-`.
- You will also see a role-scoped form such as `D-R-1748293018`. We create these automatically when one domain's contact has to diverge from the others. Treat any handle as an opaque string — do not parse it.
- Maximum 20 characters.
- **A handle belongs to your account.** Another reseller's handle is invisible to you.
- A handle can back all four roles on one domain, and can be shared across many domains.
:::caution[Sharing a handle across domains has consequences]
Updating a shared handle updates the contact on **every** domain using it, and each of those domains goes to its registry. That is usually what you want — one address change, everywhere. But if you need one domain to differ, give it its own handle instead of editing the shared one.
:::
## Contact field reference
These rules apply everywhere you send a contact — creating one, updating one, or registering a domain with contact details inline. Read this once; the endpoints below will not repeat it.
| Field | Required | Max | Rules and what we do to your value |
| --- | --- | --- | --- |
| `firstName` | required | 80 | Letters, spaces, `.` and `,` only. **Anything else is removed silently**, and what remains must be at least 2 characters. `"John99"` becomes `"John"`; `"99"` becomes empty and is rejected. |
| `lastName` | required | 80 | Same rule as `firstName`. |
| `companyName` | optional | 256 | Letters, digits, spaces and `.,'&()/-` survive; other characters are removed. **If you leave it empty we set it to "firstName lastName".** For an individual registrant, simply omit it. |
| `eMail` | required | 256 | Must be a deliverable address — see the warning below. |
| `address` | required | 256 | Letters, digits, spaces and `.,:/#()-` survive. Line breaks, tabs and runs of spaces collapse to one space. Minimum 4 characters. Send the street address on one line. |
| `city` | required | 80 | Letters, digits and spaces only. Minimum 2. |
| `state` | required | 80 | Same rule as `city`. **If your country has no states, repeat the city.** It cannot be empty. |
| `postalCode` | required | 15 | Letters, digits and spaces only. Minimum 2. |
| `country` | required | 2 | **ISO 3166-1 alpha-2, uppercase.** `"TR"`, `"US"`, `"GB"`, `"DE"`. Not the country name, not a three-letter code. See the warning below. |
| `phoneCountryCode` | required | 3 | **Digits only. No `+` sign.** `"90"` is correct; `"+90"` is rejected. |
| `phone` | required | 16 | Minimum 5 digits. We normalise it — see below. |
| `fax, faxCountryCode` | optional | 15 / 3 | Digits only. If either is invalid we clear both rather than failing your request. Omit them entirely unless you have a real fax number. |
| `discloseFlag` | optional | — | **Omit it.** Leaving it out means "do not touch WHOIS disclosure". Only send `true`/`false` if you are deliberately setting disclosure at creation time. It is ignored when updating a contact — use domain privacy instead. |
| `contactType` | varies | — | Required in some places, absent in others. Each endpoint states it. |
:::caution[Always validate `country` before you send it]
The `country` field must be a valid ISO 3166-1 alpha-2 code. A value we do not recognise is **not guaranteed to be stored as you submitted it**, and an incorrect country reaches the registry's public records. Validate against the ISO2 list in your own code — do not rely on the API to reject a bad value here. Common mistakes: `"Turkey"`, `"TUR"`, `"turkey"`, `"UK"` (the correct code for the United Kingdom is `GB`).
:::
:::danger[The e-mail address must be real and monitored]
This is the single most consequential field in the whole API. For most domain extensions, the registrant's e-mail address has to be **verified by clicking a link**. If nobody clicks it within **15 days**, the domain is **suspended and stops resolving**. Never use a placeholder, a no-reply address, or an address the customer does not read. See [Contact verification](https://www.domainnameapi.com/docs/contacts/verification/).
:::
### Phone number format
We accept most formats and normalise them. The steps, in order: strip everything that is not a digit; remove the country code if the number repeats it; remove a single leading zero.
All four of these arrive as country code `90`, number `5321234567`:
```json
"+90 (532) 123 45 67"
"0532 123 45 67"
"905321234567"
"5321234567"
```
The registry receives `+90.5321234567`. The one thing you must get right is keeping the `+` out of `phoneCountryCode`.
---
# Create, read and update contacts
> Create a contact, read it together with its open verifications, and update it on every domain that uses it.
## POST /api/v1/contacts
Creates a contact and returns its handle code. Nothing is sent to any registry yet — that happens when you use the handle to register or update a domain.
**Request**
A single `contact` object. All fields follow the [contact field reference](https://www.domainnameapi.com/docs/contacts/#contact-field-reference). There is no `contactType` here — the role is decided when you use the handle.
```json
{
"contact": {
"firstName": "Ahmet",
"lastName": "Yilmaz",
"companyName": "Apiname Ltd",
"eMail": "ahmet@apiname.com",
"address": "Ataturk Caddesi No 12 Kat 3",
"city": "Istanbul",
"state": "Istanbul",
"postalCode": "34100",
"country": "TR",
"phoneCountryCode": "90",
"phone": "5321234567"
}
}
```
**Response — 200**
```json
{
"handle": "D-174829301847",
"isSuccess": true,
"operationMessage": "Operation completed successfully"
}
```
:::tip[What to do with it]
**Store `handle` against your customer record.** This is the only time it is returned for a newly created contact, and it is what you send to `POST /api/v1/domains/register`. Losing it means creating a duplicate contact.
:::
**Errors**
| Code | Meaning and fix |
| --- | --- |
| (validation) | HTTP 400 with `validationErrors`. Read `members` to see which field. Typical: a required field missing, a name that became empty after invalid characters were removed, or a `+` in `phoneCountryCode`. |
| `Dna.DomainService:Contact:10011` | Invalid e-mail address. |
| `Dna.DomainService:Contact:10013` | Phone country code contains something other than digits. |
| `Dna.DomainService:Contact:10014` | Phone number is not usable after normalisation. |
## GET /api/v1/contacts/{handleCode}
Reads a contact in your account, together with any verification process currently open on it.
**Request**
```http
GET /api/v1/contacts/D-174829301847
```
**Response — 200**
```json
{
"contact": {
"handle": "D-174829301847",
"contactType": "Registrant",
"firstName": "Ahmet",
"lastName": "Yilmaz",
"companyName": "Apiname Ltd",
"eMail": "ahmet@apiname.com",
"address": "Ataturk Caddesi No 12 Kat 3",
"city": "Istanbul",
"state": "Istanbul",
"postalCode": "34100",
"country": "TR",
"phoneCountryCode": "90",
"phone": "5321234567"
},
"verificationObjects": [
{
"fieldType": "Email",
"fieldValue": "ahmet@apiname.com",
"ownerName": "Ahmet Yilmaz",
"operationStatus": "VerificationPending",
"isUserVerified": false,
"tokenExpireDate": "2026-11-14T10:22:31",
"resendDate": "2026-10-30T10:23:31",
"attemptNumber": 1,
"resendRetryCount": 100
}
]
}
```
:::tip[What to do with it]
Check `verificationObjects` first. An **empty array means nothing is outstanding**. If an entry has `isUserVerified: false`, the `tokenExpireDate` is **the date the domain will be suspended** — show it to your customer and chase them before it arrives.
:::
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `Dna.DomainService:Contact:Verification:10006` | Handle not found in your account. Check for a typo, and that the handle is yours. |
## PUT /api/v1/contacts/{handleCode}
Updates a contact. This is not a local edit — the change is pushed to the registry of **every domain** using this handle, and the response reports what happened to each one.
:::caution[This is a replace, not a patch]
Send the **complete** contact. Any field you leave out is not preserved. Read the contact first, change what you need, send it all back.
:::
**Request**
```http
PUT /api/v1/contacts/D-174829301847
{
"contact": {
"firstName": "Ahmet",
"lastName": "Yilmaz",
"companyName": "Apiname Ltd",
"eMail": "ahmet@apiname.com",
"address": "Bagdat Caddesi No 45 Daire 7",
"city": "Istanbul",
"state": "Istanbul",
"postalCode": "34728",
"country": "TR",
"phoneCountryCode": "90",
"phone": "5329876543"
}
}
```
**Response — 200**
```json
{
"handle": "D-174829301847",
"contactUpdateSuccess": true,
"stats": {
"totalDomainCount": 3,
"successCount": 2,
"pendingDocumentCount": 0,
"failedCount": 0,
"splitCount": 1
},
"affectedDomains": [
{
"domainName": "apiname.com",
"status": "Success",
"newHandle": null,
"reason": "Updated",
"message": "Handle update completed"
},
{
"domainName": "apiname.net",
"status": "Success",
"newHandle": null,
"reason": "RddsPending",
"message": "Handle update completed, RDDS verification started"
},
{
"domainName": "apiname.com.tr",
"status": "Success",
"newHandle": "D-R-1748293018",
"reason": "SplitNotSubjectToRdds",
"message": "Moved to a new handle, not subject to RDDS verification"
}
]
}
```
**Reading the response**
| Field | Meaning |
| --- | --- |
| `contactUpdateSuccess` | Whether the contact record itself was saved. |
| `stats.totalDomainCount` | How many domains use this handle. |
| `stats.successCount` | Updated at the registry. |
| `stats.pendingDocumentCount` | The registry wants documents before accepting the change. |
| `stats.failedCount` | The registry rejected the change. |
| `stats.splitCount` | Domains moved onto a **new handle** instead of being updated. |
| `affectedDomains[].reason` | `Updated` · `RddsPending` (verification started) · `SplitForDocument` · `SplitNotSubjectToRdds` · `Failed` |
| `affectedDomains[].newHandle` | Set when that domain was moved to a new handle. `null` otherwise. |
:::danger[Always read `newHandle`]
When domains using one handle cannot all take the same change, we move the ones that cannot onto a **newly created handle** rather than leaving your records inconsistent. That domain is **no longer reachable through the handle you just updated**.
Loop over `affectedDomains` and, for every entry where `newHandle` is not null, store the new handle against that domain in your database. Skipping this is the most common integration bug in this endpoint.
:::
**Does the handle code change?**
**No.** The handle string stays the same — only its contents change. Your stored handle keeps working for future registrations. The two exceptions:
- A domain was split off (`newHandle` is set). For that domain the handle changed; your original handle is still valid for everything else.
- An identity change is awaiting verification. The contact is updated but the registry change is held until the owner confirms. A domain you register with the handle meanwhile uses the new details and starts its own verification.
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `Dna.DomainService:Domain:10038` | Handle not found. |
| `Dna.DomainService:Contact:10012` | Invalid country — not a recognised ISO2 code. |
| `Dna.DomainService:Contact:10020` | The handle is linked to at least one domain that is not yours. Nothing was changed. |
| `Dna.DomainService:Contact:Verification:10008` | An ownership-change verification is already open on this contact. Wait for it to finish, or have the owner reject it, before changing identity again. |
| `Dna.DomainService:Contact:Verification:10010` | **You are changing the name, surname or company, and the contact's e-mail is not verified.** Verify the e-mail first — see the sequence below. |
| `Dna.DomainService:Contact:10026` | The handle is used by several domains in a way we cannot split safely. Open a support ticket. |
| `Dna.DomainService:Epp:10001` | The registry rejected the change. Per-domain detail is in `affectedDomains`. |
---
# Contact verification
> Why an unverified contact e-mail suspends a domain after 15 days, how to check and resend verification, and how to change details mid-verification.
This is the part of the API that most often surprises new integrators. Read it before you register your first domain.
For most domain extensions, registry rules require the registrant's contact data to be verified. There are two independent processes:
| Type | What it verifies | Who gets the e-mail | Started by |
| --- | --- | --- | --- |
| `Email` | That the contact's e-mail address is real and reachable. | The contact's own address. | Creating a domain or contact; changing an e-mail address. |
| `Owner` | That the current owner consents to an ownership change. | The **previous** owner's address. | Changing `firstName`, `lastName` or `companyName` on a contact behind an in-scope domain. |
## Timings you need to design around
| Setting | Value |
| --- | --- |
| Verification link validity | **15 days** from issue |
| Automatic reminder e-mails | every **3 days** while pending |
| Minimum gap between manual re-sends | **1 minute** |
| Maximum re-sends | **100** |
## What happens if nobody verifies
1. You register a domain. It becomes active straight away — **verification is not a precondition for registration**.
2. We open a verification process for each distinct contact e-mail on the domain. One address used for all four roles produces **one** verification, not four.
3. The contact receives a link valid for 15 days, plus a reminder every 3 days.
4. If nobody clicks within 15 days, the domain is **suspended**: its status becomes `PendingHold`, the reason becomes `RddsVerificationPending`, and its name servers are switched to our suspension servers — **the website and e-mail stop working**.
5. When the contact finally verifies, the domain is reactivated automatically. This is not instant — it is handled by a background process shortly afterwards.
:::danger[The practical consequence]
You can register a domain with an unverified contact and it will work. **Fifteen days later it will go dark** unless the registrant clicked the link. If you register domains on behalf of customers, build the verification state into your dashboard and chase it — do not discover it when the customer calls to say their site is down.
:::
## Which extensions this applies to
Verification applies to most generic extensions (`.com`, `.net`, `.org` and the newer gTLDs). A number of country-code extensions are outside its scope and never enter the process.
The practical test: call `GET /api/v1/contacts/{handleCode}`. If `verificationObjects` comes back empty and the contact is not already verified, that handle's domains are outside scope.
## Renewing a suspended domain
A domain suspended for unverified contact data **can still be renewed** — do not let it expire while you chase the verification. Renewing does not lift the suspension; only verification does.
## Changing an e-mail address mid-verification
Changing the address does not reset the clock to zero and does not avoid verification. The new address joins the same verification chain. If the new address is **already verified** from another contact, the chain inherits that verification and suspended domains become eligible for reactivation. The number of address changes within one chain is capped; past the limit only support can intervene.
## GET /api/v1/contacts/verification/check
Current verification state for a handle. This is the endpoint to poll from your dashboard.
**Request**
```http
GET /api/v1/contacts/verification/check?handleCode=D-174829301847
```
**Response — 200**
```json
{
"results": [
{
"fieldType": "Email",
"fieldValue": "ahmet@apiname.com",
"ownerName": "Ahmet Yilmaz",
"operationStatus": "VerificationPending",
"isUserVerified": false,
"userVerificationDate": null,
"tokenExpireDate": "2026-11-14T10:22:31",
"resendDate": "2026-10-30T10:23:31",
"resendRetryCount": 100,
"attemptNumber": 1,
"lastAttemptDate": "2026-10-30T10:22:31",
"createdDate": "2026-10-30T10:22:31"
}
]
}
```
**Status values**
| Value | Name | Meaning |
| --- | --- | --- |
| 0 | `None` | Just created. |
| 1 | `VerificationPending` | Waiting for the user. Re-send is allowed. |
| 2 | `Completed` | Finished. |
| 3 | `TokenExpired` | The 15 days ran out. Re-sending issues a fresh link and a fresh 15-day window. |
| 4 | `Cancelled` | Abandoned. |
| 5 | `ResendLimitReached` | Allowance exhausted. Open a support ticket. |
| 6 | `MailChanged` | Superseded because the address changed; the chain continues on the new address. |
| 7 | `OperationPending` | The user responded; we are applying the result. |
:::note[This endpoint errors when there is nothing to report]
Unlike `GET /contacts/{handleCode}`, which returns an empty array, this endpoint returns `Dna.DomainService:Contact:Verification:10005` when no verification exists. That is not a failure — it usually means the handle's extensions are outside verification scope, or verification completed some time ago. Treat it as "nothing pending".
:::
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `Dna.DomainService:Contact:10019` | `handleCode` is empty. |
| `Dna.DomainService:Contact:Verification:10006` | Handle not found in your account. |
| `Dna.DomainService:Contact:Verification:10005` | No verification record. See the note above. |
## POST /api/v1/contacts/verification/request
Re-sends the verification e-mail. Use it when the customer says they never received it, or when the link has expired.
**Request**
```json
{
"handleCode": "D-174829301847"
}
```
**Response — 204, no body**
:::tip[What this does]
If both an e-mail and an ownership verification are open, **both** notices go out in one call. If the link had already expired, a **new link with a fresh 15-day window** is issued — this is how you revive a lapsed verification without recreating anything.
Recipients differ: the e-mail verification goes to the contact's address; the ownership verification goes to the **previous** owner's address.
:::
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `Dna.DomainService:Contact:Verification:10002` | You are inside the 1-minute cooldown. The message tells you how many seconds to wait. |
| `Dna.DomainService:Contact:Verification:10003` | Already verified — nothing to send. Treat as success. |
| `Dna.DomainService:Contact:Verification:10001` | Send limit reached. Open a support ticket; the customer most likely has a mail-delivery problem. |
| `Dna.DomainService:Contact:Verification:10009` | This verification is already finalised (completed, cancelled or superseded) and cannot be re-sent. |
| `Dna.DomainService:Contact:Verification:10005` | No verification record to re-send against. |
| `Dna.DomainService:Contact:Verification:10004` | The e-mail could not be sent. Try again shortly. |
| `Dna.DomainService:Contact:Verification:10006` | Handle not found in your account. |
## Changing an owner's name when the e-mail is unverified
You cannot change `firstName`, `lastName` or `companyName` while the contact's e-mail is unverified — the request fails with `Dna.DomainService:Contact:Verification:10010`. The reason is that the ownership-change notice is sent to that very address, so it has to be known to work first.
The working sequence:
1. `POST /api/v1/contacts/verification/request` — send the e-mail verification.
2. The customer clicks the link.
3. `GET /api/v1/contacts/verification/check` until `isUserVerified` is `true` for `fieldType: "Email"`.
4. `PUT /api/v1/contacts/{handleCode}` with the new name. This now starts an **ownership** verification, sent to the current owner.
---
# Domains
> Rules shared by every domain call: name format, period, name servers, extra registry fields (tldAttributes), the trustee service and how paid operations work.
Everything you can do to a domain name: check availability, register, renew, transfer, and manage it afterwards. This is the largest section — the shared rules come first, then the endpoints grouped by task.
## Rules that apply to every domain call
### Domain name format
We accept Unicode and punycode, normalise to lowercase, and validate against the public suffix list so that `apiname.co.uk` and `apiname.com.tr` are understood as whole domains rather than subdomains.
A name is rejected when:
- it contains no dot, or has an empty label (`apiname..com`);
- any label starts or ends with a hyphen (`-apiname.com`, `apiname-.com`);
- it is longer than 63 characters;
- it **mixes alphabets within one label** — see below.
:::caution[Mixed-alphabet names are rejected]
A single label may not combine Latin, Cyrillic, Greek, Arabic, Hebrew, Thai or Lao letters. Registries refuse these as look-alike (homograph) attacks, so we catch them first. The classic case is a Cyrillic `а` (U+0430) hidden among Latin letters in something like `fаcebook.com` — visually identical, a different domain entirely.
Chinese, Japanese and Korean scripts count as one family and may be combined with each other, but not with Latin. Digits and hyphens are neutral. Turkish characters (ç ö ü ğ ş ı İ) are Latin, so they never cause this. Sending the punycode form does not bypass the check — we decode it first.
Error: `Dna.DomainService:Domain:10058`, message "Domain name mixes multiple scripts". Note that this code is also used for a completely different, far more serious condition — see [Error codes](https://www.domainnameapi.com/docs/reference/errors/).
:::
### The `period` field
Registration, renewal and transfer term, in **years**.
- Valid range is 1–10, but **the real constraint is per TLD**. The catalogue's `registrationPeriods` and `renewalPeriods` arrays list the exact terms you may send. A registration outside `registrationPeriods` gives `Dna.DomainService:Domain:10023`; a renewal outside `renewalPeriods` gives `Dna.DomainService:Domain:10002`.
- On renewal, `0` is treated as `1`.
- **Premium domains accept `period: 1` only.** Registry premium fees are quoted a year at a time. Anything higher is rejected with `Dna.DomainService:Domain:10071`.
### The `nameServers` field
Required when registering. At least one entry; the per-TLD minimum and maximum are enforced (usually 2–13). To use our own DNS — which is what makes the [DNS records API](https://www.domainnameapi.com/docs/dns-records/) work — send:
```json
["tr.apiname.com", "eu.apiname.com"]
```
### Extra registry fields: `tldAttributes`
Some extensions demand data beyond the standard contact set — a tax number for `.com.tr`, a citizenship declaration for `.eu`, a nexus category for `.us`. You supply these as a flat key/value object alongside the rest of the registration request.
#### Where the keys and values come from
**Do not guess them and do not hard-code them.** Every valid key is published in the `attributes` array of the TLD catalogue:
```http
GET /api/v1/products/tlds?filterText=com.tr
```
See [the TLD catalogue](https://www.domainnameapi.com/docs/catalogue/) for the full response, or the extension's own page under [TLDs](https://www.domainnameapi.com/docs/tlds/). Each entry in `attributes` gives you everything you need to build the form:
| Catalogue field | Use it for |
| --- | --- |
| `key` | **The key to send in `tldAttributes`.** |
| `description` | The label to show. |
| `type` | `Text`, `DropdownList`, `RadioButton`, `Checkbox`, `CheckboxWithContract`, `FileUpload` or `Label` — tells you which input to render. `Label` entries are informational only. |
| `options` | **The exact permitted values**, each as `{ "value": "..." }`. Send one of these verbatim; anything else is rejected. |
| `isRequired` | Whether registration fails without it. |
:::tip[Build the form from the catalogue, not from a hard-coded list]
Render the extra fields dynamically from `attributes`. New extension requirements then work without a code change, you never send a key the registry does not recognise, and the permitted values for dropdowns always match what the registry accepts.
:::
#### Worked example: `.tr` domains
Turkish domains are the most involved case. In the test environment you can register them with the following attributes:
```json
{
"domainName": "apiname.com.tr",
"period": 1,
"nameServers": ["tr.apiname.com", "eu.apiname.com"],
"contacts": [
{
"contactType": "Registrant",
"firstName": "Ahmet",
"lastName": "Yilmaz",
"companyName": "Apiname Ltd",
"eMail": "ahmet@apiname.com",
"address": "Ataturk Caddesi No 12 Kat 3",
"city": "Istanbul",
"state": "Istanbul",
"postalCode": "34100",
"country": "TR",
"phoneCountryCode": "90",
"phone": "5321234567"
}
],
"tldAttributes": {
"TRABISDOMAINCATEGORY": "Corporate",
"TRABISTAXNUMBER": "11111111111",
"TRABISTAXOFFICE": "Yok"
}
}
```
:::note[These values are for the test environment]
`11111111111` and `"Yok"` are accepted by the test registry so you can exercise the flow end to end. **In production you must send the customer's real tax number and real tax office** — the registry verifies them against official records.
:::
#### The attributes depend on each other
`.tr` is a good illustration of something that applies to several extensions: one attribute decides which others are required and how they are checked.
| `TRABISDOMAINCATEGORY` | What is then required and validated |
| --- | --- |
| `Corporate` | `TRABISTAXNUMBER` — checked as a tax number (or an 11-digit identity number)
`TRABISTAXOFFICE` — checked as a tax office |
| `Owner` | `TRABISCITIZENID` — checked as an 11-digit national identity number |
Send the wrong category and you will either be asked for a field you were not expecting, or the field you did send will go unchecked and reach the registry unverified.
:::danger[The contact and the attributes must agree — this one has consequences]
The extra attributes are validated **together with the contact you send**, not in isolation. In particular, the **registrant's `country`** changes how they are checked: Turkish tax and identity numbers are only verified when the registrant's country is `TR`. Send a different country and that check is skipped — your value is accepted here and passed straight to the registry.
The registry then does its own verification, after registration. If the details do not match official records, the domain can be suspended or **deleted**, and a deleted domain is not something we can recover for you.
So before you register:
- Make sure `country`, the address and the tax or identity number describe the **same real entity**.
- Use the customer's actual registered address, not your own and not a placeholder.
- Treat a successful registration as "accepted", not "verified" — the registry's own check comes later.
:::
#### What a bad attribute value gives you
| Code | Meaning and fix |
| --- | --- |
| `Dna.DomainService:TldAttribute:10001` | You sent a key this extension does not define. `details` lists the offending keys. Check them against `attributes[].key` in the catalogue — a common cause is reusing keys from a different extension. |
| `Dna.DomainService:TldAttribute:10002` | A required attribute is missing. `details` names it in readable form. Remember that which attributes are required can depend on the value of another one. |
| `Dna.DomainService:TldAttribute:10003` | A value failed validation. The message names the field; `data.ValidationError` carries the specific rule that failed — see the table below. |
| `Dna.DomainService:TldAttribute:10004` | This extension does not support internationalised (IDN) names. |
| `Dna.DomainService:TldAttribute:10005` | Value longer than the attribute allows. `details` gives the limit. |
When `10003` is raised, `data.ValidationError` tells you exactly which rule rejected the value:
| `data.ValidationError` | What was wrong |
| --- | --- |
| `Validation:IdentityNumber:Length` | The identity number is not exactly 11 digits. |
| `Validation:IdentityNumber:Format` | It is not 11 digits, or it starts with `0`. |
| `Validation:IdentityNumber:RepeatedDigits` | The same digit repeats 6 or more times in a row — rejected as an obviously fake number even when the checksum passes. |
| `Validation:IdentityNumber:Checksum` | The number is well-formed but fails its check-digit calculation. Almost always a typo. |
| `Dna.TaxNoValidatorError` | The tax number is not a valid 10-digit tax number and not a valid 11-digit identity number. |
| `Dna.RequiredValidatiorError` | An attribute the registry treats as mandatory was left empty. (The key is spelled this way in the response — match it literally.) |
:::caution[Validate before you buy]
Attribute validation happens during registration, which is also when your balance is checked. A rejected attribute does not charge you, but it does mean a round trip and a failed order on your record. Validate tax and identity numbers in your own form first — the rules above are enough to catch almost every bad value before it reaches us.
:::
### Trustee service: `useTrusteeContact`
Some country extensions require a local presence. Setting `useTrusteeContact: true` on registration buys our trustee service and uses the trustee's details as the domain's contacts.
:::caution[What changes when you use a trustee]
- Your `contacts` array and `tldAttributes` are both **replaced** by the trustee's. Anything you send in them is discarded.
- The domain costs more — a second line item appears on the order.
- Contact verification does not apply: the contacts are the trustee's, not your customer's.
- `PUT /api/v1/domains/contacts/update` is afterwards refused with `Dna.DomainService:Domain:10037`.
- `GET /api/v1/domains/info` returns an **empty** `contacts` array.
Check `isSupportTrustee` and `isTrusteeRequired` in the catalogue. If `isTrusteeRequired` is true and you omit the flag, registration fails with `Dna.DomainService:Trustee:10006`.
:::
### How paid operations work
Register, renew, transfer and restore all debit your balance. The sequence is: check your account is in good standing → look up your price → check your balance → send the command to the registry → record it → charge you.
Two consequences worth designing for:
- A **price seal** is taken when you search. For premium domains the registry quote is re-checked at purchase; if it moved, the purchase is refused with `Dna.DomainService:Domain:10072` and **nothing is charged**. Search again to get the current price.
- If the registry succeeds but we cannot record it, you get a **never-retry** error. See the box below — this is the most important operational rule in the API.
:::danger[Three codes that mean "do not retry"]
| Code | What happened |
| --- | --- |
| `Dna.DomainService:Domain:10058` | The domain **was registered** at the registry, but we could not write our own record. |
| `Dna.DomainService:Domain:10059` | The domain **was renewed** at the registry, but we could not record it. |
| `Dna.DomainService:Domain:10060` | The transfer **was started** at the registry, but we could not record it. |
In all three cases the operation **succeeded**. A recovery record has been created and our team will reconcile it. **Retrying creates a duplicate registration or a double charge.** Open a support ticket with the domain name and your correlation ID instead.
The message text tells you which of the two meanings of `10058` you have: a registry message means do-not-retry; "mixes multiple scripts" means your input was rejected and nothing happened.
:::
---
# Check availability
> Check whether one domain, or up to 30 at once, is available and what it would cost.
## POST /api/v1/domains/search
Is this domain available, and what would it cost? Costs 1 quota point, and the answer is cached for 10 seconds per account. Together with `bulk-search` it is limited to 2 calls per second — see [Rate limits](https://www.domainnameapi.com/docs/getting-started/rate-limits/).
**Request**
```json
{
"domainName": "apiname.com"
}
```
**Response — 200, available domain**
```json
{
"success": true,
"code": "1000",
"reason": null,
"operationMessage": null,
"info": {
"domainName": "apiname.com",
"tld": "com",
"status": "AVAILABLE",
"reason": null,
"isPremium": false,
"isDocumentRequired": false,
"price": 11.40,
"currency": "USD",
"period": 1
}
}
```
**Response — 200, taken domain**
```json
{
"success": true,
"code": "2302",
"reason": "Domain exists",
"info": {
"domainName": "apiname.com",
"tld": "com",
"status": "NOTAVAILABLE",
"reason": "Domain exists",
"isPremium": false,
"isDocumentRequired": false,
"price": 11.40,
"currency": "USD",
"period": 1
}
}
```
:::note[`success: true` does not mean "available"]
`success` describes the *lookup*, not the domain. A successful lookup of a registered domain returns `success: true` with `info.status: "NOTAVAILABLE"`. **Read `info.status`**.
:::
**info.status values**
| Value | Meaning and what to do |
| --- | --- |
| `AVAILABLE` | Registrable now. Proceed to register. |
| `NOTAVAILABLE` | Taken. It may still be transferable — check with `/transfers/check`. |
| `UNSUPPORTEDTLD` | We do not sell this extension. Do not retry. |
| `INVALIDDOMAINNAME` | The name is syntactically invalid. |
| `ERROR` | The registry lookup failed. Retry after a short pause. |
| `NONE` | No result returned. |
**Fields that change your flow**
| Field | What it means for you |
| --- | --- |
| `price` | Your selling price for the **shortest** registration term this TLD offers — not necessarily one year. Check `period`. |
| `isPremium` | Registry-priced premium name. `price` is the registry quote with your margin applied, and **you can only register, renew or transfer it for one year**. |
| `isDocumentRequired` | Registration will not complete until you upload documents. Plan the [document flow](https://www.domainnameapi.com/docs/domains/documents/) before selling this domain. |
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `DnaValidationError` | `domainName` empty. |
| `Dna.DomainService:Domain:10005` | Invalid domain name. |
| `Dna.DomainService:Domain:10004` | We do not sell this extension. |
| `Dna.DomainService:Domain:10017` | Registry search temporarily unavailable. Retry. |
| `Dna.DomainService:Price:10001` | No price configured for this extension. Open a ticket. |
## POST /api/v1/domains/bulk-search
Up to **30** domains in one call. Use this for search-result pages and extension suggestions.
**Request — a JSON array, not an object**
```json
[
{ "domainName": "apiname.com" },
{ "domainName": "apiname.net" },
{ "domainName": "apiname.org" },
{ "domainName": "apiname.com.tr" }
]
```
**Response — 200**
```json
{
"success": true,
"code": "1000",
"reason": null,
"operationMessage": null,
"infos": [
{ "domainName": "apiname.com", "tld": "com", "status": "NOTAVAILABLE",
"isPremium": false, "isDocumentRequired": false,
"price": 11.40, "currency": "USD", "period": 1 },
{ "domainName": "apiname.net", "tld": "net", "status": "AVAILABLE",
"isPremium": false, "isDocumentRequired": false,
"price": 13.20, "currency": "USD", "period": 1 },
{ "domainName": "apiname.org", "tld": "org", "status": "AVAILABLE",
"isPremium": false, "isDocumentRequired": false,
"price": 12.80, "currency": "USD", "period": 1 }
]
}
```
:::danger[Two traps in this response]
1. **`infos` can be shorter than your request.** In the example above four domains were asked about and three came back — `apiname.com.tr` was dropped. Entries are skipped silently when the name is invalid, the extension is unknown, or no price is configured. **Match results back by `infos[].domainName`, never by array index.** Anything missing should be treated as "unknown", not "available".
2. **The top-level `success`, `code`, `reason` and `operationMessage` are not per-domain.** They reflect the last entry processed. Ignore them and read `infos[]`.
:::
:::note[Cost]
This costs **10 points**, not 1 — it is a bulk write-weight operation. Even so, 30 domains in one `bulk-search` (10 points) is three times cheaper than 30 separate `search` calls (30 points), as well as far faster.
:::
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `Dna.Domainservice:Domain:10036` | More than 30 domains. Split into batches of 30. |
---
# Register a domain
> Register a domain with inline contact details or with handle codes, and how contactType is interpreted by each endpoint.
There are two ways to register, and the difference matters.
| | `/register-with-contacts` | `/register` |
| --- | --- | --- |
| Contacts supplied as | Full details inline | Existing **handle codes** |
| Fewer than 4 contacts | **Allowed** — we fill the rest | **Not allowed** — all four required |
| `contactType` matching | Flexible | **Exact names only** |
| Creates new contact records | Yes, one per role | No, reuses yours |
| Trustee service | Supported | Not supported |
| Best for | One-off registrations, first-time customers | Volume, repeat customers, consistent WHOIS |
## How `contactType` is interpreted
This is the single most common source of confusion, because the two registration endpoints behave differently.
**On /register-with-contacts and /domains/contacts/update — flexible**
Values are resolved in this order:
1. **Numeric first.** `"0"` → Admin, `"1"` → Registrant, `"2"` → Billing, `"3"` → Tech. A number outside 0–3 falls through to the next step.
2. **First letter, case-insensitive.** Starts with `A` → Admin, `B` → Billing, `R` → Registrant, `T` → Tech.
3. **Anything else → Registrant.**
| You send | Resolves to | Why |
| --- | --- | --- |
| `"Registrant"`, `"registrant"`, `"REG"`, `"r"` | Registrant | first letter R |
| `"1"` | Registrant | numeric |
| `"Admin"`, `"administrative"`, `"a"` | Admin | first letter A |
| `"0"` | Admin | numeric |
| `"Tech"`, `"technical"`, `"t"` | Tech | first letter T |
| `"Billing"`, `"b"` | Billing | first letter B |
| `"7"` | **Registrant** | not a valid number, matches no letter rule → default |
| `"owner"`, `"xyz"` | **Registrant** | default |
:::caution[An unrecognised value silently becomes Registrant]
There is no error for a typo. `"Techncial"` starts with T and becomes Tech — fine. `"owner"` becomes **Registrant**, which may not be what you meant, and if you also sent a real Registrant you will get a duplicate-role error instead of a clear message about the typo. **Send the exact names** — `Registrant`, `Admin`, `Tech`, `Billing` — and you never have to think about any of this.
:::
**On /register — exact names only**
:::danger[`/register` is case-sensitive and does not accept numbers]
Handle matching on `/register` compares `contactType` literally against `Registrant`, `Admin`, `Billing`, `Tech`. The flexible rules above **do not apply**. These all fail:
```json
"contactType": "1" ✗
"contactType": "registrant" ✗
"contactType": "REGISTRANT" ✗
"contactType": "Registrant" ✓
```
A mismatch surfaces as `Dna.DomainService:Contact:10018` — "missing contact type" — which does not obviously point at a capitalisation problem. If you get that error on `/register`, check your casing first.
:::
## Registering with contact details
### POST /api/v1/domains/register-with-contacts
Registers a domain, creating contact records from the details you send.
**Request**
| Field | Required | Notes |
| --- | --- | --- |
| `domainName` | required | Must be `AVAILABLE`. |
| `period` | required | Years. Must be one of the TLD's `registrationPeriods`. Premium: 1 only. |
| `nameServers` | required | Array of host names. At least one. |
| `contacts` | required | 1 to 4 objects. See auto-fill below. |
| `tldAttributes` | varies | Required when the TLD defines required attributes. |
| `useTrusteeContact` | optional | Default `false`. |
**Minimal request — one contact for all four roles**
```json
{
"domainName": "apiname.com",
"period": 1,
"nameServers": ["tr.apiname.com", "eu.apiname.com"],
"contacts": [
{
"contactType": "Registrant",
"firstName": "Ahmet",
"lastName": "Yilmaz",
"companyName": "Apiname Ltd",
"eMail": "ahmet@apiname.com",
"address": "Ataturk Caddesi No 12 Kat 3",
"city": "Istanbul",
"state": "Istanbul",
"postalCode": "34100",
"country": "TR",
"phoneCountryCode": "90",
"phone": "5321234567"
}
]
}
```
**With a required TLD attribute**
```json
{
"domainName": "apiname.com.tr",
"period": 1,
"nameServers": ["tr.apiname.com", "eu.apiname.com"],
"contacts": [
{
"contactType": "Registrant",
"firstName": "Ahmet",
"lastName": "Yilmaz",
"companyName": "Apiname Ltd",
"eMail": "ahmet@apiname.com",
"address": "Ataturk Caddesi No 12 Kat 3",
"city": "Istanbul",
"state": "Istanbul",
"postalCode": "34100",
"country": "TR",
"phoneCountryCode": "90",
"phone": "5321234567"
}
],
"tldAttributes": {
"identityNumber": "12345678901"
}
}
```
**Two separate contacts**
```json
{
"domainName": "apiname.net",
"period": 2,
"nameServers": ["tr.apiname.com", "eu.apiname.com"],
"contacts": [
{
"contactType": "Registrant",
"firstName": "Ahmet", "lastName": "Yilmaz",
"companyName": "Apiname Ltd", "eMail": "ahmet@apiname.com",
"address": "Ataturk Caddesi No 12 Kat 3",
"city": "Istanbul", "state": "Istanbul", "postalCode": "34100",
"country": "TR", "phoneCountryCode": "90", "phone": "5321234567"
},
{
"contactType": "Tech",
"firstName": "Mehmet", "lastName": "Kaya",
"companyName": "Apiname Ltd", "eMail": "tech@apiname.com",
"address": "Ataturk Caddesi No 12 Kat 3",
"city": "Istanbul", "state": "Istanbul", "postalCode": "34100",
"country": "TR", "phoneCountryCode": "90", "phone": "5329876543"
}
]
}
```
**How missing roles are filled in**
You do not need to send four contacts. Roles are assigned, then any still-empty role is filled by **copying the first contact in your array**.
| You send | What the domain ends up with |
| --- | --- |
| 1 contact, no `contactType` | It becomes **Registrant**; Admin, Tech and Billing are copies of it. *The typical single-contact call.* |
| 1 contact, `"Admin"` | It becomes Admin; the other three are copies of it. |
| 2 contacts: Registrant + Tech | Those two as given; **Admin and Billing are copies of the first contact** (the registrant). |
| 2 contacts, both `"Registrant"` | The first is Registrant. The second's role is cleared and it takes **Admin**. Tech and Billing are copies of the first. |
| 4 contacts, all roles named | Used exactly as given. No copying. |
| 4 contacts, none with `contactType` | Assigned in array order: Registrant, Admin, Tech, Billing. |
| 5 or more contacts | The first four to claim a role win; extras are ignored. |
:::caution[An empty `contacts` array is not filled in]
Sending `"contacts": []` does **not** produce four default contacts — it fails with `Dna.DomainService:Contact:10018`. Send at least one.
:::
**Response — 200**
```json
{
"success": true,
"message": "Domain registration successful",
"domainId": "3c9a7e14-82b5-4d60-9f31-c7e8a05b6d42",
"status": "Active",
"expirationDate": "2027-10-30T12:04:17"
}
```
:::danger[`status` is not always `Active`]
A 200 means the registration was accepted, not that the domain is live. For extensions that require documents you will get `WaitingForRegistration` or `WaitingForDocument`, and the domain does not work until you [upload documents](https://www.domainnameapi.com/docs/domains/documents/) and the registry approves them.
**Always read `status`** and branch on it. The registration confirmation e-mail to the registrant is only sent when the status is `Active`.
:::
:::tip[What to do next]
1. Store `domainId` — quote it in support tickets.
2. If `status` is not `Active`, go to the document flow.
3. Either way, **check verification**: `GET /api/v1/contacts/verification/check`. The 15-day clock has started.
4. If you sent our name servers, configure DNS records with the [zones API](https://www.domainnameapi.com/docs/dns-records/).
:::
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `Dna.DomainService:Domain:1026` | Already registered. Search first; consider transfer. |
| `Dna.DomainService:Domain:10044` | Invalid domain name. |
| `Dna.DomainService:Domain:10058` | Mixed alphabets in the name — *or* the never-retry condition. Read `message`. |
| `Dna.DomainService:Domain:10004` | Extension not sold. |
| `Dna.DomainService:Domain:10023` | `period` not offered for this TLD. |
| `Dna.DomainService:Domain:10071` | Premium domain with `period` above 1. |
| `Dna.DomainService:Domain:10072` | Premium price changed since your search. Nothing charged — search again. |
| `Dna.DomainService:Dns:10022` | Too few or too many name servers for this TLD. |
| `Dna.DomainService:Dns:10013` | Duplicate entry in `nameServers`. |
| `Dna.DomainService:Dns:10026` | IPv6 glue not supported by this TLD. |
| `Dna.DomainService:Contact:10018` | Fewer than four roles resolved, or `contacts` empty. |
| `Dna.DomainService:Contact:10022` | Two contacts resolved to the same role. |
| `Dna.DomainService:Contact:10011` | Invalid contact e-mail. |
| `Dna.DomainService:Contact:10012` | Invalid country code. |
| `Dna.DomainService:Contact:10013 / :10014` | Phone country code or number invalid. |
| `Dna.DomainService:Contact:10023 / :10024` | First or last name empty after invalid characters were removed. |
| `Dna.DomainService:TldAttribute:10001–10005` | Extra-field problems — see above. |
| `Dna.DomainService:Trustee:10002` | Trustee not available for this domain. |
| `Dna.DomainService:Trustee:10006` | This TLD requires the trustee service; set `useTrusteeContact: true`. |
| `Dna.DomainService:Domain:10049` | No price configured for this TLD and period. |
| `Dna.DomainService:Deposit:10001` | Insufficient balance. `data` tells you how much is needed. |
| `Dna.DomainService:Reseller:10001` | Your account balance is suspended. Contact us. |
| `Dna.DomainService:Epp:10001` | The registry refused for a reason we have no specific code for. Read `details`. |
## Registering with handle codes
### POST /api/v1/domains/register
Registers a domain using contact handles that already exist in your account. No new contact records are created. This is the endpoint to use at volume.
**Request**
| Field | Required | Notes |
| --- | --- | --- |
| `domainName` | required | |
| `period` | required | Years. |
| `nameServers` | required | Must not be empty. |
| `handles` | required | **All four roles.** Must not be empty. |
| `handles[].contactType` | required | **Exactly** `Registrant`, `Admin`, `Billing` or `Tech`. |
| `handles[].handle` | required | A handle in your account. |
| `tldAttributes` | varies | As above. |
**One handle for all four roles**
```json
{
"domainName": "apiname.com",
"period": 1,
"nameServers": ["tr.apiname.com", "eu.apiname.com"],
"handles": [
{ "contactType": "Registrant", "handle": "D-174829301847" },
{ "contactType": "Admin", "handle": "D-174829301847" },
{ "contactType": "Tech", "handle": "D-174829301847" },
{ "contactType": "Billing", "handle": "D-174829301847" }
]
}
```
**Different handles per role**
```json
{
"domainName": "apiname.net",
"period": 1,
"nameServers": ["tr.apiname.com", "eu.apiname.com"],
"handles": [
{ "contactType": "Registrant", "handle": "D-174829301847" },
{ "contactType": "Admin", "handle": "D-174829301847" },
{ "contactType": "Tech", "handle": "D-174830552193" },
{ "contactType": "Billing", "handle": "D-174830998471" }
],
"tldAttributes": {}
}
```
**Response — 200**
Identical to `/register-with-contacts`:
```json
{
"success": true,
"message": "Domain registration successful",
"domainId": "3c9a7e14-82b5-4d60-9f31-c7e8a05b6d42",
"status": "Active",
"expirationDate": "2027-10-30T12:04:17"
}
```
:::caution[All four roles are mandatory here]
There is no auto-fill on this endpoint. Omitting a role gives `Dna.DomainService:Contact:10018`. The simplest correct call repeats the same handle four times, as in the first example.
:::
**Errors — handles**
| Code | Meaning and fix |
| --- | --- |
| `Dna.DomainService:Contact:10018` | A role is missing. **Most often a capitalisation problem** — see the box above. Also fires if you genuinely omitted a role. |
| `Dna.DomainService:Contact:10006` | `handles` is empty. |
| `Dna.DomainService:Contact:10005` | `contactType` could not be resolved at all. |
| `Dna.DomainService:Contact:10008` | The handle does not exist **in your account**. Check the code, and that it is yours. |
| `Dna.DomainService:Contact:10019` | Handle string empty or malformed. |
All the registration errors listed under `/register-with-contacts` apply here too.
## Can you register with an unverified contact?
**Yes** — and this catches people out, so it is worth being explicit.
Verification is a *consequence* of registration, not a precondition. The domain registers and goes live immediately. Then the 15-day clock starts. If the registrant never clicks the link, the domain is suspended and stops resolving. Full detail is in [Contact verification](https://www.domainnameapi.com/docs/contacts/verification/).
:::tip[The recommended registration flow]
1. `POST /api/v1/domains/search` — confirm `info.status` is `AVAILABLE` and note `isPremium` and `isDocumentRequired`.
2. `POST /api/v1/contacts` — create the contact once, store the handle. (Skip if you already have one for this customer.)
3. `POST /api/v1/domains/register` — register with the handle.
4. Read `status`. Not `Active`? Go to the document flow.
5. `GET /api/v1/contacts/verification/check` — record `tokenExpireDate` and surface it in your dashboard.
6. Configure DNS: [zone records](https://www.domainnameapi.com/docs/dns-records/) if you used our name servers, otherwise [change the name servers](https://www.domainnameapi.com/docs/name-servers/).
:::
---
# Renew a domain
> Renew safely: check first, understand the auto-renew and renew periods, and every reason a renewal can be refused.
Always call `/renew/check` first. It tells you whether the renewal will be accepted and whether a premium price applies, without charging anything.
:::danger[Important: a domain can only be renewed once per grace period]
This is the single most common reason a renewal is refused, and it surprises almost everyone the first time. **Nothing is wrong with the domain and nothing is wrong with your request — the registry is simply holding a window open during which a second renewal is not allowed.** These windows are temporary and they protect you financially: without them a domain could be renewed twice and you would be charged twice.
There are two such windows, and which one you hit depends on whether the domain had already expired.
:::
## After expiry: the auto-renew period
When a domain reaches its expiry date without being renewed, most registries do not delete it immediately. On the first day after expiry the registry **renews it automatically**, and the domain enters its **auto-renew grace period**.
Inside that window the domain has already been renewed once. A further renewal is refused until the window closes. The length varies by extension and is published as `autoRenewGracePeriod` in the TLD catalogue — commonly **two to three weeks**, and up to 45 days on some extensions.
| What you get | Meaning |
| --- | --- |
| `Dna.DomainService:Domain:10020` | "The domain is in its auto-renew period and its expiration has already been extended." |
:::tip[What to do]
**Nothing, usually.** The domain is already renewed — read `GET /api/v1/domains/info` and you will see the new `expirationDate`. Update your own records from it rather than retrying. If the customer genuinely needs an additional year on top, wait for the grace period to end and renew then.
:::
## Before expiry: the renew period
A domain that has *not* expired and that you renew normally enters a shorter window called the **renew period**, typically **three to five days**. A second renewal inside it is refused for the same reason.
| What you get | Meaning |
| --- | --- |
| `Dna.DomainService:Domain:10051` | "The domain has already been renewed and is currently in its renew-period. You can renew it again in a few days." |
:::note[Sometimes this resolves itself silently]
If the registry shows a later expiry than we hold on record, we take the registry's date, update the domain and return success without charging you again — the renewal you were asking for had already happened. You only get `10051` when the dates agree and the window is genuinely still open.
:::
## Renewing long before expiry
Most generic extensions do not let you renew at any time. If the domain's renewal date is more than **60 days** away, the renewal is refused:
| What you get | Meaning |
| --- | --- |
| `Dna.DomainService:Domain:10021` | "This domain cannot be renewed yet because its TLD does not support early renewal before the expiration date." |
The extensions that **do** allow it are mostly country-code domains — `.de` and `.it` are typical. The catalogue does not publish which extensions accept early renewal, so treat `Dna.DomainService:Domain:10021` as the answer: it means "not yet — try again once the domain is within 60 days of its renewal date". Inside that window, this rule no longer applies on any extension.
:::caution[One more limit when early renewal is allowed]
On extensions that accept early renewal, the time already remaining plus the term you are adding must not exceed the longest term the extension sells. Renewing a domain that still has 8 years left for another 5 is refused with `Dna.DomainService:Domain:1028` — "The maximum renewal period for the domain name has exceeded the allowed limit." Request fewer years.
:::
## All the reasons a renewal can be refused
| Code | Why, and what to do |
| --- | --- |
| `Dna.DomainService:Domain:10020` | **Auto-renew period.** Already renewed automatically after expiry. Call `GET /api/v1/domains/info` and store the new `expirationDate`; wait for the window to close if another year is really needed. |
| `Dna.DomainService:Domain:10051` | **Renew period.** Renewed within the last few days. Wait and retry. |
| `Dna.DomainService:Domain:10021` | **Too early.** More than 60 days out on an extension that does not allow early renewal. Retry once the domain is within 60 days of its renewal date. |
| `Dna.DomainService:Domain:1028` | **Too long.** The time remaining plus the requested term exceeds the longest term in the extension's `renewalPeriods` (usually 10 years), counted from today. Request fewer years. |
| `Dna.DomainService:Domain:10002` | The `period` you asked for is not one of the extension's `renewalPeriods`. Read them from the catalogue. |
| `Dna.DomainService:Domain:10022` | `period` is above 10. |
| `Dna.DomainService:Domain:10018` | The registry has a renewal prohibition on this domain, or its status does not allow renewal. |
| `Dna.DomainService:Domain:10045` | A `clientRenewProhibited` lock is set at the registry. |
| `Dna.DomainService:Domain:10019` | A registry connection problem was recorded for this domain in the last three days, so renewal is held back to avoid a double charge. Also returned when the request could not be completed for a temporary reason. Retry later. |
:::tip[The safe renewal routine]
1. `POST /api/v1/domains/renew/check` costs nothing from your balance. It catches a bad `period` (`1016`, `10022`, `10002`, returned as errors) and, with `renewabilityStatus: false`, three refusals in `errorMessageKey`: `10045` (renewal prohibited at the registry), `1016` (the term is too long; `/renew` reports the same case as `1028`) and `10071` (premium domain, 1 year only).
2. The check does **not** ask the registry about its renewal windows, so `10020` and `10051` only come back from `/renew` itself. When they do, call `GET /api/v1/domains/info` and sync `expirationDate` — the renewal you wanted has very likely already happened.
3. Otherwise renew, and store the `expirationDate` the response gives you rather than calculating it yourself.
:::
## POST /api/v1/domains/renew/check
Dry run: can this domain be renewed for this term, and at what price?
**Request**
```json
{
"domainName": "apiname.com",
"period": 1
}
```
**Response — renewable, standard price**
```json
{
"renewabilityStatus": true,
"renewalLock": false,
"errorMessageKey": null,
"isPremium": false,
"premiumPrice": null,
"premiumCurrency": null
}
```
**Response — not renewable**
```json
{
"renewabilityStatus": false,
"renewalLock": false,
"errorMessageKey": "Dna.DomainService:Domain:1016",
"isPremium": false,
"premiumPrice": null,
"premiumCurrency": null
}
```
**Response — premium domain**
```json
{
"renewabilityStatus": true,
"renewalLock": false,
"errorMessageKey": null,
"isPremium": true,
"premiumPrice": 420.00,
"premiumCurrency": "USD"
}
```
| Field | How to use it |
| --- | --- |
| `renewabilityStatus` | `true` means `/renew` will be accepted. Gate your renew button on this. |
| `renewalLock` | A renewal prohibition is set at the registry. |
| `errorMessageKey` | When `renewabilityStatus` is `false`, this is **the exact error code `/renew` would return**. Look it up in [Error codes](https://www.domainnameapi.com/docs/reference/errors/) and show the reason instead of letting the customer hit the error. |
| `premiumPrice` | Your selling price for **one year**. `null` when not premium, in which case the catalogue price applies. |
:::caution[Premium domains and multi-year renewal]
If you ask for more than one year on a premium domain, the response comes back with `renewabilityStatus: false` and `errorMessageKey: "Dna.DomainService:Domain:10071"`. Retry with `period: 1`.
:::
## POST /api/v1/domains/renew
Renews the domain and debits your balance.
**Request**
```json
{
"domainName": "apiname.com",
"period": 2
}
```
**Response — 200**
```json
{
"success": true,
"message": "Domain renewal successful",
"domainId": "3c9a7e14-82b5-4d60-9f31-c7e8a05b6d42",
"status": "Active",
"expirationDate": "2029-10-30T12:04:17"
}
```
:::tip[What to do with it]
Store the new `expirationDate` — it is authoritative and comes from the registry. Do not calculate it yourself by adding years to the old date: grace periods and registry rounding mean the result is often different from what you would compute.
:::
:::note[Trustee domains]
If the domain uses our trustee service, the trustee fee is added to the same order automatically. You do not need to request it, and your balance is debited for both.
:::
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `Dna.DomainService:Domain:1016` | Only on `/renew/check`: `period` is 0. (On `/renew`, a `period` below 1 is treated as 1.) |
| `Dna.DomainService:Domain:10007` | Domain not found or not yours. |
| `Dna.DomainService:Domain:10018` | Not in a renewable state — deleted, transferred out, or pending deletion. |
| `Dna.DomainService:Domain:10019` | Temporarily unavailable: a registry connection problem was recorded for this domain in the last three days. Retry later. |
| `Dna.DomainService:Domain:10020` | The registry already auto-renewed it; the expiry has moved. Call `GET /api/v1/domains/info` and store the new `expirationDate`. |
| `Dna.DomainService:Domain:10021` | Too early — this TLD does not allow renewal this far before expiry. |
| `Dna.DomainService:Domain:10051` | Renewed very recently and still inside the registry's renewal grace window. Wait a few days. |
| `Dna.DomainService:Domain:10022` | `period` above 10. |
| `Dna.DomainService:Domain:10002` | `period` is not one of the extension's `renewalPeriods`. |
| `Dna.DomainService:Domain:1028` | The renewal would push total registration past the longest term in the extension's `renewalPeriods` (usually 10 years from today). Renew for fewer years. |
| `Dna.DomainService:Domain:10045` | A renewal prohibition is set at the registry. |
| `Dna.DomainService:Domain:10071` | Premium domain, `period` above 1. |
| `Dna.DomainService:Domain:10072` | Premium price changed. Nothing charged — re-check and retry. |
| `Dna.DomainService:Domain:10049` | No renewal price configured. |
| `Dna.DomainService:Deposit:10001` | Insufficient balance. |
| `Dna.DomainService:Reseller:10001` | Balance suspended. |
| `Dna.DomainService:Trustee:10001` | Trustee domain with no trustee price configured. Open a ticket. |
| `Dna.DomainService:Domain:10059` | **Never retry.** Renewed at the registry, not recorded here. Open a support ticket with the domain name and your `X-Correlation-ID`. |
---
# Transfer a domain in
> Transfer a domain to your account: check with the authorisation code, start the transfer, then poll until the registry completes it.
The correct order is **check → transfer → poll**. A transfer is not instant: most extensions need the current owner's approval and a registry waiting period of up to five days.
## POST /api/v1/domains/transfers/check
Asks the registry whether the domain can be transferred to you with the authorisation code you hold, and what it would cost.
:::caution[This endpoint raises errors instead of returning `false`]
A bad auth code, an active transfer lock or a transfer already in progress all come back as **an HTTP error with an error code** (400 for a bad auth code, 409 for a lock or a transfer already in progress), not as a negative field in a 200 response. Treat a 200 as "transferable" and read the error codes for the reasons.
:::
**Request**
```json
{
"domainName": "apiname.com",
"authCode": "aB3!xY9-kL2pQ7"
}
```
**Response — 200, transferable**
```json
{
"authCodeIsRequired": true,
"authCodeIsValid": true,
"userTransferRequired": true,
"transferLock": false,
"transferAvailabilityStatus": true,
"domainStatuses": ["ok", "clientUpdateProhibited"],
"additionalAttributes": {},
"isPremium": false,
"premiumPrice": null,
"premiumCurrency": null,
"messageKey": null,
"message": ""
}
```
| Field | How to use it |
| --- | --- |
| `authCodeIsRequired` | Whether this TLD needs an auth code at all. A few do not. |
| `authCodeIsValid` | The registry accepted the code. |
| `userTransferRequired` | **Important.** `true` means the current registrant must approve by e-mail before the transfer completes. Tell your customer to expect that e-mail, and that ignoring it will stall the transfer. |
| `transferLock` | A transfer prohibition is set. It must be removed at the losing registrar. |
| `domainStatuses` | Raw registry status strings, useful for diagnostics. |
| `premiumPrice` | Your price for a **one-year** transfer when the name is premium. |
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `Dna.DomainService:Domain:10025` | This extension has no transfer-check facility. Not a failure — skip straight to `/transfer`. Check `isTransferCheckSupported` in the catalogue to avoid the call entirely. |
| `Dna.DomainService:Domain:10008` | The registry rejected the auth code. Have the customer re-fetch it from the current registrar. |
| `Dna.DomainService:Domain:10006` | Transfer lock is active. The customer must unlock the domain at their current registrar first. |
| `Dna.DomainService:Domain:10029` | A transfer is already pending, possibly by another registrar. Wait for it to resolve. |
| `Dna.DomainService:Epp:2303` | The domain is not registered at all. Register it instead of transferring. |
## POST /api/v1/domains/transfer
Starts the transfer and debits your balance.
**Request**
| Field | Required | Notes |
| --- | --- | --- |
| `domainName` | required | |
| `authCode` | required | From the current registrar. Length limits vary by TLD. |
| `period` | required | Used for **pricing**. Most registries add exactly one year to the existing expiry regardless. |
| `contacts` | optional | Contact details to apply **after** the transfer completes. Not part of the transfer command itself. |
```json
{
"domainName": "apiname.com",
"authCode": "aB3!xY9-kL2pQ7",
"period": 1
}
```
**Response — 200**
```json
{
"success": true,
"message": "Domain transfer completed successfully",
"domainId": "9b1e4f73-2c58-4a06-8d94-5f2a7c3e1b80",
"status": "pending",
"expirationDate": "2027-06-14T09:31:02"
}
```
:::danger[A 200 means accepted, not completed]
The message says "completed successfully" but `status` is typically `pending`. The domain is **not yours yet**. What usually has to happen next:
- The current registrant receives an approval e-mail and must click it.
- The losing registrar may take up to 5 days to release, or the registry auto-approves after that window.
Poll `/transfers/query` and do not promise the customer a live domain until the status is approved. Your balance is debited at this point regardless.
:::
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `Dna.DomainService:Domain:10039` | The domain is available, not registered. Use registration. |
| `Dna.DomainService:Domain:10024` | The registry does not permit transfer of this name. |
| `Dna.DomainService:Domain:10011` | This extension does not support transfers at all. Check `isSupportTransfer`. |
| `Dna.DomainService:Domain:10026` | `authCode` missing. |
| `Dna.DomainService:Domain:10008 / :10047` | Auth code incorrect. |
| `Dna.DomainService:Domain:10035` | Auth code length is outside this TLD's limits. `details` gives the min and max. |
| `Dna.DomainService:Domain:10006` | Transfer lock active at the losing registrar. |
| `Dna.DomainService:Domain:10031 / :10057` | **60-day rule.** The domain was registered or transferred within the last 60 days. Registry policy — nothing can be done but wait. |
| `Dna.DomainService:Domain:10028` | You already have a transfer pending on this domain. |
| `Dna.DomainService:Domain:10029` | Another registrar's transfer is pending. |
| `Dna.DomainService:Domain:1024` | The domain is already in your account. |
| `Dna.DomainService:Domain:10048` | No transfer price configured for that period. |
| `Dna.DomainService:Domain:10050` | The domain is in our system but we cannot match the record. Open a ticket. |
| `Dna.DomainService:Domain:10071` | Premium domain, `period` above 1. |
| `Dna.DomainService:Deposit:10001` | Insufficient balance. |
| `Dna.DomainService:Reseller:10001` | Balance suspended. |
| `Dna.DomainService:Domain:10060` | **Never retry.** Started at the registry, not recorded here. |
## POST /api/v1/domains/transfers/query
Status of a transfer in flight. Poll this after starting one.
**Request**
```json
{
"domainName": "apiname.com"
}
```
**Response — 200**
```json
{
"domainName": "apiname.com",
"status": "pending",
"requestedDate": "2026-10-30T12:18:44",
"finalDate": "2026-11-04T12:18:44",
"requestedClientId": "GAINING-REGISTRAR",
"actionClientId": "LOSING-REGISTRAR"
}
```
| Field | How to use it |
| --- | --- |
| `status` | `pending` · `clientApproved` · `clientRejected` · `clientCancelled` · `serverApproved` · `serverCancelled` |
| `finalDate` | **The date the registry will auto-approve** if nobody acts. Show this to your customer as "transfer completes by". |
| `requestedClientId` | The gaining registrar. |
| `actionClientId` | The losing registrar. |
:::tip[Polling advice]
Poll once or twice a day, not every minute. Transfers move on a scale of days. `clientRejected` or `clientCancelled` are terminal — the customer must restart the process with the losing registrar.
:::
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `Dna.DomainService:Domain:10007` | No record of this domain. |
| `Dna.DomainService:Domain:10025` | The domain is not currently in a transfer state, so there is nothing to query. (This code has a different meaning on `/transfers/check`.) |
| `Dna.DomainService:Domain:10027` | The registry has no transfer history for this domain. |
---
# Read domain information
> Read everything about one domain, or page through every domain in your account to keep your own database in sync.
## GET /api/v1/domains/info
Everything we know about one of your domains. Costs 1 quota point — cheap enough to call on every page load.
**Request**
```http
GET /api/v1/domains/info?domainName=apiname.com
```
**Response — 200**
```json
{
"domainName": "apiname.com",
"domainNameIdn": "apiname.com",
"isIdnName": false,
"resellerId": "7f3c1a28-9e4b-4c51-b1d2-0a6e5f8c3d94",
"startDate": "2026-10-30T12:04:17",
"expirationDate": "2027-10-30T12:04:17",
"transferDate": "0001-01-01T00:00:00",
"updatedDate": "2026-10-30T14:22:08",
"remainingDay": 365,
"status": "Active",
"statusCode": "ok",
"statusReason": "None",
"rgpStatues": "ok",
"objectId": "2184796_DOMAIN_COM-VRSN",
"renewalMode": "AutoRenew",
"authCode": "aB3!xY9-kL2pQ7",
"lockStatus": true,
"privacyProtectionStatus": false,
"isForwarded": false,
"useTrusteeContact": false,
"nameservers": ["tr.apiname.com", "eu.apiname.com"],
"hosts": [],
"contacts": [
{
"contactType": "Registrant",
"handle": "D-174829301847",
"firstName": "Ahmet",
"lastName": "Yilmaz",
"companyName": "Apiname Ltd",
"eMail": "ahmet@apiname.com",
"address": "Ataturk Caddesi No 12 Kat 3",
"city": "Istanbul",
"state": "Istanbul",
"postalCode": "34100",
"country": "TR",
"phoneCountryCode": "90",
"phone": "5321234567"
}
],
"additionalAttributes": {}
}
```
**The fields that matter most**
| Field | How to use it |
| --- | --- |
| `status` | The **name** of the status (`Active`, `PendingHold`…). Note that the domain *list* endpoint returns a number here instead. Full table in [Status values](https://www.domainnameapi.com/docs/reference/status-values/). |
| `statusReason` | **Why** it is in that status. This is where you find out that a domain was suspended for unverified contact data (`RddsVerificationPending`) or is waiting on documents. |
| `remainingDay` | Days to expiry. Goes negative once expired. Drive renewal reminders off this. |
| `rgpStatues` | Grace-period state: `ok`, `autoRenewPeriod`, `renewPeriod`, `redemptionPeriod`, `pendingDelete`. **Restore is only possible when this is `redemptionPeriod`.** |
| `authCode` | The current transfer authorisation code. Give it to the customer when they want to transfer away. Treat it as a secret otherwise. |
| `lockStatus` | Transfer lock on or off. |
| `nameservers` | Current delegation. If this is not `tr.apiname.com` / `eu.apiname.com`, the [zones API](https://www.domainnameapi.com/docs/dns-records/) will not serve this domain. |
| `hosts` | Host (glue) records defined under this domain. |
| `contacts` | One entry per role. **Empty array when `useTrusteeContact` is `true`** — the trustee's details are not disclosed. |
| `additionalAttributes` | The `tldAttributes` stored for this domain. |
### renewalMode
Indicates how the domain is set to behave at the end of its term.
| Value | Name | Meaning |
| --- | --- | --- |
| 1 | `AutoRenew` | The domain is renewed at expiry and your balance is charged. The minimum term is normally one year; some extensions only renew in longer increments, and that increment is used. |
| 2 | `AutoExpire` | The domain is not renewed and is dropped at the end of its term. A few registries vary this — for `.at`, a new billing term begins instead and the domain is charged on the renewal date rather than dropped. |
| 3 | `AutoDelete` | The domain is deleted at expiry without entering the registry's auto-renew grace period, so no auto-renewal fee is incurred. |
The default for your account is configured in your reseller panel, under reseller settings. To renew a specific domain explicitly at any time, use `POST /api/v1/domains/renew`.
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `Dna.DomainService:Domain:10007` | Not found — **or found but not yours**. Ownership mismatches are reported as not-found deliberately. |
| `Dna.DomainService:Domain:10005` | Invalid domain name. |
## GET /api/v1/domains
Paged list of the domains in your account. Use it to sync your own database.
**Request — query string**
| Parameter | Default | Notes |
| --- | --- | --- |
| `domainName` | — | Partial-match filter. |
| `statusIds` | — | Comma-separated status **names or numbers**: `Active,WaitingForDocument` or `0,2`. |
| `skipCount` | 0 | Offset. |
| `maxResultCount` | 25 | **Silently capped at 500.** Asking for 1000 gives you 500 — page properly. |
| `sorting` | — | `field asc` or `field desc`. `expirationDate asc` is the useful one for renewal queues. |
```http
GET /api/v1/domains?maxResultCount=100&skipCount=0
&sorting=expirationDate%20asc
&statusIds=Active
```
**Response — 200**
```json
{
"totalCount": 243,
"items": [
{
"domainName": "apiname.com",
"domainNameIdn": "apiname.com",
"isIdnName": false,
"objectClass": "Standard",
"status": 0,
"statusCode": "ok",
"renewalMode": "AutoRenew",
"startDate": "2026-10-30T12:04:17",
"expirationDate": "2027-10-30T12:04:17",
"remainingDay": 365,
"transferDate": null,
"updatedDate": "2026-10-30T14:22:08",
"rgpExpirationDate": null,
"agpExpirationDate": null,
"lockStatus": true,
"privacyProtectionStatus": false,
"contacts": {
"Registrant": "D-174829301847",
"Admin": "D-174829301847",
"Tech": "D-174829301847",
"Billing": "D-174829301847"
},
"nameservers": [
{ "name": "tr.apiname.com", "isChildnameServer": false,
"isGlueRecord": false, "isLinked": false },
{ "name": "eu.apiname.com", "isChildnameServer": false,
"isGlueRecord": false, "isLinked": false }
]
}
]
}
```
:::caution[Two differences from `/info`]
- `status` here is a **number** (`0` = Active), while `/info` returns the name (`"Active"`). Handle both.
- `contacts` here is a **map of role to handle code**, not full contact details. It is `null` for trustee domains. Use it to see which handles are in play, then call `/info` or the contacts API for detail.
:::
:::tip[Syncing efficiently]
Page with `skipCount` and `maxResultCount=500`, sorted by `expirationDate asc`. Use `totalCount` to know when to stop. This is one call per 500 domains at 10 points each — far cheaper than calling `/info` per domain.
:::
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `Dna.DomainService:Domain:1019` | An entry in `statusIds` is not a valid status. |
| `Dna.DomainService:Domain:10034` | `sorting` names a field that cannot be sorted on. |
---
# Lock, privacy and authorisation code
> Turn the transfer lock and WHOIS privacy on or off, and generate a new transfer authorisation code.
## POST /api/v1/domains/lock · POST /api/v1/domains/unlock
Turns the registrar transfer lock on or off. The lock prevents the domain being transferred away — leave it on unless the customer is actively moving the domain.
**Request — same body for both**
```json
{
"domainName": "apiname.com"
}
```
:::note[Which operation you get is decided by the URL]
There is no `lockStatus` flag. `/lock` locks, `/unlock` unlocks. If your client sends a `lockStatus` field it is ignored.
:::
**Response — 204, no body**
Confirm the new state with `GET /api/v1/domains/info` and read `lockStatus`.
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `DnaValidationError` | `domainName` missing. |
| `Dna.DomainService:Domain:10007` | Domain not found or not yours. |
| `Dna.DomainService:Domain:10016` | The domain's status does not permit the change. |
| `Dna.DomainService:Domain:10032` | **Unlock only.** Refused because an ownership change is pending. Finish that first. |
| `Dna.DomainService:Epp:10001` | The registry rejected it. |
## POST /api/v1/domains/privacy
Turns WHOIS privacy protection on or off. With privacy on, the registrant's personal data is replaced by a proxy in public records.
**Request**
```json
{
"domainName": "apiname.com",
"privacyStatus": true
}
```
| Field | Required | Notes |
| --- | --- | --- |
| `domainName` | required | Must be a whole domain, **not a subdomain**. |
| `privacyStatus` | required | `true` enables, `false` disables. **It must be present** — omitting it is an error, not a default. |
**Response — 204, no body**
:::note[Check support first]
Not every extension sells privacy. Read `isPrivacyAvailable` from the TLD catalogue before offering it, or you will get `Dna.DomainService:Tld:10001`.
:::
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `DnaValidationError` | `privacyStatus` omitted or not a boolean, or `domainName` missing. |
| `Dna.DomainService:Domain:10046` | You sent a subdomain. Send the registrable domain. |
| `Dna.DomainService:Domain:1021` | Domain unknown or not yours. |
| `Dna.DomainService:Tld:10001` | This extension does not support WHOIS privacy. |
## PUT /api/v1/domains/auth
Generates a new transfer authorisation code and returns it.
**Request**
```json
{
"domainName": "apiname.com"
}
```
**Response — 200**
```json
{
"domainName": "apiname.com",
"authCode": "mQ7#vR2-pL9xK4"
}
```
:::caution[The previous code stops working immediately]
If the customer already has the old code and is mid-transfer somewhere else, regenerating breaks it. Only regenerate when asked, or when you suspect the code has leaked. To read the existing code without changing it, use `GET /api/v1/domains/info` and read `authCode`.
:::
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `Dna.DomainService:Domain:10007` | Domain not found or not yours. |
| `Dna.DomainService:Domain:10040` | The registry refused to change the code. |
| `Dna.DomainService:Domain:10035` | The generated code does not satisfy this TLD's length policy. Open a ticket. |
| `Dna.DomainService:Domain:10016` | The domain's status does not permit the change. |
---
# Change a domain's contacts
> Replace a domain's contacts with inline details or handle codes, and when that counts as an ownership change.
## PUT /api/v1/domains/contacts/update
Replaces the contact details for one or more roles on a single domain.
**Request**
```json
{
"domainName": "apiname.com",
"contacts": [
{
"contactType": "Admin",
"firstName": "Mehmet",
"lastName": "Kaya",
"companyName": "Apiname Ltd",
"eMail": "admin@apiname.com",
"address": "Ataturk Caddesi No 12 Kat 3",
"city": "Ankara",
"state": "Ankara",
"postalCode": "06000",
"country": "TR",
"phoneCountryCode": "90",
"phone": "5551234567"
}
]
}
```
:::caution[No auto-fill here, and no partial updates]
- Roles you do not include are **left untouched**. This endpoint does not copy one contact into the other roles the way registration does.
- Each contact you do include is **replaced wholesale**. Send every field.
- Omitting `contactType` makes the entry resolve to **Registrant** — which is almost certainly not what you meant. Always set it explicitly.
:::
**Response — 204, no body**
:::danger[Changing the registrant's name starts an ownership verification]
If you change `firstName`, `lastName` or `companyName` on the Registrant, that is an **ownership change**. An approval e-mail goes to the current owner, the domain is transfer-locked, and for some extensions the registry demands documents. Read [Contact verification](https://www.domainnameapi.com/docs/contacts/verification/) before using this endpoint on a registrant.
Changing only the address, phone or e-mail is not an ownership change — though changing the e-mail does start a new e-mail verification.
:::
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `Dna.DomainService:Domain:10007` | Domain not found or not yours. |
| `Dna.DomainService:Domain:10037` | The domain uses the trustee service; its contacts cannot be changed. |
| `Dna.DomainService:Contact:10022` | Two entries resolved to the same role. |
| `Dna.DomainService:Contact:10012 / :10013 / :10014` | Country, phone country code or phone invalid. |
| `Dna.DomainService:Contact:Verification:10008` | An ownership change is already awaiting verification. |
| `Dna.DomainService:Contact:Verification:10010` | You are changing the name but the contact's e-mail is unverified. Verify it first. |
| `Dna.DomainService:Contact:10020` | The handle is shared with a domain you do not own. |
| `Dna.DomainService:Epp:10001` | The registry rejected the change. |
## PUT /api/v1/domains/contacts/update-with-handle
Points a domain's roles at handles that already exist in your account. No contact details are sent — just the handle codes.
**Request**
```json
{
"domainName": "apiname.com",
"handleItems": [
{ "contactType": "Registrant", "handle": "D-174829301847" },
{ "contactType": "Admin", "handle": "D-174830552193" },
{ "contactType": "Tech", "handle": "D-174830552193" },
{ "contactType": "Billing", "handle": "D-174830998471" }
]
}
```
**Response — 204, no body**
:::note[Supply all four roles]
Use the exact names `Registrant`, `Admin`, `Billing`, `Tech`. Check `isHandleUpdateAvailable` in the TLD catalogue — a few extensions do not support re-pointing contacts this way.
:::
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `Dna.DomainService:Domain:10007` | Domain not found or not yours. |
| `Dna.DomainService:Contact:10008` | A handle does not exist in your account. |
| `Dna.DomainService:Contact:10018` | A role was not supplied. |
| `Dna.DomainService:Contact:10026` | The handle is shared across domains in a way that cannot be re-pointed safely. Create a dedicated handle for this domain instead. |
| `Dna.DomainService:Domain:10037` | Trustee domain. |
---
# Forwarding
> Redirect a domain to another URL without running a web server, read the forward back, and remove it.
Forwarding points a domain at another URL without you running a web server. We take over the domain's DNS to do it.
:::danger[Forwarding replaces the domain's name servers]
Creating a forward switches the domain to our name servers and publishes the records needed to redirect it. **Any DNS you were running elsewhere stops being authoritative** — mail included. Deleting the forward restores the previous name servers.
If the domain has mail on it, do not use forwarding. Point the web records where you want them with the [zones API](https://www.domainnameapi.com/docs/dns-records/) instead and leave the MX records alone.
:::
## POST /api/v1/domains/forwards
Creates a forwarding record.
**Request**
```jsonc
{
"domainName": "apiname.com",
"redirectAddress": "https://www.apiname.net/landing",
"forwardType": "Standard"
}
```
| Field | Required | Notes |
| --- | --- | --- |
| `domainName` | required | No underscores; no label may start or end with a hyphen. |
| `redirectAddress` | required | Destination URL. Maximum 100 characters. |
| `forwardType` | required | `Standard` or `Frame`. Case-insensitive, and the initial letter alone is enough — see below. |
| Value | Name | Behaviour |
| --- | --- | --- |
| 1 | `Standard` | HTTP 301 permanent redirect. The browser address bar shows the destination. Correct for almost all cases, and SEO-friendly. |
| 2 | `Frame` | The destination is loaded inside a frame, so the address bar keeps showing your domain. Breaks on sites that refuse framing, and is bad for SEO. Use only when the customer specifically asks for URL masking. |
### How `forwardType` is interpreted
The same relaxed matching as [`contactType`](https://www.domainnameapi.com/docs/domains/register/#how-contacttype-is-interpreted): the numeric value first, then the initial letter, case-insensitive.
| You send | Resolves to |
| --- | --- |
| `"Standard"`, `"standard"`, `"STANDARD"`, `"s"`, `"S"` | Standard |
| `"1"` | Standard |
| `"Frame"`, `"frame"`, `"FRAME"`, `"f"`, `"F"` | Frame |
| `"2"` | Frame |
| anything else | **rejected** with `Dna.DomainService:Domain:1018` |
:::note[One deliberate difference from `contactType`]
An unrecognised `contactType` silently falls back to `Registrant`. An unrecognised `forwardType` does **not** fall back — it is rejected. With only two options, silently picking the wrong one would set up the redirect in a way you did not ask for, so `"permanent"` or `"301"` give you a clear error rather than a surprise.
:::
**Response — 204, no body**
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `DnaValidationError` | A required field is missing. |
| `Dna.DomainService:Domain:10005` | Invalid domain name, or it contains an underscore, or a label starts/ends with a hyphen. |
| `Dna.DomainService:Domain:1018` | `forwardType` could not be resolved to `Standard` or `Frame`. |
| `Dna.DomainService:Domain:1025` | A forward already exists. Delete it first, then create the new one. |
| `Dna.DomainService:Domain:1021` | Domain not yours. |
| `Dna.DomainService:DomainSale:10007` | The domain is listed for sale and uses parking records. Cancel the listing first. |
## GET /api/v1/domains/forwards · DELETE /api/v1/domains/forwards
Read or remove the forwarding record.
**GET — request and response**
```http
GET /api/v1/domains/forwards?domainName=apiname.com
{
"redirectAlias": "https://www.apiname.net/landing",
"redirectType": "Standard"
}
```
**DELETE — request**
```json
{
"domainName": "apiname.com"
}
```
Returns 204. The name servers recorded before the forward was created are restored.
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `Dna.DomainService:Domain:1017` | No forwarding configured on this domain. |
| `Dna.DomainService:Domain:1021` | Domain not yours. |
---
# Restore a deleted domain
> Recover a deleted domain while it is still in the registry's redemption period.
## POST /api/v1/domains/restore
Recovers a deleted domain from the registry's redemption period. Chargeable, and usually expensive — restore fees are set by the registry and are far higher than a renewal.
**Request**
```json
{
"domainName": "apiname.com"
}
```
**Response — 204, no body**
:::caution[Check the window before you try]
Restore only works while the domain is in the redemption period. Call `GET /api/v1/domains/info` and check that `rgpStatues` is `redemptionPeriod`. Once it moves to `pendingDelete` the domain is beyond recovery and will be released to the public.
The redemption window length per extension is `deletionRestorablePeriod` in the TLD catalogue — typically 30 days.
:::
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `Dna.DomainService:Domain:10043` | Not in the redemption period. Check `rgpStatues`. |
| `Dna.DomainService:Domain:10007` | Domain not found or not yours. |
| `Dna.DomainService:Domain:10038` | The domain has no registrant contact, which the registry requires for the restore report. Open a ticket. |
| `Dna.DomainService:Domain:10049` | No restore price configured for this extension. |
| `Dna.DomainService:Deposit:10001` | Insufficient balance. |
| `Dna.DomainService:Reseller:10001` | Balance suspended. |
---
# Registry documents
> Upload and track the documents some extensions, Turkish third-level domains in particular, require before approving a registration or ownership change.
Some extensions — Turkish third-level domains in particular — require supporting documents before the registry approves a registration or an ownership change. These endpoints submit and track them.
:::caution[You can only upload while the domain is expecting documents]
Call `GET /api/v1/domains/info` and check `status` and `statusReason` first:
| status | statusReason | Upload accepted? |
| --- | --- | --- |
| WaitingForDocument | DocumentPendingForRegistration | Yes — for the registration |
| WaitingForDocument | anything else | Yes — for an ownership change |
| WaitingForRegistration | DocumentPendingForRegistration, DocumentUnderReview or DocumentInvalid | Yes — for the registration |
| ModificationPending | — | Yes — for an ownership change |
| anything else | — | **No** — `Dna.DomainService:Domain:10055` |
:::
## POST /api/v1/domains/documents
Uploads one or more documents as Base64 and forwards each to the registry.
**Request**
| Field | Required | Notes |
| --- | --- | --- |
| `domainName` | required | |
| `documents` | required | Array, at least one entry. |
| `documents[].documentType` | required | Number or name from the table below. |
| `documents[].fileName` | required | **Must include the extension.** The extension is how we determine the expected content type. |
| `documents[].fileContent` | required | Raw Base64. **No `data:` prefix.** |
```json
{
"domainName": "apiname.com.tr",
"documents": [
{
"documentType": 1,
"fileName": "identity-card.jpg",
"fileContent": "/9j/4AAQSkZJRgABAQEAYABgAAD..."
},
{
"documentType": 3,
"fileName": "tax-certificate.pdf",
"fileContent": "JVBERi0xLjQKJcfsj6IKNSAwIG9iago8..."
}
]
}
```
**Limits**
| Limit | Value |
| --- | --- |
| Allowed formats | PDF, DOC, DOCX, ODT, JPG, JPEG, PNG |
| Maximum per file | **10 MB** |
| Maximum per request, all files | **50 MB** |
| Maximum documents under review per domain | **10** (pending plus new, combined) |
:::caution[The file extension must match the actual file]
We decode each file and inspect its real format, then require that it matches the extension you gave. Renaming a `.docx` to `.pdf` is rejected with `Dna.DomainService:Domain:10068`, and `details` tells you what the file really is. This catches the common case of a customer uploading a Word file named `.pdf`.
:::
**Response — 200**
```json
{
"uploaded": [
{
"name": "identity-card.jpg",
"size": 284119,
"mimeType": "image/jpeg",
"type": 1,
"uploadedDate": "2026-10-30T15:41:09"
}
],
"duplicates": [],
"failed": ["tax-certificate.pdf"],
"totalDocumentCount": 1,
"totalDocumentSize": 1093847
}
```
:::danger[This endpoint is partially successful by design]
Documents are processed one at a time. One failure does not abort the rest, and **HTTP 200 does not mean everything was accepted**. You must read all three arrays:
| Array | Meaning |
| --- | --- |
| `uploaded` | Stored **and** accepted by the registry. These are done. |
| `duplicates` | Skipped — a document with the same file name is already under review, or the name repeated within your request. Rename and resend if it was a different file. |
| `failed` | Skipped — storage failed, or **the registry rejected this particular file**. Retry these. |
A 200 with `uploaded: []` and entries in `failed` means nothing was accepted. Note that `totalDocumentSize` counts *everything you submitted*, including failures, while `totalDocumentCount` counts only successes.
:::
:::tip[What happens next]
Once at least one document is accepted, the domain moves to `statusReason: DocumentUnderReview`. The registry reviews it — this takes hours to days depending on the extension. Poll `GET /api/v1/domains/documents` to watch each document's status, and `GET /api/v1/domains/info` for the domain's overall state.
If a document is rejected (`status: Rejected`), upload a corrected one. The domain stays in the waiting state until the registry is satisfied.
:::
**Document types**
| Value | Name | Document |
| --- | --- | --- |
| 1 | `IdentityCard` | National identity card, both sides in one file |
| 2 | `Passport` | Passport, for foreign nationals |
| 3 | `TaxCertificate` | Tax registration certificate, for companies |
| 4 | `ActivityCertificate` | Certificate of activity or chamber registration |
| 5 | `SignatureCircular` | Signature circular |
| 6 | `AuthorizationLetter` | Letter of authority or proxy to act |
| 7 | `Petition` | Petition, e.g. a deletion request |
| 8 | `TradeRegistryGazette` | Trade registry gazette |
| 9 | `TrademarkCertificate` | Trademark registration certificate |
| 10 | `EducationCertificate` | Educational institution certificate |
| 11 | `OrganizationStatute` | Association or foundation statute |
| 12 | `GovernmentApproval` | Official body approval or ministry permit |
| 13 | `DomainOwnershipProof` | Proof of ownership: prior WHOIS, invoice, declaration |
| 14 | `PowerOfAttorney` | Power of attorney from a lawyer or representative |
| 15 | `BarAssociationCertificate` | Bar registration or licence |
| 16 | `MedicalDiplomaOrLicense` | Medical diploma or specialisation certificate |
| 17 | `MunicipalOfficialLetter` | Official signed request from the competent authority |
| 18 | `EducationInstitutionLicense` | Establishment or operating licence for a school |
| 19 | `ChamberOfCommerceCertificate` | Chamber of commerce registration letter |
| 20 | `TrademarkTransferAgreement` | Trademark transfer agreement |
| 21 | `KepAuthorization` | Registered-e-mail authority document |
| 99 | `Other` | Anything else, or a special case |
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `Dna.DomainService:Domain:10055` | The domain is not expecting documents. Check `status` and `statusReason`. |
| `Dna.DomainService:Domain:10061` | `documents` empty or missing. |
| `Dna.DomainService:Domain:10066` | An entry lacks `fileName` or `fileContent`. |
| `Dna.DomainService:Domain:10065` | `documentType` is not a valid value. |
| `Dna.DomainService:Domain:10062` | Format not allowed, or the content is unrecognisable. |
| `Dna.DomainService:Domain:10067` | Not valid Base64. The usual cause is leaving the `data:image/jpeg;base64,` prefix in. |
| `Dna.DomainService:Domain:10068` | Extension does not match the file content. |
| `Dna.DomainService:Domain:10069` | A single file exceeds 10 MB. |
| `Dna.DomainService:Domain:10064` | The request total exceeds 50 MB. Split it. |
| `Dna.DomainService:Domain:10063` | More than 10 documents would be under review. `details` gives the pending and new counts. |
| `Dna.DomainService:Epp:10001` | Every document was refused by the registry. Read `details`. |
## GET /api/v1/domains/documents
Lists the documents uploaded for a domain and their review status. Metadata only — file contents are not returned.
**Request — query string**
| Parameter | Default | Notes |
| --- | --- | --- |
| `domainName` | — | **Required.** |
| `documentTypes` | — | Comma-separated filter of names or numbers: `IdentityCard,TaxCertificate` or `1,3`. |
| `skipCount` | 0 | |
| `maxResultCount` | 10 | |
```http
GET /api/v1/domains/documents?domainName=apiname.com.tr
```
**Response — 200**
```json
{
"totalCount": 2,
"items": [
{
"name": "identity-card.jpg",
"type": 1,
"status": 3,
"operationType": 1,
"uploadedDate": "2026-10-30T15:41:09"
},
{
"name": "tax-certificate.pdf",
"type": 3,
"status": 2,
"operationType": 1,
"uploadedDate": "2026-10-30T15:52:33"
}
]
}
```
**Document status**
| Value | Name | What it means for you |
| --- | --- | --- |
| 1 | `Waiting` | A document is expected but none has been sent. Upload one. |
| 2 | `Pending` | Sent, awaiting registry review. Wait. |
| 3 | `Approved` | Accepted. Nothing more to do for this document. |
| 4 | `Rejected` | **Upload a corrected document.** The domain stays blocked until the registry is satisfied. |
| 5 | `Expired` | The document's validity window passed. Upload a current one. |
| 6 | `Cancelled` | The surrounding application or ownership change was cancelled. |
`operationType`: `1` registration · `2` ownership change · `3` deletion.
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `Dna.DomainService:Domain:10007` | Domain not found or not yours. |
| `Dna.DomainService:Domain:10065` | An entry in `documentTypes` is not a recognised type. |
---
# Name servers
> Change which name servers answer for a domain, and how an active DNSSEC setup affects the change.
This section is about **delegation** — which name servers answer for the domain — and DNSSEC. For editing the actual records inside a zone (A, MX, TXT and so on), see [DNS records](https://www.domainnameapi.com/docs/dns-records/).
:::note[These all live under the domain path]
DNS, DNSSEC and zone management are not separate services — every path in this section and in DNS records sits under `/api/v1/domains/`, and in the interactive API explorer the DNS and DNSSEC operations are listed together with the rest of the **Domain** group:
```text
/api/v1/domains domain operations (Domains)
/api/v1/domains/dns name servers (this section)
/api/v1/domains/dns/host host / glue records (this section)
/api/v1/domains/dns/dnssec DS records (this section)
/api/v1/domains/zones DNS records (DNS records)
```
They are split into separate chapters here because they are separate jobs, not because they are separate parts of the API. Your API key and the domain's ownership rules apply identically across all of them.
:::
:::note[Which section do you need?]
| You want to… | Use |
| --- | --- |
| Point the domain at someone else's name servers | `PUT /domains/dns/name-server` — this section |
| Point the domain at our name servers | `PUT /domains/dns/name-server`, or `POST /domains/zones/apply` |
| Run your own name servers under the domain (`ns1.apiname.com`) | `POST /domains/dns/host` — this section |
| Add an A, MX, TXT, CNAME record | [DNS records](https://www.domainnameapi.com/docs/dns-records/) |
| Enable DNSSEC | `POST /domains/dns/dnssec` — this section |
:::
:::caution[One rule applies to every call in this section]
No DNS change is accepted while the domain is waiting for registry documents. You get `Dna.DomainService:Domain:10070`. Resolve the [document flow](https://www.domainnameapi.com/docs/domains/documents/) first. The host endpoints additionally require the domain to be active.
:::
## Changing name servers
### PUT /api/v1/domains/dns/name-server
Replaces the domain's name servers. This is a wholesale replacement, not an add or remove — send the complete list you want the domain to end up with.
**Request**
| Field | Required | Notes |
| --- | --- | --- |
| `domainName` | required | |
| `nameServers` | required | The complete new set. Count must satisfy the TLD's minimum and maximum — usually 2 to 13. No duplicates. |
| `dnssecMode` | conditional | **Required when DNSSEC is active on the domain.** See below. Defaults to `0`, which blocks the change. |
**Move to a third-party DNS provider**
```json
{
"domainName": "apiname.com",
"nameServers": ["ns1.otherhost.com", "ns2.otherhost.com"]
}
```
**Move to our DNS, so you can use the zones API**
```json
{
"domainName": "apiname.com",
"nameServers": ["tr.apiname.com", "eu.apiname.com"]
}
```
**Response — 204, no body**
:::danger[Set up the new DNS before you switch]
The moment resolvers pick up the new delegation, the old name servers stop being authoritative. If the new ones do not yet have your records, the website and e-mail go down.
Create the zone and all its records at the new provider **first**, verify them, then change the delegation. Expect up to **48 hours** for the change to reach every resolver worldwide on a first-time switch.
:::
#### dnssecMode — only relevant when DNSSEC is active
Changing name servers on a DNSSEC-signed domain breaks it unless the new provider publishes keys matching the published DS records. We refuse to do that silently, so you have to state your intent.
| Value | Name | Behaviour |
| --- | --- | --- |
| 0 | `Block` | **Default.** The change is refused with `Dna.DomainService:Dnssec:10010`. This is deliberate — it stops you breaking the domain by accident. |
| 1 | `KeepDnssec` | You confirm the new provider already publishes keys matching the existing DS records. The DS records stay and the name servers change. **If you are wrong, the domain becomes unresolvable for validating resolvers.** |
| 2 | `DisableDnssec` | The safe option. All DS records are removed from the registry first, then the name servers change. If removal fails, the name servers are left alone. |
:::tip[Recommended DNSSEC-safe move]
Unless you have deliberately arranged key continuity with the new provider, use `"dnssecMode": 2`. Re-enable DNSSEC afterwards with the new provider's DS records. Domains lose DNSSEC protection briefly but never become unresolvable.
:::
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `Dna.DomainService:Domain:10007` | Domain not found or not yours. |
| `Dna.DomainService:Domain:10044` | Invalid domain name. |
| `Dna.DomainService:Domain:10070` | The domain is waiting for registry documents. |
| `Dna.DomainService:Dns:10005` | `nameServers` is empty. |
| `Dna.DomainService:Dns:10022` | Too few or too many for this TLD. Check the catalogue. |
| `Dna.DomainService:Dns:10013` | Duplicate entry in the list. |
| `Dna.DomainService:Dns:10025` | The change would drop below the TLD's minimum. |
| `Dna.DomainService:Dns:10016` | A name server under this domain needs a glue IP. Create the host record first — see below. |
| `Dna.DomainService:Dns:10026` | IPv6 glue not supported by this TLD. |
| `Dna.DomainService:Dnssec:10010` | DNSSEC is active and `dnssecMode` is `0`. Pick 1 or 2. |
| `Dna.DomainService:Dnssec:10011` | You chose `DisableDnssec` but the DS records could not be removed. Nothing was changed. `details` carries the registry's message. |
| `Dna.DomainService:Dnssec:10012` | DS removal is queued for registry approval. Retry the name-server change once it completes. |
| `Dna.DomainService:DomainSale:10007` | The domain is listed for sale and uses parking records. |
| `Dna.DomainService:Epp:10001` | The registry rejected the change. |
---
# Host (glue) records
> Create, update and delete host (glue) records for name servers that live under the domain they serve, and the two registry models behind them.
A **host record** is needed when you run a name server that lives under the domain it serves — `ns1.apiname.com` answering for `apiname.com`. Resolvers cannot look that up without a circular dependency, so the registry publishes its IP addresses as *glue*.
:::note[You probably do not need these]
Host records are only for running your own name servers under the domain. If you point at a third party's name servers, or at `tr.apiname.com` / `eu.apiname.com`, you need no host records at all.
:::
Two terms you will meet in the errors:
- **In-bailiwick** — the host name is a subdomain of the domain it serves. Most registries only accept glue for in-bailiwick hosts. Anything else gives `Dna.DomainService:Dns:10019`.
- **Host object support** — registries differ in how they model name servers. The catalogue field `isHostObjectAccepted` tells you, and `isGlueRecordAllowed` says whether glue is accepted at all.
## The two models, and why it matters to you
There are two ways a registry can represent a name server that lives under your domain. Which one applies changes what you get back from `GET /domains/info`, so it is worth understanding before you build a UI around it.
| `isHostObjectAccepted` | What happens to `ns1.apiname.com` |
| --- | --- |
| **true** | It becomes a **host object** — an independent record at the registry with its own name and IP addresses. It can be created, renamed, re-addressed and deleted on its own, and it can be shared by several domains. |
| **false** | **No host object is created.** The name server stays attached to the domain as a **glue record**: the name and its IP travel with the domain's own record rather than existing separately. |
:::note[Where you will see each]
`.tr` and `.ge` are typical examples of registries where `isHostObjectAccepted` is **false** — your child name server never appears as a standalone host, only as a glue record on the domain.
An extension may support **both** models. When it does, **the host object takes priority** — we create the host object and manage the name server through it.
:::
:::caution[What this changes in practice]
- **When `isHostObjectAccepted` is true**, the host endpoints below behave exactly as described: create once, reuse across domains, delete when no longer referenced.
- **When it is false**, the host is not an independent object, so there is nothing to share between domains and nothing to delete separately. Removing the name server from the domain's delegation removes the glue with it. Each domain carries its own copy of the name and IP.
- **Do not assume a host you created on one domain is visible on another** unless the extension uses host objects. Read `isHostObjectAccepted` from the catalogue rather than assuming.
If neither model is available for an extension, you get `Dna.DomainService:Dns:10018` — "A valid host type could not be determined for this TLD".
:::
## POST /api/v1/domains/dns/host
Creates a host record with its IP addresses.
**Request**
```json
{
"domainName": "apiname.com",
"hostName": "ns1.apiname.com",
"ipAddresses": [
{ "ipAddress": "203.0.113.10", "ipVersion": "v4" },
{ "ipAddress": "2001:db8::10", "ipVersion": "v6" }
]
}
```
| Field | Required | Notes |
| --- | --- | --- |
| `domainName` | required | Maximum 63 characters. |
| `hostName` | required | Full host name, maximum 100 characters. Normally must be a subdomain of `domainName`. |
| `ipAddresses` | required | At least one. No duplicates. |
| `ipAddresses[].ipAddress` | required | IPv4 or IPv6 literal. |
| `ipAddresses[].ipVersion` | required | `v4` or `v6`. Case does not matter. |
**Response — 204, no body**
:::tip[The order to do this in]
1. `POST /domains/dns/host` — create `ns1.apiname.com` with its IP.
2. Repeat for `ns2.apiname.com`.
3. `PUT /domains/dns/name-server` — delegate the domain to them.
Doing it the other way round fails with `Dna.DomainService:Dns:10016`, because the delegation needs the glue to exist first.
:::
## PUT /api/v1/domains/dns/host · DELETE /api/v1/domains/dns/host
Rename a host and/or replace its IP addresses, or delete it.
**PUT — change the IP addresses**
```json
{
"domainName": "apiname.com",
"hostName": "ns1.apiname.com",
"ipAddresses": [
{ "ipAddress": "203.0.113.20", "ipVersion": "v4" }
]
}
```
**PUT — rename and re-address in one call**
```json
{
"domainName": "apiname.com",
"hostName": "ns1.apiname.com",
"newHostName": "dns1.apiname.com",
"ipAddresses": [
{ "ipAddress": "203.0.113.20", "ipVersion": "v4" }
]
}
```
`ipAddresses` is the **complete replacement set**. Omit `newHostName` to keep the current name.
**DELETE**
```json
{
"domainName": "apiname.com",
"hostName": "ns1.apiname.com"
}
```
**Response — 204, no body**
:::caution[A host in use cannot be deleted]
If the host is still serving as a name server — for this domain or any other — deletion is refused with `Dna.DomainService:Dns:10024`. Re-delegate the affected domains with `PUT /domains/dns/name-server` first, then delete the host.
:::
**Errors — all host endpoints**
| Code | Meaning and fix |
| --- | --- |
| `Dna.DomainService:Domain:10044` | Invalid domain or host name. |
| `Dna.DomainService:Domain:10007` | Domain not found or not yours. |
| `Dna.DomainService:Domain:10016` | The domain is not active. |
| `Dna.DomainService:Domain:10070` | Waiting for registry documents. |
| `Dna.DomainService:Dns:10015` | The same IP appears twice in `ipAddresses`. |
| `Dna.DomainService:Dns:10006` | `ipAddresses` is empty. |
| `Dna.DomainService:Dns:10007` | Malformed IPv4 address. |
| `Dna.DomainService:Dns:10008` | Malformed IPv6 address. |
| `Dna.DomainService:Dns:10014` | `ipVersion` is not `v4` or `v6`. |
| `Dna.DomainService:Dns:10026` | This TLD does not accept IPv6 glue. Send only v4. |
| `Dna.DomainService:Dns:10012` | `hostName` is empty. |
| `Dna.DomainService:Dns:10019` | The host is not a subdomain of the domain (not in-bailiwick). |
| `Dna.DomainService:Dns:10018` | We could not determine how this TLD models name servers. Open a ticket. |
| `Dna.DomainService:Dns:10021` | Create: the host already exists on this domain. |
| `Dna.DomainService:Dns:10020 / :10004` | Edit or delete: the host does not exist. |
| `Dna.DomainService:Dns:10017` | Glue records are not allowed for this TLD. |
| `Dna.DomainService:Dns:10023 / :10024` | The host cannot be deleted in its current state, or is still in use. |
| `Dna.DomainService:Domain:Dns:Host:10001` | Registry-side host conflict. |
| `Dna.DomainService:Domain:Dns:Host:10002` | The registry does not know this host. |
---
# DNSSEC
> Publish, read and remove DS records at the registry, in the order that keeps the domain online.
DNSSEC cryptographically signs your DNS so resolvers can detect tampering. You generate the keys at your DNS provider; this API publishes the resulting **DS records** at the registry.
:::caution[Get the order right or the domain goes dark]
DNSSEC is the easiest way to take a working domain offline. The rule is simple: **the keys must be live in DNS before the DS record is published at the registry, and the DS record must be removed before the keys go away.**
Enabling: publish keys at your DNS provider → then `POST /dnssec` here.\
Disabling or migrating: `POST /dnssec/disable` here → wait for confirmation → then change DNS.
:::
## GET /api/v1/domains/dns/dnssec
Current DNSSEC state, the published DS records, and what this extension accepts. **Call this before any write** — it tells you which algorithms and digest types are permitted.
**Request**
```http
GET /api/v1/domains/dns/dnssec?domainName=apiname.com
```
**Response — 200**
```json
{
"domainName": "apiname.com",
"isDnssecAvailable": true,
"status": 2,
"delegationSigned": true,
"maxSigLife": null,
"lastChangedAt": "2026-10-28T09:14:52",
"dsRecords": [
{
"keyTag": 12345,
"algorithm": 13,
"digestType": 2,
"digest": "49FD46E6C4B45C55D4AC69CBD3CD34AC1AFE51DE7D4C6F9CFBF5F8A1B2C3D4E5",
"status": 1,
"isAlgorithmNotRecommended": false,
"createdAt": "2026-10-28T09:12:03",
"activatedAt": "2026-10-28T09:14:52",
"removedAt": null
}
],
"allowedAlgorithms": [8, 13, 14, 15, 16],
"allowedDigestTypes": [2, 4],
"maxDsRecordCount": 8
}
```
| Field | How to use it |
| --- | --- |
| `isDnssecAvailable` | If `false`, every write here fails with `Dnssec:10001`. Hide the DNSSEC option in your UI. |
| `delegationSigned` | **The authoritative "is it live" signal.** `status` can lag behind registry reality; this reflects what is actually published. |
| `allowedAlgorithms` | The algorithm numbers you may send. Build your dropdown from this, not from a hard-coded list — it varies by extension. |
| `allowedDigestTypes` | Same for digest types. |
| `maxDsRecordCount` | Maximum DS records. Default 8. Relevant during key rollover, when you briefly need two. |
| `dsRecords[].isAlgorithmNotRecommended` | The algorithm works but is discouraged by current standards. Plan to migrate. |
**status**
| Value | Name | Meaning |
| --- | --- | --- |
| 0 | `Unsigned` | No DS record at the registry. DNSSEC is off. |
| 1 | `PendingEnable` | Add request sent, awaiting registry confirmation. |
| 2 | `Signed` | At least one DS record is live. |
| 3 | `PendingDisable` | Removal sent, awaiting confirmation. |
| 4 | `Error` | The last DNSSEC operation failed. Read the DS records' individual statuses. |
**dsRecords\[\].status**
| Value | Name | Meaning |
| --- | --- | --- |
| 0 | `Pending` | Submitted, not confirmed. |
| 1 | `Active` | Live at the registry. |
| 2 | `Removing` | Removal in flight. |
| 3 | `Removed` | Gone. Excluded from this list. |
| 4 | `Failed` | The registry rejected it. |
### Algorithms and digest types
Allowed values vary by extension — always read them from this endpoint. For reference:
| Value | Algorithm | Status |
| --- | --- | --- |
| 8 | `RSA/SHA-256` | **Recommended** |
| 13 | `ECDSA P-256/SHA-256` | **Recommended** — the usual modern choice |
| 14 | `ECDSA P-384/SHA-384` | Recommended |
| 15 | `Ed25519` | Recommended |
| 16 | `Ed448` | Recommended |
| 5, 7 | `RSA/SHA-1 variants` | Accepted but discouraged |
| 10 | `RSA/SHA-512` | Accepted but discouraged |
| 1, 3, 6, 12 | `MD5, DSA, GOST` | **Rejected** — never accepted, even if an extension lists them |
| Value | Digest type | Required `digest` length |
| --- | --- | --- |
| 1 | `SHA-1` | **40** hex characters |
| 2 | `SHA-256` | **64** hex characters — the usual choice |
| 4 | `SHA-384` | **96** hex characters |
| 3 | `GOST` | **Rejected** |
:::note[Digest formatting is forgiving, length is not]
We strip whitespace and uppercase the value, so `"ab cd ef"` and `"ABCDEF"` are the same. But it must then be pure hexadecimal and **exactly** the length required by the `digestType` you declared. Mismatched length is the most common DNSSEC error — usually from sending a SHA-256 digest while declaring `digestType: 1`.
:::
## POST /api/v1/domains/dns/dnssec
Publishes one or more DS records at the registry, enabling DNSSEC.
**Request**
```json
{
"domainName": "apiname.com",
"records": [
{
"keyTag": 12345,
"algorithm": 13,
"digestType": 2,
"digest": "49FD46E6C4B45C55D4AC69CBD3CD34AC1AFE51DE7D4C6F9CFBF5F8A1B2C3D4E5"
}
]
}
```
| Field | Required | Notes |
| --- | --- | --- |
| `domainName` | required | |
| `records` | required | At least one entry. |
| `records[].keyTag` | required | 0–65535. From your DNS provider. |
| `records[].algorithm` | required | Must be in `allowedAlgorithms`. |
| `records[].digestType` | required | Must be in `allowedDigestTypes`. |
| `records[].digest` | required | Hex, exact length for the digest type. |
**Response — 200**
```json
{
"items": [
{
"keyTag": 12345,
"operationType": 0,
"isSuccess": true,
"isPending": true,
"resultMessage": "Command completed successfully; action pending"
}
]
}
```
:::tip[`isPending: true` is a success, not a problem]
Many registries queue DNSSEC changes. `isSuccess: true` with `isPending: true` means the registry accepted your request and will apply it shortly. **Do not resubmit** — that produces `Dna.DomainService:Dnssec:10006` ("already exists").
Poll `GET /dnssec` until `delegationSigned` becomes `true`.
:::
`operationType`: `0` Add · `1` Remove · `2` RemoveAll · `3` Sync.
## DELETE /api/v1/domains/dns/dnssec · POST /api/v1/domains/dns/dnssec/disable
Remove one DS record, or all of them.
**DELETE — remove one record**
```json
{
"domainName": "apiname.com",
"keyTag": 12345,
"algorithm": 13,
"digestType": 2,
"digest": "49FD46E6C4B45C55D4AC69CBD3CD34AC1AFE51DE7D4C6F9CFBF5F8A1B2C3D4E5"
}
```
The record is identified by its **full value**, not by an ID. All four fields must match exactly — copy them straight from `GET /dnssec`. Any mismatch gives `Dna.DomainService:Dnssec:10007`.
The fields travel in the **request body** of the `DELETE`. Make sure your HTTP client sends a body with `DELETE` requests; some drop it unless told otherwise.
**Response — 200, DELETE**
```json
{
"keyTag": 12345,
"operationType": 1,
"isSuccess": true,
"isPending": false,
"resultMessage": "Command completed successfully"
}
```
**POST /dnssec/disable — remove all records**
```json
{
"domainName": "apiname.com"
}
```
**Response — 200, disable**
```json
{
"keyTag": null,
"operationType": 2,
"isSuccess": true,
"isPending": false,
"resultMessage": "Command completed successfully"
}
```
`operationType` says what was done: `1` one record removed, `2` all records removed. As when adding, `isSuccess: true` with `isPending: true` means the registry accepted the removal and will finish it later. Poll `GET /dnssec` rather than sending it again.
:::tip[Key rollover without downtime]
1. Generate the new key at your DNS provider and publish it alongside the old one.
2. `POST /dnssec` with the **new** DS record. Both are now live — this is why `maxDsRecordCount` is more than one.
3. Wait for `GET /dnssec` to show the new record as `Active`, then wait one more TTL cycle.
4. `DELETE /dnssec` with the **old** DS record.
5. Remove the old key at your DNS provider.
Never remove the old DS record before the new one is active.
:::
**Errors — all DNSSEC endpoints**
| Code | Meaning and fix |
| --- | --- |
| `Dna.DomainService:Dnssec:10001` | This extension does not support DNSSEC. |
| `Dna.DomainService:Dnssec:10002` | `keyTag` outside 0–65535. |
| `Dna.DomainService:Dnssec:10003` | Algorithm not permitted. Read `allowedAlgorithms`. |
| `Dna.DomainService:Dnssec:10004` | Digest type not permitted. Read `allowedDigestTypes`. |
| `Dna.DomainService:Dnssec:10005` | **The most common one.** The digest is not hex, or its length does not match the declared `digestType`. `details` states the expected length. |
| `Dna.DomainService:Dnssec:10006` | That DS record already exists, or you sent it twice in one request. |
| `Dna.DomainService:Dnssec:10007` | Delete: no record matches all four fields. Copy them from `GET /dnssec`. |
| `Dna.DomainService:Dnssec:10008` | Would exceed `maxDsRecordCount`. Remove an old record first. |
| `Dna.DomainService:Dnssec:10013` | The registry returned no DS record. Your local records were preserved rather than wiped. Check `GET /dnssec`. |
| `Dna.DomainService:Domain:10007` | Domain not found or not yours. |
| `Dna.DomainService:Domain:10070` | Waiting for registry documents. |
| `Dna.DomainService:Epp:10001` | The registry rejected the operation. |
---
# DNS records
> How zones on our name servers work: record sets, zone creation on first use, publishing, propagation and name matching.
Manage the contents of a DNS zone hosted on our name servers — A, AAAA, CNAME, MX, TXT, SRV, CAA and the rest. For delegation and glue, see [Name servers](https://www.domainnameapi.com/docs/name-servers/).
## Three things to understand first
### 1 · Records are grouped by name and type
A **record set** is everything sharing the same name and type. All values in a set share one TTL. There is no per-record TTL and no record ID — a record is identified by its **value**.
So `www` with two A values is *one* record set with two values, not two records:
```text
www.apiname.com. A 3600 203.0.113.10
203.0.113.11 ← same set, same TTL
```
This is why `DELETE` asks you for the value you want gone rather than an ID, and why `PUT` replaces an entire set.
### 2 · The zone is created on first use
There is no "create zone" call. The first successful `POST` for a domain creates the zone, seeded with a default SOA record and our name servers. A `GET` on a domain with no zone returns an **empty array** — not an error.
### 3 · Writing a record is not enough to make it resolve
:::danger[The step everyone forgets]
Records only answer queries if the domain is **delegated to our name servers**. Until then your records sit in our system answering nothing.
1. `POST /domains/zones` — write the records.
2. `POST /domains/zones/apply` — **delegate the domain to us.**
3. Wait for the parent zone's TTL — up to 48 hours on a first switch.
4. Individual record changes after that propagate in one record TTL.
:::
### How long until changes are live?
| Change | Visible when |
| --- | --- |
| Writing a record in our DNS | **Immediately.** Served by our name servers as soon as the call returns. No publication queue. |
| Changing delegation (`/apply`) | Seconds at the registry, but resolvers cache the old name servers for the parent zone's TTL — **1 to 48 hours** depending on the extension. |
| Changing a record in an already-delegated zone | One **record TTL**, which you control. |
| Adding a name that did not exist before | Up to **5 minutes** for resolvers that already looked it up and cached the "does not exist" answer. |
:::tip[Planning a change with no downtime]
1. Lower the TTL on the record to `300` and wait one *old* TTL.
2. Make the real change. It now propagates in 5 minutes.
3. Verify, then raise the TTL back to `3600` or higher.
:::
### How we match the name you send
Names are normalised to the full form. For zone `apiname.com`:
| You send | Record created at |
| --- | --- |
| `""` or `"@"` | `apiname.com.` — the apex |
| `"www"` | `www.apiname.com.` |
| `"www.apiname.com"` | `www.apiname.com.` |
| `"mail.eu"` | `mail.eu.apiname.com.` |
| `"örnek"` | `xn--rnek-hra.apiname.com.` — converted automatically |
When matching a **value** for update or delete, we are forgiving: extra whitespace and a trailing dot are ignored, Unicode host names are converted, and matching is case-insensitive for host-name-bearing types. `TXT` and `CAA` values are case-*sensitive*, but surrounding quotes are ignored — so you can send `v=spf1 -all` or `"v=spf1 -all"` and either matches.
---
# Manage DNS records
> Read, add, update and delete record sets, the value format of every record type, and how to point a domain at our name servers.
## GET /api/v1/domains/zones
Reads every record set in the zone.
**Request**
```http
GET /api/v1/domains/zones?domainName=apiname.com
```
**Response — 200**
```json
[
{
"name": "apiname.com.",
"type": "SOA",
"ttl": 3600,
"changeType": "",
"records": [
{ "content": "tr.apiname.com. hostmaster.apiname.com. 2026103001 86400 7200 1209600 300",
"disabled": false }
]
},
{
"name": "apiname.com.",
"type": "A",
"ttl": 3600,
"changeType": "",
"records": [
{ "content": "203.0.113.10", "disabled": false }
]
},
{
"name": "apiname.com.",
"type": "MX",
"ttl": 3600,
"changeType": "",
"records": [
{ "content": "10 mail1.apiname.com.", "disabled": false },
{ "content": "20 mail2.apiname.com.", "disabled": false }
]
},
{
"name": "www.apiname.com.",
"type": "CNAME",
"ttl": 3600,
"changeType": "",
"records": [
{ "content": "apiname.com.", "disabled": false }
]
}
]
```
:::note[An empty array means the zone does not exist yet]
`[]` is not an error. Create the first record with `POST` and the zone is created for you. Use this to decide whether to show "set up DNS" or the record editor.
:::
Names come back in full form with a trailing dot. `changeType` is empty on reads — ignore it.
## POST /api/v1/domains/zones
Adds one or more values to a record set. Existing values in the same set are **kept** — this adds, it does not replace.
**Request — `domainName` in the query string, body as below**
| Field | Required | Notes |
| --- | --- | --- |
| `zoneStruct.name` | varies | Subdomain label or full name. `""` or `"@"` for the apex. **Required for CNAME.** |
| `zoneStruct.type` | required | Record type in **uppercase**. `A` works, `a` does not. |
| `zoneStruct.ttl` | required | 1 to 86400 seconds. `3600` is a sensible default; `300` while making changes. |
| `zoneStruct.contents` | required | Array of values to add to the set. |
**Apex A record**
```http
POST /api/v1/domains/zones?domainName=apiname.com
{
"zoneStruct": {
"name": "@",
"type": "A",
"ttl": 3600,
"contents": ["203.0.113.10"]
}
}
```
**www as a CNAME to the apex**
```json
{
"zoneStruct": {
"name": "www",
"type": "CNAME",
"ttl": 3600,
"contents": ["apiname.com"]
}
}
```
**Two mail servers in one call**
```json
{
"zoneStruct": {
"name": "@",
"type": "MX",
"ttl": 3600,
"contents": [
"10 mail1.apiname.com",
"20 mail2.apiname.com"
]
}
}
```
**SPF**
```json
{
"zoneStruct": {
"name": "@",
"type": "TXT",
"ttl": 3600,
"contents": ["v=spf1 include:_spf.google.com -all"]
}
}
```
**DMARC**
```json
{
"zoneStruct": {
"name": "_dmarc",
"type": "TXT",
"ttl": 3600,
"contents": ["v=DMARC1; p=quarantine; rua=mailto:dmarc@apiname.com"]
}
}
```
**CAA — restrict which CA may issue certificates**
```json
{
"zoneStruct": {
"name": "@",
"type": "CAA",
"ttl": 3600,
"contents": ["0 issue \"letsencrypt.org\""]
}
}
```
**Response — 204, no body**
### Record types and their value format
| Type | Value format | Example | Notes |
| --- | --- | --- | --- |
| A | IPv4 address | `203.0.113.10` | An IPv6 value here is rejected. |
| AAAA | IPv6 address | `2001:db8::1` | An IPv4 value here is rejected. |
| CNAME | Host name | `apiname.com` | **`name` must not be empty or `@`** — a CNAME at the apex is invalid DNS. Use `ALIAS` instead. An IP value is rejected. |
| ALIAS | Host name | `apiname.com` | **Use this for a CNAME-like record at the apex.** It resolves to the target's address without breaking the other apex records. |
| MX | `priority host` | `10 mail.apiname.com` | Two fields, space-separated. Priority must be a number; lower wins. The host must not be an IP. |
| TXT | Free text | `v=spf1 -all` | Send it unquoted — quotes are added for you. |
| CAA | `flag tag "value"` | `0 issue "letsencrypt.org"` | **Exactly three** space-separated fields, or it is rejected. |
| SRV | `priority weight port host` | `10 5 443 sip.apiname.com` | Four fields. The name is conventionally `_service._proto`. |
| PTR | Host name | `host.apiname.com` | Reverse lookups. |
| TLSA, NAPTR, CERT, DNAME, LOC, SSHFP and others | Per the relevant standard | — | Accepted and validated by the DNS server. A syntax problem surfaces as `ZoneClient:10008`. |
| SOA | Full SOA string | — | Created with the zone. Only change it if you know exactly why. |
| DS, DNSKEY, RRSIG, NSEC | — | — | **Do not manage DNSSEC here.** Use [the DNSSEC endpoints](https://www.domainnameapi.com/docs/name-servers/dnssec/), which publish at the registry. |
:::caution[Name servers: use the delegation endpoint, not this one]
To change which name servers answer for the domain, use `PUT /api/v1/domains/dns/name-server`. That is the registry-level operation and the only one that has any effect on delegation. The zones endpoint is for zone *contents* — A, MX, TXT, CNAME and so on.
:::
:::caution[You cannot have a CNAME alongside other records at the same name]
This is a DNS rule, not ours. If `www` has a CNAME, it cannot also have an A record. And nothing can have a CNAME at the apex — that is what `ALIAS` is for. A mail-enabled domain must have an A or ALIAS at the apex, never a CNAME, or mail delivery breaks.
:::
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `ZoneClientValidationError` | A CNAME was sent without a `name`. CNAMEs can only exist on subdomains. |
| `ZoneClient:10002` | An `A` record's value is not a valid IPv4 address. |
| `ZoneClient:10003` | An `AAAA` record's value is not a valid IPv6 address. |
| `ZoneClient:10004` | The record name is required and cannot start with `@`. |
| `ZoneClient:10005` | A `CAA` value is not three space-separated fields. `details` shows the correct format. |
| `ZoneClient:10008` | The DNS server rejected the value's syntax. Check it against the record type's specification. |
| `ZoneClient:10009` | An `MX` priority is not a number. |
| `ZoneClient:10010` | A `CNAME` or `MX` value is an IP address. These require host names. |
| `Dna.DomainService:Zone:10001` | That exact value already exists in the set, or you sent it twice. Nothing was changed. |
| `ZoneClient:10001` | The DNS service is temporarily unreachable. Retry shortly. |
| `Dna.DomainService:Domain:10007` | Domain not found or not yours. |
## PUT /api/v1/domains/zones
Replaces a record set. **Every existing value in the set is discarded** and replaced with what you send.
**Request — query string carries both the domain and the current record name**
```http
PUT /api/v1/domains/zones?domainName=apiname.com&recordName=www
{
"zoneStruct": {
"name": "www",
"type": "A",
"ttl": 300,
"contents": ["203.0.113.50"]
}
}
```
This replaces every A value at `www` with the single new address and drops the TTL to 300.
| Parameter | Required | Notes |
| --- | --- | --- |
| `domainName` | required | Query string. |
| `recordName` | required | Query string. The **current** name of the set. |
| `zoneStruct` | required | Body. The desired end state. |
**Renaming a record set**
Send a different `zoneStruct.name` from `recordName`. The old set is removed and the values appear under the new name. Values already present at the destination are preserved rather than silently overwritten.
```http
PUT /api/v1/domains/zones?domainName=apiname.com&recordName=blog
{
"zoneStruct": {
"name": "news",
"type": "CNAME",
"ttl": 3600,
"contents": ["apiname.com"]
}
}
```
**Response — 204, no body**
:::caution[You cannot change a record's type here]
The set is located using `recordName` plus the `type` in your body, so the type is used for both lookup and result. To change a record from, say, CNAME to A: `DELETE` the old value, then `POST` the new one.
:::
:::note[Adding versus replacing]
To **add** a second IP to `www`, use `POST` — it merges. Using `PUT` with one value removes the other IP. This is the most common accident in this section.
:::
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `ZoneClient:10006` | The zone does not exist. Create a record with `POST` first. |
| `ZoneClient:10007` | No record set matches `recordName` plus that type. |
| `Dna.DomainService:Zone:10001` | A value repeats within `contents`, or already exists at the destination name. |
## DELETE /api/v1/domains/zones
Deletes **one value** from a record set. When it was the last value, the whole set is removed.
**Request**
```http
DELETE /api/v1/domains/zones?domainName=apiname.com
{
"name": "www.apiname.com",
"recordType": "A",
"record": "203.0.113.11"
}
```
| Field | Required | Notes |
| --- | --- | --- |
| `name` | required | The record name. **Must belong to this zone** — the zone itself or a subdomain of it. |
| `recordType` | required | Uppercase. |
| `record` | required | The exact value to remove. Whitespace and trailing dots are ignored when matching. |
**Response — 204, no body**
:::note[Removing one of several values]
If `www` has two A values and you delete one, the other stays. Delete both and the set disappears entirely. There is no "delete the whole set" call — delete each value, or use `PUT` to replace the set with what you want.
:::
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `ZoneClient:10011` | `name` does not belong to this zone. `details` shows the expected format. Note that a name merely *containing* the zone — `apiname.com.example.net` — is correctly rejected. |
| `ZoneClient:10006` | The zone does not exist. |
| `ZoneClient:10007` | No such record set, or no value matching `record`. Read the zone with `GET` and copy the value exactly. |
## POST /api/v1/domains/zones/apply
Publishes the zone by delegating the domain to our name servers. This is the step that makes your records actually resolve.
**Request**
```http
POST /api/v1/domains/zones/apply?domainName=apiname.com
```
**Response — delegation was changed**
```json
{
"nameServersChanged": true,
"previousNameServers": ["ns1.otherhost.com", "ns2.otherhost.com"],
"currentNameServers": ["tr.apiname.com", "eu.apiname.com"],
"systemNameServers": ["tr.apiname.com", "eu.apiname.com"]
}
```
**Response — already delegated, nothing to do**
```json
{
"nameServersChanged": false,
"previousNameServers": ["tr.apiname.com", "eu.apiname.com"],
"currentNameServers": ["tr.apiname.com", "eu.apiname.com"],
"systemNameServers": ["tr.apiname.com", "eu.apiname.com"]
}
```
| Field | How to use it |
| --- | --- |
| `nameServersChanged` | `false` means the domain was already on our name servers. `true` means you just changed delegation and **propagation has started** — warn the customer about the wait. |
| `previousNameServers` | What the domain used before. **Log this** — it is your only record of the old setup if you need to revert. |
| `currentNameServers` | What it uses now. |
:::tip[Safe to call repeatedly]
Calling it when the domain is already delegated does nothing and returns `nameServersChanged: false`. You can safely call it after every zone edit as a belt-and-braces measure.
:::
:::danger[This replaces the delegation entirely]
The comparison is exact. A domain using our two name servers *plus* a third is rewritten down to just our two. And everything the previous name servers were serving — mail included — stops being authoritative once resolvers catch up.
**Recreate your records in the zone first, then call this.**
:::
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `Dna.DomainService:Domain:10007` | Domain unknown, not yours, or deleted. |
| `Dna.DomainService:Dns:10003` | The domain has no name servers at all. Set them with `PUT /domains/dns/name-server` first. |
| `Dna.DomainService:Domain:10070` | Waiting for registry documents. |
| `Dna.DomainService:Dnssec:10010` | DNSSEC is active. Disable it first, or use `PUT /domains/dns/name-server` with `dnssecMode`. |
| `Dna.DomainService:DomainSale:10007` | The domain is listed for sale and uses parking records. |
| `Dna.DomainService:Epp:10001` | The registry rejected the delegation change. |
---
# Worked example: moving a live site to our DNS
> Step by step: move a live website and Google Workspace mail to our DNS without an outage.
A domain currently hosted elsewhere, with a website and Google Workspace mail. The goal is to move DNS without an outage.
1. **Record what exists.** Read the current zone at the old provider. You need every A, CNAME, MX and TXT record — especially the mail ones.
2. **Recreate the web records.**
```http
POST /zones?domainName=apiname.com
{"zoneStruct":{"name":"@","type":"A","ttl":3600,"contents":["203.0.113.10"]}}
POST /zones?domainName=apiname.com
{"zoneStruct":{"name":"www","type":"CNAME","ttl":3600,"contents":["apiname.com"]}}
```
3. **Recreate the mail records.** Getting these wrong is what takes mail down.
```http
POST /zones?domainName=apiname.com
{"zoneStruct":{"name":"@","type":"MX","ttl":3600,
"contents":["1 aspmx.l.google.com","5 alt1.aspmx.l.google.com","10 alt2.aspmx.l.google.com"]}}
POST /zones?domainName=apiname.com
{"zoneStruct":{"name":"@","type":"TXT","ttl":3600,
"contents":["v=spf1 include:_spf.google.com -all"]}}
```
4. **Verify.** `GET /zones?domainName=apiname.com` and compare against your notes from step 1, line by line.
5. **Switch delegation.**
```http
POST /zones/apply?domainName=apiname.com
```
Log `previousNameServers` from the response.
6. **Wait.** Up to 48 hours for full propagation. Both old and new name servers answer during this window, so a correct zone means no visible outage.
---
# SSL certificates
> The certificate lifecycle from CSR to issuance, the three rules behind most SSL errors, and how to choose a package.
SSL is the most order-sensitive part of the API. Calling these endpoints out of sequence is the commonest source of errors, so this section is laid out **in the order you must call them**.
## The lifecycle
```text
generate-csr (optional — or bring your own CSR)
│
▼
initialize ─────────────► WaitingForInstall ← you are charged here
│ │
│ │ 7-day configuration window
▼ ▼
configure ──────────► ConfigurationStarted
│
├──► WaitingForValidation / ConfirmationSent ← prove domain control
│ │
▼ ▼
check-status (poll) ─────────► Active ← issued
│
├──► certificate-content download and install
├──► reissue new key or new approver
└──► revoke cancel
```
| Step | Endpoint | Charges? |
| --- | --- | --- |
| 0a | `POST /ssls/generate-csr` — generate a CSR and key | no |
| 0b | `POST /ssls/check-csr` — inspect a CSR you hold | no |
| 0c | `GET /ssls/approvers` — valid approver e-mail addresses | no |
| 1 | `POST /ssls/initialize` — **buy the certificate** | **yes** |
| 2 | `PUT /ssls/configure` — submit CSR, contact, validation method | no |
| 3 | `PUT /ssls/check-status` — poll until issued | no |
| 4 | `GET /ssls/certificate` — full detail | no |
| 5 | `GET /ssls/certificate-content` — download the certificate | no |
## Three rules that will bite you
:::danger[1 · You have 7 days to configure what you buy]
`initialize` takes your money and reserves the certificate. If you do not call `configure` within **7 days**, the certificate is cancelled and `configure` starts failing with `Ssl:10056`. On refundable packages the fee is returned to your balance automatically.
**Never call `initialize` until you have the CSR and contact details ready.** If your checkout collects those after payment, call `initialize` at the end of checkout, not the beginning.
:::
:::caution[2 · The term is always one year]
There is no `period` parameter. Multi-year certificates are not sold — CA industry rules cap certificate lifetime at about 13 months. Do not build a year selector.
:::
:::caution[3 · Renewal opens 30 days before expiry, and there is no renewal endpoint]
Renewing is simply `initialize` + `configure` again for the same domain, within 30 days of expiry. Earlier than that gives `Ssl:10057`. Remaining days are **not** carried over — the new year starts when you configure, so renew close to expiry rather than early.
:::
## Choosing a package
Package metadata comes from `GET /api/v1/products/ssls`. Two things drive the choice.
| Value | Validation | What the CA checks | Typical wait |
| --- | --- | --- | --- |
| 1 | `DV` | Domain control only | 5–30 minutes |
| 2 | `OV` | Organisation documents verified | 1–3 business days |
| 3 | `EV` | Extended legal verification | 3–10 business days |
Package shape decides which `configure` fields are mandatory:
| Package covers | `sanList` | `wildcardList` |
| --- | --- | --- |
| One domain | forbidden | forbidden |
| Multiple domains | **required** | forbidden |
| Wildcard | forbidden | **required** |
---
# Prepare: CSR and approvers
> Generate or inspect a CSR, and list the approver e-mail addresses a certificate can be validated with. None of these calls charge.
## Step 0a — generate a CSR
### POST /api/v1/ssls/generate-csr
Generates a CSR and matching private key on our side. Optional — you may bring your own CSR to `configure` instead.
**Request**
```json
{
"domainName": "apiname.com",
"country": "TR",
"state": "Istanbul",
"locality": "Istanbul",
"organization": "Apiname Ltd",
"organizationUnit": "IT",
"alternativeNames": ["www.apiname.com"]
}
```
| Field | Required | Max | Notes |
| --- | --- | --- | --- |
| `domainName` | required | 72 | The certificate's main name. For a wildcard certificate send `*.apiname.com`. |
| `country` | required | 2 | ISO 3166-1 alpha-2, uppercase. |
| `state` | required | 50 | State, province or region. Spell it out — no abbreviations. |
| `locality` | required | 50 | City. |
| `organization` | required | 150 | Legal entity name. **For OV and EV certificates this must match official records exactly** or vetting fails. |
| `organizationUnit` | required | 150 | Department, e.g. `IT`. |
| `alternativeNames` | optional | — | Extra names to embed in the CSR. |
**Response — 200**
```json
{
"csr": "-----BEGIN CERTIFICATE REQUEST-----\nMIICvDCCAaQCAQAwdzEL...\n-----END CERTIFICATE REQUEST-----",
"privateKey": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhki...\n-----END PRIVATE KEY-----"
}
```
:::danger[Store the private key now — there is no second chance]
The private key is **not kept** unless you send it back in `configure`, and there is no endpoint that will return it later. Without it the issued certificate is useless and you will have to reissue.
Store it encrypted, alongside the CSR, against your customer's record — before you make the next API call.
:::
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `Ssl:10001` | Invalid domain name. |
| `Ssl:10005` | The domain name does not meet the required format. Wildcards must have the `*` as the leftmost label only. |
## Step 0b — inspect a CSR
### POST /api/v1/ssls/check-csr
Decodes a CSR so you can confirm its contents before buying. Useful when the customer supplies their own.
**Request**
```json
{
"csr": "-----BEGIN CERTIFICATE REQUEST-----\nMIICvDCCAaQCAQAwdzEL...\n-----END CERTIFICATE REQUEST-----"
}
```
**Response — 200**
```json
{
"domainName": "apiname.com",
"country": "TR",
"state": "Istanbul",
"locality": "Istanbul",
"organization": "Apiname Ltd",
"organizationUnit": "IT",
"alternativeNames": "www.apiname.com",
"isWildcard": false,
"isSan": true
}
```
:::tip[Use this to validate before charging]
Check `domainName` matches what the customer ordered, and that `isWildcard` matches the package type. A mismatch discovered here costs nothing; the same mismatch discovered at `configure` has already cost the certificate fee and started the 7-day clock.
:::
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `Ssl:10004` | The CSR could not be decoded. Check it includes the BEGIN/END lines and has not been line-wrapped incorrectly. |
## Step 0c — approver e-mail addresses
### GET /api/v1/ssls/approvers
Lists the e-mail addresses the CA will accept as the domain's approver, for e-mail-based validation.
**Request**
```http
GET /api/v1/ssls/approvers?domainName=apiname.com&packageCode=POSITIVESSL
```
| Parameter | Required | Notes |
| --- | --- | --- |
| `domainName` | required | |
| `packageCode` | conditional | **Required if no certificate exists yet** for this domain. Ignored once one does. |
**Response — 200**
```json
{
"mails": [
"admin@apiname.com",
"administrator@apiname.com",
"hostmaster@apiname.com",
"postmaster@apiname.com",
"webmaster@apiname.com"
]
}
```
:::tip[What to do with it]
Present this list to the customer and let them choose. The address they pick is what you send as `approverMail`. **An address not on this list is rejected** when `authenticationType` is `Email`.
If the customer has none of these mailboxes — common with a domain they just bought — use `Cname` or `Http` validation instead and skip this call.
:::
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `Ssl:10038` | The approver list could not be retrieved from the CA. Retry, or use DNS/HTTP validation. |
| `Ssl:10003` | `packageCode` missing or unknown, and no certificate exists for the domain. |
---
# Buy a certificate
> Buy a certificate. This is the step that debits your balance and starts the 7-day configuration window.
## POST /api/v1/ssls/initialize
**This is the purchase.** It reserves the certificate and debits your balance. Nothing is sent to the CA yet.
**Request**
```json
{
"packageCode": "POSITIVESSL",
"domainName": "apiname.com"
}
```
| Field | Required | Notes |
| --- | --- | --- |
| `packageCode` | required | From `GET /api/v1/products/ssls` — the `productCode` field. |
| `domainName` | required | The certificate's main name. |
**Response — 200**
```json
{
"success": true,
"message": "SSL certificate purchase initialized successfully. Waiting for installation.",
"certificateId": "5e8c2a71-4b93-4f06-ae25-1d7f9c3b8042",
"status": "WaitingForInstall",
"dcvDetails": null,
"csr": null,
"privateKey": null
}
```
:::tip[Safe to retry — you will not be charged twice]
If you call `initialize` again for a domain that already has a certificate awaiting configuration:
- **Same `packageCode`** → the existing certificate comes back with `success: true` and a message saying it was already initialized. **No second charge.** This is what makes a timed-out request safe to repeat.
- **Different `packageCode`** → `Ssl:10052`, telling you to configure the pending certificate first.
Store `certificateId` and start your 7-day timer now.
:::
:::note[Some packages are installed by our technical team]
For a few packages the message changes to say installation is performed by our technical team and asks you to open a support ticket. For those, `configure` will refuse with `Ssl:10070` — it is not a bug. Check the message on this response and route the customer accordingly.
:::
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `Ssl:10003` | `packageCode` unknown. |
| `Ssl:10067` | The package is no longer on sale. Pick another. |
| `Ssl:10052` | A certificate with a *different* package is already awaiting configuration for this domain. |
| `Ssl:10013` | An active certificate already exists for this domain. Reissue or renew instead. |
| `Ssl:10044 / Ssl:10046` | No price configured for this package. Open a ticket. |
| `Ssl:10045` | Insufficient balance. `data` gives the shortfall. |
| `Ssl:10047` | Your balance is suspended. |
| `Ssl:10001` | Invalid domain name. |
---
# Configure a certificate
> Submit the CSR, contact and validation method that open the order with the certificate authority.
## PUT /api/v1/ssls/configure
Submits everything the CA needs and **opens the order at the provider**. The CSR, contact and validation method are fixed at this point.
**Request**
| Field | Required | Notes |
| --- | --- | --- |
| `domainName` | required | Must have a certificate awaiting configuration. |
| `csr` | required | PEM CSR. **Its common name must match `domainName`**. |
| `privateKey` | optional | Send it only if you want us to store it. Omit to keep it solely on your side. |
| `approverMail` | required | For `Email` validation, must be one of the `/approvers` addresses. |
| `authenticationType` | required | `Email`, `Cname`, `Http` or `File`. |
| `webServerType` | required | `Apache`, `IIS`, `AOL` or `C2Net`. |
| `sanList` | conditional | Comma-separated extra names. **Required for multi-domain packages, forbidden on others.** |
| `wildcardList` | conditional | Comma-separated wildcard names. **Required for wildcard packages, forbidden on others.** |
| `contact` | required | One contact, submitted to the CA as both administrative and technical. |
**A standard single-domain certificate with DNS validation**
```json
{
"domainName": "apiname.com",
"csr": "-----BEGIN CERTIFICATE REQUEST-----\nMIICvDCCAaQCAQAwdzEL...\n-----END CERTIFICATE REQUEST-----",
"privateKey": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhki...\n-----END PRIVATE KEY-----",
"approverMail": "admin@apiname.com",
"authenticationType": "Cname",
"webServerType": "Apache",
"contact": {
"firstName": "Ahmet",
"lastName": "Yilmaz",
"companyName": "Apiname Ltd",
"eMail": "ahmet@apiname.com",
"address": "Ataturk Caddesi No 12 Kat 3",
"city": "Istanbul",
"state": "Istanbul",
"postalCode": "34100",
"country": "TR",
"phoneCountryCode": "90",
"phone": "5321234567"
}
}
```
**A multi-domain certificate**
```json
{
"domainName": "apiname.com",
"csr": "-----BEGIN CERTIFICATE REQUEST-----\n...\n-----END CERTIFICATE REQUEST-----",
"approverMail": "admin@apiname.com",
"authenticationType": "Email",
"webServerType": "Apache",
"sanList": "www.apiname.com,mail.apiname.com,shop.apiname.com",
"contact": { "...": "as above" }
}
```
**A wildcard certificate**
```json
{
"domainName": "apiname.com",
"csr": "-----BEGIN CERTIFICATE REQUEST-----\n...\n-----END CERTIFICATE REQUEST-----",
"approverMail": "admin@apiname.com",
"authenticationType": "Cname",
"webServerType": "Apache",
"wildcardList": "*.apiname.com",
"contact": { "...": "as above" }
}
```
### Choosing a validation method
| Value | How the customer proves control | When to use it |
| --- | --- | --- |
| `Email` | The CA e-mails `approverMail` with an approval link. | Fastest when the customer has one of the standard mailboxes. No DNS or server access needed. |
| `Cname` | Publish a CNAME record the CA specifies. The values come back in `dcvDetails`. | **Best for automation.** No mailbox needed, and if the domain's DNS is with us you can publish the record through the [zones API](https://www.domainnameapi.com/docs/dns-records/) in the same workflow. |
| `Http` | Serve a file at a URL the CA specifies. | When the customer controls the web server but not DNS or mail. |
| `File` | File-based variant; the exact path depends on the brand. | Rarely needed. |
`webServerType` determines the bundle format the CA prepares. Pick `Apache` for Apache, nginx, HAProxy and most Linux stacks; `IIS` for Microsoft IIS. `AOL` and `C2Net` are legacy.
**Response — 200**
```json
{
"success": true,
"message": "SSL certificate configured successfully. Pending domain validation.",
"certificateId": "5e8c2a71-4b93-4f06-ae25-1d7f9c3b8042",
"status": "WaitingForValidation",
"dcvDetails": "{\"MD5\":\"A1B2C3D4E5F6A7B8C9D0E1F2A3B4C5D6\",\"SHA1\":\"1A2B3C4D5E6F7A8B9C0D1E2F3A4B5C6D7E8F9A0B\",\"UniqueValue\":\"9f3c1a2b8e4d\"}",
"csr": null,
"privateKey": null
}
```
:::caution[`dcvDetails` is a JSON *string*, not an object]
Parse it, then read the keys for your CA brand:
| Brand | Keys |
| --- | --- |
| Comodo / Sectigo | `MD5`, `SHA1`, `UniqueValue` |
| DigiCert | `DCVRandomValue` |
| GlobalSign | `DNSText`, `URLMetaTag` |
It is empty for `Email` validation. Use the exact values the CA returned — do not construct the record from memory or a blog post.
:::
:::tip[What to do next, by validation method]
- **Email** — tell the customer to check `approverMail` and click the link. Then poll `check-status`.
- **Cname** — publish the record from `dcvDetails`. If the DNS is with us, do it with `POST /api/v1/domains/zones`. Then poll.
- **Http / File** — place the file on the web server as the CA specified. Then poll.
If `status` comes back `Active` immediately, a DV certificate was issued instantly and you can go straight to downloading it.
:::
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `Ssl:10026` | No certificate for this domain. Call `initialize` first. |
| `Ssl:10056` | **The 7-day window expired.** The fee is being refunded. Buy a new certificate. |
| `Ssl:10077` | Same situation, refund already in progress. |
| `Ssl:10053` | Configuration has already been started — a duplicate or concurrent call. **Do not retry**; poll `check-status`. |
| `Ssl:10054` | The provider call timed out and we could not verify the outcome. **Do not retry.** Open a support ticket with the `certificateId`. |
| `Ssl:10070` | This package is installed by our technical team. Open a support ticket. |
| `Ssl:10027 / Ssl:10041` | The certificate's status does not allow configuring — already configured, cancelled, or already active. |
| `Ssl:10004` | The CSR could not be decoded. |
| `Ssl:10040` | **Common mistake.** The CSR's common name does not match `domainName`. Check with `check-csr`. |
| `Ssl:10019` | Wildcard package, but the CSR's name does not start with `*.` |
| `Ssl:10035 / Ssl:10030` | `authenticationType` is not a valid value, or not valid for this package. |
| `Ssl:10051` | That validation method is not supported by this CA brand. Pick another. |
| `Ssl:10037` | `webServerType` is not a valid value. |
| `Ssl:10014 / Ssl:10038` | `approverMail` is malformed, or not on the approver list. |
| `Ssl:10015 / Ssl:10023` | `sanList` sent to a single-domain package, or missing on a multi-domain package. |
| `Ssl:10020 / Ssl:10021 / Ssl:10032` | Too many SANs (limit 255), duplicates in the list, or an invalid SAN name. |
| `Ssl:10016 / Ssl:10022 / Ssl:10024` | `wildcardList` sent to a non-wildcard package, or missing on a wildcard package. |
| `Ssl:10017` | A wildcard entry duplicates the certificate's main name. |
| `Ssl:10018` | A wildcard name is invalid. The `*` may only be the leftmost label. |
| `Ssl:10010 / Ssl:10011 / Ssl:10012` | The `contact` object is missing or incomplete. |
| `Ssl:10050` | The CA rejected the request. Their explanation is in the message. |
| `Ssl:10049` | The CA could not be reached. Retry in a few minutes. |
---
# Issuance and download
> Poll until the certificate is issued, then read its details and download the certificate files.
## Step 3 — poll for issuance
### PUT /api/v1/ssls/check-status
Asks the CA where the order stands and updates our record. It is a `PUT` because it has that side effect.
**Request**
```json
{
"domainName": "apiname.com"
}
```
**Response — still validating**
```json
{
"domainName": "apiname.com",
"status": "WaitingForValidation",
"statusMessage": "Waiting for domain control validation",
"isConfigured": true,
"isIssued": false,
"certificateExpiresAt": null
}
```
**Response — issued**
```json
{
"domainName": "apiname.com",
"status": "Active",
"statusMessage": "The certificate is active",
"isConfigured": true,
"isIssued": true,
"certificateExpiresAt": "2027-11-28T23:59:59"
}
```
:::tip[Poll on `isIssued`, not on `status`]
`isIssued: true` is the signal that the certificate exists and can be downloaded. Expected waits:
- **DV with Cname or Http** — minutes after the record or file is in place.
- **DV with Email** — as long as the customer takes to click.
- **OV** — 1 to 3 business days; the CA verifies the organisation.
- **EV** — 3 to 10 business days.
Poll every **5 to 10 minutes**, not every second — this call costs 10 quota points. For OV and EV, hourly is plenty.
:::
**Certificate statuses**
| Value | Name | What to do |
| --- | --- | --- |
| 1 | `Active` | Issued and in force. Download it. |
| 2 | `WaitingForInstall` | Bought but not configured. **The 7-day clock is running.** |
| 3 | `InstallationInProgress` | Installation under way. |
| 4 | `WaitingForValidation` | Publish the DNS record or serve the file, then keep polling. |
| 5 | `ConfirmationSent` | Approval e-mail sent. Chase the customer. |
| 6 | `WaitingForDocument` | The CA wants organisation documents (OV/EV vetting). They will contact the customer directly. |
| 7 | `Cancelled` | Revoked, cancelled, or the 7-day window lapsed. |
| 8 | `ConfigurationStarted` | Order sent to the CA, outcome not yet recorded. **Do not call configure again.** Keep polling. |
| 10 | `Renewed` | Superseded by a renewal. Still valid until its own expiry, but the current certificate is the newer one. |
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `Ssl:10026` | No certificate for this domain. |
| `Ssl:10049 / Ssl:10050` | The CA could not be reached or rejected the query. Retry later. |
## Steps 4 and 5 — detail and download
### GET /api/v1/ssls/certificate
Full detail for the certificate on a domain. Use it to build the customer's certificate page.
**Request**
```http
GET /api/v1/ssls/certificate?domainName=apiname.com
```
**Response — 200**
```json
{
"domainName": "apiname.com",
"status": "Active",
"isConfigured": true,
"isIssued": true,
"packageName": "PositiveSSL",
"packageCode": "POSITIVESSL",
"subscription": {
"purchasedAt": "2026-10-30T16:12:40",
"expiresAt": "2027-10-30T16:12:40"
},
"configuration": {
"configuredAt": "2026-10-30T16:28:11",
"configurationLink": null,
"pin": null,
"webServer": "Apache",
"authenticationType": "Cname",
"sanList": null,
"wildcardList": null,
"approverMail": "admin@apiname.com",
"csr": "-----BEGIN CERTIFICATE REQUEST-----\n...\n-----END CERTIFICATE REQUEST-----",
"dcvDetails": "{\"MD5\":\"A1B2C3D4E5F6A7B8C9D0E1F2A3B4C5D6\"}"
},
"certificate": {
"issuedAt": "2026-10-30T16:41:55",
"validUntil": "2027-11-28T23:59:59"
},
"contacts": [
{ "type": "Administration", "firstName": "Ahmet", "lastName": "Yilmaz" },
{ "type": "Technical", "firstName": "Ahmet", "lastName": "Yilmaz" }
]
}
```
:::danger[Two different expiry dates — do not confuse them]
| Field | Meaning |
| --- | --- |
| `subscription.expiresAt` | **What you paid for.** Drive renewal reminders off this. |
| `certificate.validUntil` | **What the CA signed.** This is when browsers start showing warnings. |
They diverge when configuration happens days after purchase. Use `subscription.expiresAt` for billing and the renewal window, and `certificate.validUntil` for "your certificate expires in N days" warnings.
:::
`configuration` is `null` until configured; `certificate` is `null` until issued. Check for null before reading them.
### GET /api/v1/ssls/certificate-content
Returns the issued certificate and its chain. Call it only once `isIssued` is `true`.
**Request**
```http
GET /api/v1/ssls/certificate-content?domainName=apiname.com
```
**Response — 200**
```json
{
"certificate": "-----BEGIN CERTIFICATE-----\nMIIFXzCCBEegAwIBAgIR...\n-----END CERTIFICATE-----",
"intermediateCertificate1": "-----BEGIN CERTIFICATE-----\nMIIGEzCCA/ugAwIBAgIQ...\n-----END CERTIFICATE-----",
"intermediateCertificate2": "-----BEGIN CERTIFICATE-----\nMIIF3jCCA8agAwIBAgIQ...\n-----END CERTIFICATE-----",
"rootCertificate": "-----BEGIN CERTIFICATE-----\nMIIFgTCCA2mgAwIBAgIO...\n-----END CERTIFICATE-----"
}
```
:::tip[Building the bundle to install]
For nginx, Apache and most modern servers, concatenate in this order:
```text
certificate
intermediateCertificate1
intermediateCertificate2 (if present)
```
The **root is normally not included** — clients already trust it, and shipping it just wastes bytes in every handshake. `intermediateCertificate2` is `null` for brands that use a single intermediate; skip it if so.
The **private key is not returned here.** It is the one you kept from `generate-csr`, or the one you supplied to `configure`.
:::
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `Ssl:10026` | No certificate for this domain. |
| `Ssl:10048` | Not issued yet. Keep polling `check-status`. **Note:** this code is shared with a provider-order error, so the message you see may mention a provider order number — if `isIssued` is `false`, the real cause is simply that the certificate is not ready. |
---
# Reissue, revoke and renew
> Reissue a certificate with a new key or approver, revoke it, and renew it before it expires.
## Reissue and revoke
### POST /api/v1/ssls/reissue
Re-issues an active certificate with a new key pair or a new approver. Free on most packages. **The validity period is not extended.**
**When you need this**
- The private key was lost or compromised.
- The server is being rebuilt and the key cannot be recovered.
- The approver e-mail address needs changing.
**Request — let us generate a new key**
```json
{
"domainName": "apiname.com"
}
```
**Request — bring your own new CSR**
```json
{
"domainName": "apiname.com",
"csr": "-----BEGIN CERTIFICATE REQUEST-----\n...\n-----END CERTIFICATE REQUEST-----",
"privateKey": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----",
"approverMail": "webmaster@apiname.com"
}
```
**Response — 200, when you omitted the CSR**
```json
{
"success": true,
"message": "Reissue request submitted",
"certificateId": "5e8c2a71-4b93-4f06-ae25-1d7f9c3b8042",
"status": "WaitingForValidation",
"dcvDetails": "{\"MD5\":\"...\",\"SHA1\":\"...\",\"UniqueValue\":\"...\"}",
"csr": "-----BEGIN CERTIFICATE REQUEST-----\nMIICvDCCAaQCAQAwdzEL...\n-----END CERTIFICATE REQUEST-----",
"privateKey": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhki...\n-----END PRIVATE KEY-----"
}
```
:::danger[Save `csr` and `privateKey` from this response immediately]
This is the **only** time these are returned. There is no way to fetch the generated private key again, and the reissued certificate cannot be installed without it. If you lose it you must reissue again.
If you send your own `csr`, these two fields come back `null` — the key stays with you, which is the safer option.
:::
After reissuing you go through validation again: publish the new `dcvDetails` record or have the approver click the new e-mail, then poll `check-status`.
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `Ssl:10026` | No certificate for this domain. |
| `Ssl:10006` | Reissue is not supported for this certificate. |
| `Ssl:10008` | The certificate must be `Active`. You cannot reissue one that is still validating. |
| `Ssl:10055` | The subscription has ended. Reissue is not possible — buy a new certificate. |
| `Ssl:10075` | This package is managed by our technical team. Open a support ticket. |
| `Ssl:10007` | The CA failed to process the reissue. Retry, or open a ticket. |
| `Ssl:10004 / Ssl:10040` | Your supplied CSR is invalid or its name does not match. |
### DELETE /api/v1/ssls/revoke
Revokes the certificate. Its status becomes `Cancelled`.
**Request**
```json
{
"domainName": "apiname.com"
}
```
:::danger[This is not a refund, and it is not reversible]
Revoking a configured certificate does **not** return the fee. The only automatic refund is letting the 7-day configuration window lapse on a refundable package.
Once revoked, the certificate is permanently distrusted by browsers. You cannot un-revoke it — a new purchase is required. Only revoke when the private key is known to be compromised.
:::
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `Ssl:10026` | No certificate for this domain. |
| `Ssl:10027` | The status does not allow revoking — already cancelled, or not yet configured. |
| `Ssl:10049` | The revoke failed. **Note:** this code is shared with a CA connectivity error — read the message to tell which. |
| `Ssl:10075` | Package managed by our technical team. Open a support ticket. |
## Renewal
There is no renewal endpoint. Renewal is a fresh purchase cycle inside the renewal window:
1. `GET /api/v1/ssls/certificate` — read `subscription.expiresAt`.
2. Within **30 days** of that date, `POST /api/v1/ssls/initialize` with the same domain. You are charged for a new one-year subscription.
3. `PUT /api/v1/ssls/configure` — the new year begins **here**, not at the old expiry.
4. The old certificate's status becomes `Renewed`. It stays technically valid until its own expiry, so there is no gap.
:::caution[Do not renew early]
Remaining days are not carried over. Renewing 30 days before expiry and configuring immediately loses those 30 days. Renew within the window but close to expiry — around 7 to 14 days before is a good balance between safety and value.
:::
| Code | Meaning and fix |
| --- | --- |
| `Ssl:10057` | Too early. The message tells you the date renewal opens. |
| `Ssl:10058` | Already renewed — the renewal is in your certificate list. |
| `Ssl:10059` | Not renewable. Only configured, non-cancelled certificates can be renewed. |
---
# Hosting
> Buy and provision shared hosting asynchronously: pick a package, create the account, poll its status, and look it up later.
Buy and provision shared hosting accounts. Unlike everything else in this API, hosting creation is **asynchronous**: you get HTTP 202 immediately and poll for the result.
## The flow
1. `GET /api/v1/hostings/packages` — pick a `servicePlan` value.
2. `POST /api/v1/hostings/create` — returns **202** with a `serviceId` and status `Provisioning`.
3. `GET /api/v1/hostings/check-status` — poll until `Active` or `Failed`. When `Active`, the credentials are in the response.
:::note[Why it is asynchronous]
Creating an account on the hosting panel takes 20 to 60 seconds on its own. Rather than hold your HTTP request open that long, we take the order, charge your balance, and hand the provisioning to a background worker. If provisioning then fails on every attempt, **your balance is refunded automatically**.
:::
:::caution[Hosting errors do not carry error codes]
Every other area of this API returns a machine-readable `code`. The hosting endpoints currently return a plain English `message` only, with **HTTP 403** and `error.code` empty. Until that changes, match on `error.message` for these endpoints — the exact strings are listed with each endpoint below.
:::
## GET /api/v1/hostings/packages
Lists what you can sell. Call this first — the `servicePlan` value from here is what `create` expects.
**Request — no parameters**
```http
GET /api/v1/hostings/packages
```
**Response — 200**
```json
[
{
"name": "Starter",
"requiredMinLeasing": 1,
"permittedMaxLeasing": 12,
"servicePlans": [
{
"servicePlan": "starter-linux-01",
"operatingSystem": "Linux",
"panelType": "cPanel"
},
{
"servicePlan": "starter-win-01",
"operatingSystem": "Windows",
"panelType": "Plesk"
}
]
},
{
"name": "Business",
"requiredMinLeasing": 1,
"permittedMaxLeasing": 24,
"servicePlans": [
{
"servicePlan": "business-linux-01",
"operatingSystem": "Linux",
"panelType": "cPanel"
}
]
}
]
```
| Field | How to use it |
| --- | --- |
| `name` | Package name, for display. |
| `requiredMinLeasing` | Minimum lease term in months. |
| `permittedMaxLeasing` | Maximum lease term in months. |
| `servicePlans[].servicePlan` | **The exact value to send to `create`.** Do not construct it yourself. |
| `servicePlans[].operatingSystem` | `Linux` or `Windows`. |
| `servicePlans[].panelType` | `cPanel` or `Plesk`. |
:::caution[The operating system belongs to the plan, not the package]
One package can offer both a Linux/cPanel and a Windows/Plesk variant, as in the `Starter` example above. Let the customer choose deliberately — **this cannot be changed after provisioning.** Moving between them means a new account and a manual migration.
:::
## POST /api/v1/hostings/create
Buys the package and queues provisioning. **Returns HTTP 202, not 200.**
**Request**
```json
{
"domainName": "apiname.com",
"servicePlan": "starter-linux-01"
}
```
| Field | Required | Notes |
| --- | --- | --- |
| `domainName` | required | The domain the account is created for. Must be a valid registrable domain — it does not have to be registered with us. |
| `servicePlan` | required | A `servicePlan` value from `GET /packages`. |
**Response — 202 Accepted**
```jsonc
{
"serviceId": "HST-2026-0004821",
"status": "Provisioning",
"panelAddress": "https://panel.apiname.com",
"username": "",
"password": "",
"token": ""
}
```
:::danger[The credential fields are empty here — that is expected]
`username`, `password` and `token` exist on the response but are **always empty at this stage**, and `status` is **always `Provisioning`**. The account does not exist on the panel yet.
**Store `serviceId`.** It identifies the hosting in every other call, and it is the only thing you get from this response that you cannot obtain again easily.
:::
:::tip[What to do next]
Poll `GET /api/v1/hostings/check-status` with the `serviceId`. Show the customer a "setting up your hosting" state in your UI rather than a credentials page.
:::
**Errors — messages, no codes**
| Message | Meaning and fix |
| --- | --- |
| `The provided domain name is invalid.` | `domainName` could not be parsed as a domain. |
| `No product is defined for package '{name}'.` | Configuration problem on our side. Open a support ticket. |
| `No price defined for package '{name}'.` | No price set for your account on that package. Open a ticket. |
| `Insufficient balance to purchase this hosting package.` | Top up and retry. |
:::note[If a hosting stays in `Provisioning` for a long time]
Normal provisioning finishes in under two minutes. If a record is still `Provisioning` after, say, 30 minutes, something went wrong in a way that did not surface as an error. Report it with the `serviceId` rather than creating a second hosting — that would charge you twice.
:::
## GET /api/v1/hostings/check-status
Reports where provisioning got to and, once complete, returns the credentials.
**Request — send exactly one of these**
| Parameter | Notes |
| --- | --- |
| `serviceId` | From the `create` response. |
| `domainName` | Alternative lookup key. |
```http
GET /api/v1/hostings/check-status?serviceId=HST-2026-0004821
```
:::caution[Exactly one — not both, not neither]
Sending both `serviceId` and `domainName` is an error, as is sending neither. This applies to `GET /hostings` as well.
:::
**Response — still provisioning**
```jsonc
{
"serviceId": "HST-2026-0004821",
"domainName": "apiname.com",
"status": "Provisioning",
"statusMessage": "The hosting account is being created on the server.",
"panelAddress": "https://panel.apiname.com",
"username": "",
"password": "",
"token": "",
"failureReason": null
}
```
**Response — ready**
```jsonc
{
"serviceId": "HST-2026-0004821",
"domainName": "apiname.com",
"status": "Active",
"statusMessage": "The hosting account is ready.",
"panelAddress": "https://panel.apiname.com",
"username": "apiname1",
"password": "xK7#mQ2pL9vR4tZ8",
"token": "a4f81c2e9b7d35604e8a1f93c62b07d5",
"failureReason": null
}
```
**Response — failed**
```json
{
"serviceId": "HST-2026-0004821",
"domainName": "apiname.com",
"status": "Failed",
"statusMessage": "The hosting account could not be created. The amount has been refunded.",
"panelAddress": "",
"username": "",
"password": "",
"token": "",
"failureReason": "Account name already exists on the target server"
}
```
**Status values**
`status` is always a **string** — the name below, never a number.
| `status` | What to do |
| --- | --- |
| `Provisioning` | Keep polling. Expect 20–60 seconds, occasionally longer. |
| `Active` | Ready. Read `username`, `password` and `token`. |
| `Failed` | **Your balance has already been refunded.** Read `failureReason`, fix the cause, call `create` again. |
| `Suspended` | Suspended because the lease expired. Renew to reactivate; if it is not renewed by the deletion date it becomes `Deleted`. |
| `Deleted` | Terminal. |
:::danger[Credentials are returned only while the status is `Active`]
`username`, `password` and `token` are populated **only** when `status` is `Active`. In every other state they are empty strings.
Capture them on the first `Active` response and store them encrypted. The response is sent with `Cache-Control: no-store` for a reason — do not log it, do not put it in a URL, and do not cache it in a browser.
:::
:::tip[Polling advice]
This call costs 10 quota points, so polling every second will build up points fast. Poll every **5 to 10 seconds** for the first two minutes, then back off. Give up and report the `serviceId` after about 30 minutes.
:::
**Errors — messages, no codes**
| Message | Meaning and fix |
| --- | --- |
| `Either serviceId or domainName must be provided.` | You sent neither. |
| `Provide only one of serviceId or domainName, not both.` | You sent both. |
| `Hosting not found.` | No matching record. |
| `You are not authorized to access this hosting.` | The record belongs to another reseller. |
## GET /api/v1/hostings · GET /api/v1/hostings/by-token · GET /api/v1/hostings/plans
Look up a hosting record, or read its plan limits.
**GET /api/v1/hostings — by service ID or domain**
```http
GET /api/v1/hostings?serviceId=HST-2026-0004821
{
"hostingId": "b7f24e90-3a51-4c86-9d02-6e8b1f5a7c34",
"serviceId": "HST-2026-0004821",
"domainName": "apiname.com",
"packageName": "Starter",
"leaseOn": "2026-10-30T16:55:12",
"expiredOn": "2027-10-30T16:55:12",
"status": "Active",
"externalCustomerId": "CUST-88201"
}
```
:::caution[Two different identifiers]
`serviceId` (`HST-…`) is what you use for `check-status` and lookups. `hostingId` (a GUID) is what `GET /plans` expects. **They are not interchangeable.** Store both.
No credentials are returned here — use `check-status` for those.
:::
**GET /api/v1/hostings/by-token — when all you have is the panel token**
```http
GET /api/v1/hostings/by-token?token=a4f81c2e9b7d35604e8a1f93c62b07d5
```
Returns the same object. Useful when a provisioned account's token is the only reference you have.
**GET /api/v1/hostings/plans — resource limits**
```http
GET /api/v1/hostings/plans?hostingId=b7f24e90-3a51-4c86-9d02-6e8b1f5a7c34
[
{
"name": "Starter Linux",
"externalId": "starter-linux-01",
"diskQuotaMb": 10240,
"bandwidthLimitMb": 102400,
"maxDomains": 1,
"maxSubDomains": 10,
"maxDatabases": 5,
"maxFtpAccounts": 3,
"maxEmailAccounts": 25,
"hasDedicatedIp": false,
"hasShellAccess": false
}
]
```
:::note[`null` means unlimited, not zero]
A `null` numeric limit means the resource is unlimited on that plan. Do not render it as "0" — that is the opposite of what it means.
:::
**Errors — messages, no codes**
| Message | Meaning and fix |
| --- | --- |
| `Hosting not found.` | No matching record. |
| `You are not authorized to access this hosting.` | Belongs to another reseller. |
| `Token is required.` | `token` empty on `/by-token`. |
| `Token not recognized.` | No hosting matches that token. |
| `Token was not recognized by the panel.` | The hosting panel rejected the token. |
| `The account for this token could not be resolved.` | The panel returned no account. |
| `Account information could not be retrieved from the panel: {detail}` | Panel error; the detail is theirs. |
| `No hosting account is available for this hosting.` | There is no panel account — provisioning never completed. Check `check-status`. |
---
# TLD catalogue
> Every extension you can sell, with its periods, prices, features and required extra fields, in one free call. Fetch it once and cache it.
## GET /api/v1/products/tlds
**The single most useful endpoint in the API.** It answers how many years you can sell an extension for, whether it supports privacy, DNSSEC and transfers, which extra fields are required, and what it costs — all in one call.
:::tip[This endpoint is free]
It is exempt from rate limiting and never costs quota points. Even so, **cache it on your side** and refresh daily — it changes rarely and the response is large.
:::
**Request**
```http
GET /api/v1/products/tlds?maxResultCount=500¤cy=USD
```
| Parameter | Default | Notes |
| --- | --- | --- |
| `filterText` | — | Filter by extension name. |
| `currency` | — | Express prices in this currency, e.g. `USD`, `TRY`. |
| `skipCount` | 0 | |
| `maxResultCount` | 10 | **Raise this** — the default of 10 will surprise you. The full catalogue is several hundred entries. |
| `sorting` | — | `field asc` or `field desc`. Must end in `asc` or `desc`. |
**Response — 200, one entry abridged**
```json
{
"totalCount": 487,
"items": [
{
"name": "com",
"minRegistrationPeriod": 1,
"maxRegistrationPeriod": 10,
"registrationPeriods": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
"renewalPeriods": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
"addGracePeriod": 5,
"autoRenewGracePeriod": 45,
"deletionRestorablePeriod": 30,
"deletionHoldPeriod": 5,
"transferPeriod": 5,
"isSupportTransfer": true,
"isTransferCheckSupported": true,
"isRequiredAuthCode": true,
"isTransferLockPossible": true,
"isPrivacyAvailable": true,
"isDnssecAvailable": true,
"isSupportIdn": true,
"isIpv6Available": true,
"isGlueRecordAllowed": true,
"isHostObjectAccepted": true,
"registryDnsCheck": false,
"isRequireDocument": false,
"isSupportTrustee": false,
"isTrusteeRequired": false,
"isHandleUpdateAvailable": true,
"isSaleAllowed": true,
"availableInTestEnvironment": true,
"prices": [
{
"priceGroup": "Standard",
"register": [
{ "period": 1, "price": 11.40, "currency": "USD" },
{ "period": 2, "price": 22.80, "currency": "USD" }
],
"renew": [
{ "period": 1, "price": 12.90, "currency": "USD" }
],
"transfer": [
{ "period": 1, "price": 11.40, "currency": "USD" }
],
"restore": { "period": 1, "price": 85.00, "currency": "USD" },
"backorder": { "period": 1, "price": 25.00, "currency": "USD" }
}
],
"attributes": []
}
]
}
```
### Every field, and what to do with it
This response is the contract for what an extension will and will not accept. The fields fall into four groups.
**1 · Terms you may sell — in years**
| Field | Meaning and use |
| --- | --- |
| `name` | The extension itself, without a leading dot: `com`, `com.tr`, `co.uk`. |
| `registrationPeriods` | **The exact terms you may send as `period` when registering.** A list, not a range — `[1,2,3,5,10]` means 4 is not sellable. Anything else gives `Domain:10023`. |
| `renewalPeriods` | The same list for renewal. It is not always identical to `registrationPeriods`. |
| `minRegistrationPeriod`
`maxRegistrationPeriod` | The smallest and largest entry in `registrationPeriods`, provided for convenience. Use them for a "from N years" label; use the list itself to build the selector. |
| `renewalPeriod` | The shortest renewal term. Useful as the default in a renewal form. |
| `transferPeriod` | The shortest transfer term. **May be `0`** when the extension does not publish transfer terms in a form we can read — treat `0` as "not stated" and rely on `/transfers/check` and the transfer price list instead. |
| `registerPeriod` | Reserved. Currently always `0` — ignore it. |
**2 · Capability flags — check before you call**
Each of these tells you whether an operation is possible at all. Checking first turns a failed API call into a disabled button.
| Flag | What it gates, and the error if you ignore it |
| --- | --- |
| isSupportTransfer | Whether domains can be transferred in at all. `false` → `Domain:10011` on `/domains/transfer`. |
| isTransferCheckSupported | Whether the registry offers a pre-transfer check. `false` → `Domain:10025` on `/transfers/check`; that is not a failure, just skip the check and call `/transfer` directly. |
| isRequiredAuthCode | Whether an authorisation code is mandatory to transfer in. `true` means you must collect it from the customer before you start. |
| isTransferLockPossible | Whether the registrar transfer lock can be toggled. `false` means `/domains/lock` and `/unlock` have nothing to act on. |
| isPrivacyAvailable | Whether WHOIS privacy is sold. `false` → `Tld:10001` on `/domains/privacy`. Hide the privacy option in your order form. |
| isDnssecAvailable | Whether DNSSEC is supported. `false` → every DNSSEC write gives `Dnssec:10001`. |
| isSupportIdn | Whether internationalised (non-ASCII) names are accepted. `false` → registering one gives `TldAttribute:10004`. |
| isIpv6Available | Whether IPv6 glue addresses are accepted. `false` → sending a `v6` address gives `Dns:10026`; send only `v4`. |
| isGlueRecordAllowed | Whether glue records are accepted at all. `false` → host operations give `Dns:10017`. |
| isHostObjectAccepted | How name servers under the domain are modelled. `true` → independent host objects; `false` → glue records carried on the domain. Changes what you can share and delete — see [Host (glue) records](https://www.domainnameapi.com/docs/name-servers/hosts/). |
| isHandleUpdateAvailable | Whether contacts can be re-pointed by handle. `false` → use `/domains/contacts/update` with full details instead of `/update-with-handle`. |
| isSupportTrustee | Whether a trustee / local-presence service is available to buy. |
| isSaleAllowed | Whether domains on this extension may be listed for sale. |
| availableInTestEnvironment | Whether the extension exists in the test environment. **Check this before writing an integration test** against a specific extension. |
**3 · Flags that change your workflow**
These do not block anything — they mean the happy path has an extra step. Design for them before you sell the extension, not after the first support ticket.
| Flag | What changes when it is `true` |
| --- | --- |
| isRequireDocument | **Registration does not complete on its own.** The domain comes back in a waiting state and stays there until you [upload documents](https://www.domainnameapi.com/docs/domains/documents/) and the registry approves them. Your order flow needs a document step and a status screen. |
| isTrusteeRequired | **You must send `useTrusteeContact: true`** or registration fails with `Trustee:10006`. The trustee fee is added to the order, so quote the customer the higher price. |
| registryDnsCheck | The registry queries your name servers and checks they really answer for the domain **before** accepting the registration. Point the domain at name servers that are already live — using a provider you have not configured yet will have the registration refused. |
**4 · Lifecycle periods — in calendar days**
These describe what the registry does to a domain as it ages. They are the numbers behind the renewal and restore rules, and they differ by extension.
| Field | Meaning and use |
| --- | --- |
| `addGracePeriod` | Days after a **new registration** during which deleting the domain is refunded by the registry. Commonly around 3–5 days. This is your window to undo a typo'd registration at no cost. |
| `autoRenewGracePeriod` | **Days after expiry during which the registry's automatic renewal can still be reversed.** The domain is auto-renewed on the first day after expiry and sits in this window — which is exactly why a second renewal inside it returns `Domain:10020`. Commonly two to three weeks, up to 45 days. |
| `deletionRestorablePeriod` | **The redemption window.** How many days `POST /domains/restore` keeps working after the domain is deleted — typically 30. Drive your "you can still recover this" messaging off it. |
| `deletionHoldPeriod` | Days between redemption lapsing and the domain actually being released to the public. Nothing can be done during it; the domain is beyond recovery. |
| `finalizationPeriod` | Days until a pending renewal becomes irreversible at the registry. |
| `failurePeriod` | The point after expiry at which the domain can no longer be renewed at all and moves into deletion. **Often a negative number**, counted relative to the expiry date. |
| `paymentPeriod` | Days during which the registry accepts payment for an upcoming renewal. |
:::tip[How the lifecycle fields fit together]
```text
registration ──► addGracePeriod delete here = refunded
│
▼
active ... ... ... ... ... expiry date
│
▼
autoRenewGracePeriod registry auto-renews;
second renewal refused (10020)
│
▼
failurePeriod renewal no longer possible
│
▼
deletionRestorablePeriod restore still works
│
▼
deletionHoldPeriod released to the public
```
Two practical uses: send renewal reminders before `failurePeriod` is reached, and show "recoverable until" dates from `deletionRestorablePeriod` instead of assuming 30 days everywhere.
:::
### Prices
Read the `prices` entry whose `priceGroup` matches your account's group — which you can find from `GET /api/v1/deposit/accounts/me` as `resellerGroupName`.
:::caution[These are list prices, and premium domains are not here]
- If you have a negotiated rate, the amount actually charged can be **lower** than what this endpoint shows. Treat catalogue prices as your sell-price baseline, not as your cost.
- **Premium domain prices never appear here.** They come from `POST /domains/search`, `/renew/check` or `/transfers/check`, and they can be many times the standard price. Always check `isPremium` before showing a price to a customer.
:::
### Extra fields (attributes)
The `attributes` array lists the registry-specific extra fields for the extension. Each entry has:
| Field | Meaning |
| --- | --- |
| `key` | **The key to send in `tldAttributes`.** |
| `description` | Label to show the customer. |
| `type` | `Text`, `DropdownList`, `RadioButton`, `Checkbox`, `CheckboxWithContract`, `FileUpload` or `Label`. `Label` entries are informational only; nothing is sent for them. |
| `isRequired` | Whether the registration fails without it. |
| `options` | The permitted values, each as `{ "value": "..." }`. Send one of the `value`s verbatim. Empty for free-text fields. |
```json
"attributes": [
{
"key": "TRABISDOMAINCATEGORY",
"description": "Domain category",
"isRequired": true,
"type": "DropdownList",
"options": [{ "value": "Corporate" }, { "value": "Owner" }]
}
]
```
:::tip[Build your registration form from this]
Rather than hard-coding "`.com.tr` needs an identity number", render the form dynamically from `attributes`. New extension requirements then work without a code change, and you never send a key the registry does not recognise. Every extension's fields are also listed on its page under [TLDs](https://www.domainnameapi.com/docs/tlds/).
:::
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `Dna.ProductService.Product:10002` | Invalid `sorting` value. The format is `field asc` or `field desc`. |
---
# SSL catalogue and prices
> Certificate packages and their prices, and the exact price for any product, operation and period at checkout.
## GET /api/v1/products/ssls
Certificate packages and their prices. Use it to pick the `packageCode` for [SSL purchase](https://www.domainnameapi.com/docs/ssl/buy/).
**Request**
```http
GET /api/v1/products/ssls?maxResultCount=100¤cy=USD&validationType=1
```
| Parameter | Notes |
| --- | --- |
| `filterText` | Matches package name or code. |
| `currency` | e.g. `USD`, `TRY`. |
| `validationType` | `1` DV, `2` OV, `3` EV. |
| `isWildcard` | `true` / `false`. |
| `isMultiDomain` | `true` / `false`. |
| `vendorName` | e.g. `Sectigo`, `DigiCert`. |
| `skipCount, maxResultCount, sorting` | Standard paging. |
**Response — 200**
```json
{
"totalCount": 24,
"items": [
{
"name": "PositiveSSL",
"productCode": "POSITIVESSL",
"vendorName": "Sectigo",
"validationType": "DV",
"isWildcard": false,
"isMultiDomain": false,
"defaultSanCount": 0,
"maxSanCount": 0,
"warrantyAmount": 50000,
"issueTimeMinutes": 15,
"isReissueFree": true,
"requiresCsr": true,
"prices": [
{
"priceGroup": "Standard",
"create": [
{ "period": 1, "price": 8.50, "currency": "USD" }
]
}
]
}
]
}
```
| Field | How to use it |
| --- | --- |
| `productCode` | **This is the `packageCode` for `/ssls/initialize`.** |
| `validationType` | `DV` issues in minutes; `OV` and `EV` take days. Set customer expectations accordingly. |
| `isWildcard` | If `true`, `configure` **requires** `wildcardList`. |
| `isMultiDomain` | If `true`, `configure` **requires** `sanList`. |
| `defaultSanCount / maxSanCount` | Names included in the base price, and the ceiling. |
| `issueTimeMinutes` | Typical issue time. Treat it as a guide for DV; OV and EV are driven by manual vetting, not this number. |
| `isReissueFree` | Whether `/ssls/reissue` costs anything. |
| `prices[].create` | Only `create` exists — SSL terms are always one year. |
## GET /api/v1/products/info
One product with its selling price recalculated for your account right now. Costs 1 quota point. Use it at checkout to show the exact price you will be charged.
**Request**
```http
GET /api/v1/products/info?productName=com&orderType=1&period=1
```
| Parameter | Required | Notes |
| --- | --- | --- |
| `productName` | required | Extension or package name. **Letters and dots only.** A leading dot is stripped, so `.com` and `com` both work. |
| `orderType` | required | `1` Register · `2` Renew · `3` Transfer · `4` Restore · `11` Create (SSL/hosting). |
| `period` | required | **1 to 10.** Outside that range is an error. |
**Response — 200**
```json
{
"id": "e1d7a92c-5f38-4b06-9c41-8a2e7f3d5b94",
"parentProductId": null,
"productName": "com",
"productCode": "COM",
"entityId": "4f8b1c23-9d05-4a71-b83e-2c6f9a1d7e40",
"productType": 1,
"sellingPrice": 11.40,
"sellingCurrency": "USD",
"subproducts": []
}
```
:::tip[This is your real price]
`sellingPrice` includes any negotiated rate on your account, so it can be lower than the catalogue figure. This is the number to show at checkout and the number that will be debited.
`subproducts` is populated when the product has add-ons — the trustee service is the common case. Add those to your displayed total.
:::
**Errors**
| Code | Meaning and fix |
| --- | --- |
| `Dna.ProductService.Product:10002` | `period` outside 1–10. **Note:** this code is also used for an invalid `sorting` value — read the message. |
| `Dna.ProductService.Product:10003` | `productName` contains characters other than letters and dots. |
| `Dna.ProductService.Product:10001` | Product not found. |
| `Dna.ProductService.Product:10004` | Unsupported currency. |
---
# Orders
> Read one order and its line items. Every paid operation creates an order, failed attempts included.
## GET /api/v1/order/{orderCode}
Reads one order with its line items. Every paid operation produces an order — including **failed** attempts, which are recorded so the failure is auditable.
**Request**
```http
GET /api/v1/order/ORD-2026-0038214
```
**Response — 200**
```json
{
"orderCode": "ORD-2026-0038214",
"status": 1,
"amount": 11.40,
"amountCurrency": "USD",
"products": [
{
"name": "apiname.com",
"productCode": "COM",
"productType": 1,
"orderType": 1,
"status": 1,
"price": 11.40,
"priceCurrency": "USD",
"period": 1,
"description": "Register: apiname.com",
"additionalData": null
}
]
}
```
| status | Order status |
| --- | --- |
| 1 | `Active` |
| 2 | `Pending` |
| 3 | `Canceled` |
| 4 | `InProgress` |
`products[].status`: `1` Ordered · `2` Canceled · `3` InProgress.
`orderType`: `1` Register · `2` Renew · `3` Transfer · `4` Restore · `9` Trustee · `10` Hosting lease · `11` Create (SSL/hosting) · `12` Ownership change.
`productType`: `1` Domain · `2` SSL · `3` Deposit · `4` Domain trustee · `5` Hosting · `6` Ownership change.
:::note[A trustee domain produces two line items]
One for the domain (`productType: 1`) and one for the trustee service (`productType: 4`). The order `amount` is the sum. Pass this through to your customer's invoice so the extra charge is visible.
:::
---
# Balance
> Read your current balances and the ledger of every balance movement, for reconciliation.
## GET /api/v1/deposit/accounts/me
Your current balances. Check this before bulk operations rather than discovering a shortfall half way through.
**Request — no parameters**
```http
GET /api/v1/deposit/accounts/me
```
**Response — 200**
```json
{
"resellerId": "7f3c1a28-9e4b-4c51-b1d2-0a6e5f8c3d94",
"resellerName": "Apiname Reseller",
"resellerGroupName": "Standard",
"tryBalance": 12450.75,
"usdBalance": 842.10
}
```
:::tip[What to do with it]
`resellerGroupName` tells you which `priceGroup` entry in the TLD and SSL catalogues applies to you — read that one and ignore the others.
Build a low-balance alert off `tryBalance` and `usdBalance`. Running out mid-batch means a wave of `Deposit:10001` errors and partially processed work.
:::
## GET /api/v1/deposit/transactions
Paged ledger of every balance movement. This is where you reconcile what you were charged against what you sold.
**Request**
```http
GET /api/v1/deposit/transactions?startDate=2026-10-01&endDate=2026-10-31
&maxResultCount=100&sorting=creationTime%20desc
```
| Parameter | Notes |
| --- | --- |
| `startDate, endDate` | Date range. |
| `transactionTypes` | Filter by type — see the table below. |
| `productTypes` | Filter by product type. |
| `chargeType` | `0` credits only, `1` debits only. |
| `traceId` | Exact trace ID — the fastest way to find one operation. |
| `description` | Partial match, e.g. a domain name. |
| `amount` | Exact amount. |
| `skipCount, maxResultCount, sorting` | Standard paging. |
**Response — 200**
```json
{
"totalCount": 318,
"items": [
{
"traceId": "a7f3c92e-1b84-4d06-9512-6e8a2f7c3d41",
"type": 1,
"status": 1,
"chargeType": 1,
"amount": 11.40,
"amountCurrency": "USD",
"exchangeAmount": 0,
"exchangeCurrency": 0,
"productType": 1,
"productId": "3c9a7e14-82b5-4d60-9f31-c7e8a05b6d42",
"description": "Register: apiname.com",
"period": 1,
"creationTime": "2026-10-30T12:04:19",
"resellerName": "Apiname Reseller",
"oldBalance": 853.50,
"balance": 842.10
}
]
}
```
| type | Transaction type | type | Transaction type |
| --- | --- | --- | --- |
| 1 | `Register` | 7 | Refund |
| 2 | `Renew` | 8 | Deduction |
| 3 | `Transfer` | 9 | PreRegister |
| 4 | `Restore` | 10 | Shopping |
| 5 | `Deposit` | 11 | ResellerPayment |
| 6 | `Backorder` | 12 | InternalTransfer |
| status | Name | Meaning |
| --- | --- | --- |
| 1 | `Success` | Applied. |
| 0 | `Failed` | The movement did not take effect. |
| 2 | `Canceled` | Cancelled. |
| 3 | `Processing` | In progress. |
| 4 | `Refunded` | Refunded — e.g. an SSL whose 7-day window lapsed, or a hosting whose provisioning failed. |
`chargeType`: `0` Add (a credit — top-up or refund) · `1` Subtract (a debit — a purchase).
:::tip[Reconciliation tips]
- **`traceId` is your key.** Log it against the operation in your own system. When you need support, quoting it finds the transaction instantly.
- `productId` is the domain ID or certificate ID the charge belongs to — join on it to match charges to objects.
- A **refunded purchase appears as two rows**: the original debit with status `Refunded`, and a separate credit of type `Refund`. Match them on `traceId` so you do not double-count.
- `oldBalance` and `balance` let you verify the running total without recomputing it.
:::
---
# TLDs
> Every extension we sell, with its terms, transfer rules and special requirements. Each one links to a page with ready-to-send JSON payloads.
731 extensions, from the TLD catalogue on 2026-11-02. Select one to see its rules, its extra registry fields and the JSON to register, renew and transfer it.
In your integration, read the same data live from [`GET /api/v1/products/tlds`](https://www.domainnameapi.com/docs/catalogue/) — it is free and never rate-limited. These pages are for reading.
The columns answer "what will this extension ask of me?": the registration terms in years, whether transfers in are possible, how many extra registry fields it has, and whether it needs registry documents, the trustee service, DNSSEC support, non-ASCII names or the test environment.
| TLD | Register (years) | Transfer in | Extra fields | Documents | Trustee | DNSSEC | IDN | Test env. |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| [.abogado](https://www.domainnameapi.com/docs/tlds/abogado/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.ac](https://www.domainnameapi.com/docs/tlds/ac/) | 1–5 | Yes | — | — | — | No | Yes | Yes |
| [.ac.nz](https://www.domainnameapi.com/docs/tlds/ac.nz/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.aca.pro](https://www.domainnameapi.com/docs/tlds/aca.pro/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.academy](https://www.domainnameapi.com/docs/tlds/academy/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.accountant](https://www.domainnameapi.com/docs/tlds/accountant/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.accountants](https://www.domainnameapi.com/docs/tlds/accountants/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.actor](https://www.domainnameapi.com/docs/tlds/actor/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.adult](https://www.domainnameapi.com/docs/tlds/adult/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.ae](https://www.domainnameapi.com/docs/tlds/ae/) | 1–5 | Yes | — | — | — | Yes | Yes | Yes |
| [.aero](https://www.domainnameapi.com/docs/tlds/aero/) | 1–10 | Yes | 2 | Required | — | Yes | No | Yes |
| [.africa](https://www.domainnameapi.com/docs/tlds/africa/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.africa.com](https://www.domainnameapi.com/docs/tlds/africa.com/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.ag](https://www.domainnameapi.com/docs/tlds/ag/) | 1–10 | Yes | — | — | — | No | Yes | Yes |
| [.agency](https://www.domainnameapi.com/docs/tlds/agency/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.ai](https://www.domainnameapi.com/docs/tlds/ai/) | 2, 4, 6, 8, 10 | Yes | — | — | — | Yes | Yes | Yes |
| [.airforce](https://www.domainnameapi.com/docs/tlds/airforce/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.am](https://www.domainnameapi.com/docs/tlds/am/) | 1–5 | Yes | — | — | — | No | Yes | Yes |
| [.amsterdam](https://www.domainnameapi.com/docs/tlds/amsterdam/) | 1–10 | Yes | 2 | — | — | Yes | Yes | Yes |
| [.apartments](https://www.domainnameapi.com/docs/tlds/apartments/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.app](https://www.domainnameapi.com/docs/tlds/app/) | 1–10 | Yes | 1 | — | — | Yes | Yes | Yes |
| [.archi](https://www.domainnameapi.com/docs/tlds/archi/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.army](https://www.domainnameapi.com/docs/tlds/army/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.art](https://www.domainnameapi.com/docs/tlds/art/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.as](https://www.domainnameapi.com/docs/tlds/as/) | 2 | Yes | — | — | — | Yes | Yes | Yes |
| [.asia](https://www.domainnameapi.com/docs/tlds/asia/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.associates](https://www.domainnameapi.com/docs/tlds/associates/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.at](https://www.domainnameapi.com/docs/tlds/at/) | 1 | Yes | — | — | — | No | Yes | Yes |
| [.attorney](https://www.domainnameapi.com/docs/tlds/attorney/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.au](https://www.domainnameapi.com/docs/tlds/au/) | 1–10 | Yes | 8 | — | — | Yes | Yes | Yes |
| [.auction](https://www.domainnameapi.com/docs/tlds/auction/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.audio](https://www.domainnameapi.com/docs/tlds/audio/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.auto](https://www.domainnameapi.com/docs/tlds/auto/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.autos](https://www.domainnameapi.com/docs/tlds/autos/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.av.tr](https://www.domainnameapi.com/docs/tlds/av.tr/) | 1–5 | Yes | 4 | Required | — | Yes | No | Yes |
| [.baby](https://www.domainnameapi.com/docs/tlds/baby/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.band](https://www.domainnameapi.com/docs/tlds/band/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.bank](https://www.domainnameapi.com/docs/tlds/bank/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.bar](https://www.domainnameapi.com/docs/tlds/bar/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.bargains](https://www.domainnameapi.com/docs/tlds/bargains/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.bayern](https://www.domainnameapi.com/docs/tlds/bayern/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.bbs.tr](https://www.domainnameapi.com/docs/tlds/bbs.tr/) | 1–5 | Yes | 4 | Required | — | Yes | Yes | Yes |
| [.be](https://www.domainnameapi.com/docs/tlds/be/) | 1 | Yes | — | — | — | Yes | Yes | Yes |
| [.beauty](https://www.domainnameapi.com/docs/tlds/beauty/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.beer](https://www.domainnameapi.com/docs/tlds/beer/) | 1–10 | Yes | — | — | — | Yes | No | Yes |
| [.bel.tr](https://www.domainnameapi.com/docs/tlds/bel.tr/) | 1–5 | Yes | 4 | Required | — | Yes | Yes | Yes |
| [.berlin](https://www.domainnameapi.com/docs/tlds/berlin/) | 1–10 | Yes | — | — | Available | Yes | Yes | Yes |
| [.best](https://www.domainnameapi.com/docs/tlds/best/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.bet](https://www.domainnameapi.com/docs/tlds/bet/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.bh](https://www.domainnameapi.com/docs/tlds/bh/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.bible](https://www.domainnameapi.com/docs/tlds/bible/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.bid](https://www.domainnameapi.com/docs/tlds/bid/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.bike](https://www.domainnameapi.com/docs/tlds/bike/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.bingo](https://www.domainnameapi.com/docs/tlds/bingo/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.bio](https://www.domainnameapi.com/docs/tlds/bio/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.biz](https://www.domainnameapi.com/docs/tlds/biz/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.biz.pl](https://www.domainnameapi.com/docs/tlds/biz.pl/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.biz.tr](https://www.domainnameapi.com/docs/tlds/biz.tr/) | 1–5 | Yes | 4 | Required | — | Yes | Yes | Yes |
| [.black](https://www.domainnameapi.com/docs/tlds/black/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.blackfriday](https://www.domainnameapi.com/docs/tlds/blackfriday/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.blog](https://www.domainnameapi.com/docs/tlds/blog/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.blue](https://www.domainnameapi.com/docs/tlds/blue/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.boats](https://www.domainnameapi.com/docs/tlds/boats/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.bond](https://www.domainnameapi.com/docs/tlds/bond/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.boston](https://www.domainnameapi.com/docs/tlds/boston/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.boutique](https://www.domainnameapi.com/docs/tlds/boutique/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.br.com](https://www.domainnameapi.com/docs/tlds/br.com/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.broker](https://www.domainnameapi.com/docs/tlds/broker/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.brussels](https://www.domainnameapi.com/docs/tlds/brussels/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.build](https://www.domainnameapi.com/docs/tlds/build/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.builders](https://www.domainnameapi.com/docs/tlds/builders/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.business](https://www.domainnameapi.com/docs/tlds/business/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.buzz](https://www.domainnameapi.com/docs/tlds/buzz/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.bz](https://www.domainnameapi.com/docs/tlds/bz/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.ca](https://www.domainnameapi.com/docs/tlds/ca/) | 1–10 | Yes | 2 | Required | — | Yes | Yes | Yes |
| [.cab](https://www.domainnameapi.com/docs/tlds/cab/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.cafe](https://www.domainnameapi.com/docs/tlds/cafe/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.cam](https://www.domainnameapi.com/docs/tlds/cam/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.camera](https://www.domainnameapi.com/docs/tlds/camera/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.camp](https://www.domainnameapi.com/docs/tlds/camp/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.capetown](https://www.domainnameapi.com/docs/tlds/capetown/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.capital](https://www.domainnameapi.com/docs/tlds/capital/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.car](https://www.domainnameapi.com/docs/tlds/car/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.cards](https://www.domainnameapi.com/docs/tlds/cards/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.care](https://www.domainnameapi.com/docs/tlds/care/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.careers](https://www.domainnameapi.com/docs/tlds/careers/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.cars](https://www.domainnameapi.com/docs/tlds/cars/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.casa](https://www.domainnameapi.com/docs/tlds/casa/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.cash](https://www.domainnameapi.com/docs/tlds/cash/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.casino](https://www.domainnameapi.com/docs/tlds/casino/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.cat](https://www.domainnameapi.com/docs/tlds/cat/) | 1–10 | Yes | 1 | — | — | Yes | Yes | Yes |
| [.catering](https://www.domainnameapi.com/docs/tlds/catering/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.cc](https://www.domainnameapi.com/docs/tlds/cc/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.center](https://www.domainnameapi.com/docs/tlds/center/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.ceo](https://www.domainnameapi.com/docs/tlds/ceo/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.cf](https://www.domainnameapi.com/docs/tlds/cf/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.cfd](https://www.domainnameapi.com/docs/tlds/cfd/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.ch](https://www.domainnameapi.com/docs/tlds/ch/) | 1 | No | — | Required | — | No | Yes | Yes |
| [.charity](https://www.domainnameapi.com/docs/tlds/charity/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.chat](https://www.domainnameapi.com/docs/tlds/chat/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.cheap](https://www.domainnameapi.com/docs/tlds/cheap/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.christmas](https://www.domainnameapi.com/docs/tlds/christmas/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.church](https://www.domainnameapi.com/docs/tlds/church/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.city](https://www.domainnameapi.com/docs/tlds/city/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.cl](https://www.domainnameapi.com/docs/tlds/cl/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.claims](https://www.domainnameapi.com/docs/tlds/claims/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.cleaning](https://www.domainnameapi.com/docs/tlds/cleaning/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.click](https://www.domainnameapi.com/docs/tlds/click/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.clinic](https://www.domainnameapi.com/docs/tlds/clinic/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.clothing](https://www.domainnameapi.com/docs/tlds/clothing/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.cloud](https://www.domainnameapi.com/docs/tlds/cloud/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.club](https://www.domainnameapi.com/docs/tlds/club/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.cm](https://www.domainnameapi.com/docs/tlds/cm/) | 1–5 | Yes | — | — | — | Yes | No | Yes |
| [.cn](https://www.domainnameapi.com/docs/tlds/cn/) | 1–5 | Yes | 3 | Required | — | Yes | Yes | Yes |
| [.cn.com](https://www.domainnameapi.com/docs/tlds/cn.com/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.co](https://www.domainnameapi.com/docs/tlds/co/) | 1–5 | Yes | — | — | — | No | Yes | Yes |
| [.co.ag](https://www.domainnameapi.com/docs/tlds/co.ag/) | 1–10 | Yes | — | — | — | Yes | No | Yes |
| [.co.am](https://www.domainnameapi.com/docs/tlds/co.am/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.co.at](https://www.domainnameapi.com/docs/tlds/co.at/) | 1 | Yes | — | — | — | Yes | Yes | Yes |
| [.co.com](https://www.domainnameapi.com/docs/tlds/co.com/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.co.gy](https://www.domainnameapi.com/docs/tlds/co.gy/) | 1–4 | Yes | — | — | — | Yes | Yes | Yes |
| [.co.id](https://www.domainnameapi.com/docs/tlds/co.id/) | 1 | Yes | — | — | Available | Yes | Yes | Yes |
| [.co.il](https://www.domainnameapi.com/docs/tlds/co.il/) | 1, 2 | Yes | 1 | — | — | Yes | Yes | Yes |
| [.co.in](https://www.domainnameapi.com/docs/tlds/co.in/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.co.it](https://www.domainnameapi.com/docs/tlds/co.it/) | 1 | Yes | 8 | — | — | Yes | Yes | Yes |
| [.co.mu](https://www.domainnameapi.com/docs/tlds/co.mu/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.co.nl](https://www.domainnameapi.com/docs/tlds/co.nl/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.co.no](https://www.domainnameapi.com/docs/tlds/co.no/) | 1 | Yes | — | — | — | Yes | Yes | Yes |
| [.co.nz](https://www.domainnameapi.com/docs/tlds/co.nz/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.co.uk](https://www.domainnameapi.com/docs/tlds/co.uk/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.co.ve](https://www.domainnameapi.com/docs/tlds/co.ve/) | 1 | Yes | — | — | — | Yes | Yes | Yes |
| [.co.za](https://www.domainnameapi.com/docs/tlds/co.za/) | 1 | Yes | — | — | — | Yes | Yes | Yes |
| [.coach](https://www.domainnameapi.com/docs/tlds/coach/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.codes](https://www.domainnameapi.com/docs/tlds/codes/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.coffee](https://www.domainnameapi.com/docs/tlds/coffee/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.college](https://www.domainnameapi.com/docs/tlds/college/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.cologne](https://www.domainnameapi.com/docs/tlds/cologne/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.com](https://www.domainnameapi.com/docs/tlds/com/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.com.ag](https://www.domainnameapi.com/docs/tlds/com.ag/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.com.ai](https://www.domainnameapi.com/docs/tlds/com.ai/) | 2, 4, 6, 8, 10 | Yes | — | — | — | Yes | Yes | Yes |
| [.com.am](https://www.domainnameapi.com/docs/tlds/com.am/) | 1–5 | Yes | — | — | — | Yes | Yes | Yes |
| [.com.ar](https://www.domainnameapi.com/docs/tlds/com.ar/) | 1 | Yes | — | — | — | Yes | Yes | Yes |
| [.com.au](https://www.domainnameapi.com/docs/tlds/com.au/) | 1–5 | Yes | 8 | Required | — | Yes | Yes | Yes |
| [.com.bh](https://www.domainnameapi.com/docs/tlds/com.bh/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.com.br](https://www.domainnameapi.com/docs/tlds/com.br/) | 1–10 | Yes | 1 | — | — | Yes | Yes | Yes |
| [.com.bz](https://www.domainnameapi.com/docs/tlds/com.bz/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.com.cm](https://www.domainnameapi.com/docs/tlds/com.cm/) | 1–10 | Yes | — | — | — | Yes | No | Yes |
| [.com.cn](https://www.domainnameapi.com/docs/tlds/com.cn/) | 1–5 | Yes | 3 | — | Available | Yes | Yes | Yes |
| [.com.co](https://www.domainnameapi.com/docs/tlds/com.co/) | 1–5 | Yes | — | — | — | Yes | Yes | Yes |
| [.com.de](https://www.domainnameapi.com/docs/tlds/com.de/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.com.ec](https://www.domainnameapi.com/docs/tlds/com.ec/) | 1–10 | Yes | — | — | — | Yes | No | Yes |
| [.com.es](https://www.domainnameapi.com/docs/tlds/com.es/) | 1–5, 10 | Yes | 12 | — | — | Yes | Yes | Yes |
| [.com.ge](https://www.domainnameapi.com/docs/tlds/com.ge/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.com.gl](https://www.domainnameapi.com/docs/tlds/com.gl/) | 1, 2 | Yes | — | — | — | Yes | Yes | Yes |
| [.com.gr](https://www.domainnameapi.com/docs/tlds/com.gr/) | 2, 4, 6, 8, 10 | Yes | — | — | — | Yes | Yes | Yes |
| [.com.gy](https://www.domainnameapi.com/docs/tlds/com.gy/) | 1–4 | Yes | — | — | — | Yes | Yes | Yes |
| [.com.hk](https://www.domainnameapi.com/docs/tlds/com.hk/) | 1–5 | Yes | 6 | Required | — | Yes | Yes | Yes |
| [.com.hn](https://www.domainnameapi.com/docs/tlds/com.hn/) | 1–5 | Yes | — | — | — | Yes | Yes | Yes |
| [.com.ht](https://www.domainnameapi.com/docs/tlds/com.ht/) | 1–5 | Yes | — | — | — | Yes | Yes | Yes |
| [.com.im](https://www.domainnameapi.com/docs/tlds/com.im/) | 1–5 | Yes | — | — | — | Yes | Yes | Yes |
| [.com.kz](https://www.domainnameapi.com/docs/tlds/com.kz/) | 1–10 | Yes | 2 | — | — | Yes | Yes | Yes |
| [.com.lc](https://www.domainnameapi.com/docs/tlds/com.lc/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.com.lv](https://www.domainnameapi.com/docs/tlds/com.lv/) | 1 | Yes | 3 | — | — | Yes | Yes | Yes |
| [.com.mg](https://www.domainnameapi.com/docs/tlds/com.mg/) | 1–5 | Yes | — | — | — | Yes | Yes | Yes |
| [.com.mk](https://www.domainnameapi.com/docs/tlds/com.mk/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.com.ms](https://www.domainnameapi.com/docs/tlds/com.ms/) | 1–10 | Yes | — | — | — | Yes | No | Yes |
| [.com.mu](https://www.domainnameapi.com/docs/tlds/com.mu/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.com.mx](https://www.domainnameapi.com/docs/tlds/com.mx/) | 1–10 | Yes | — | — | — | Yes | No | Yes |
| [.com.my](https://www.domainnameapi.com/docs/tlds/com.my/) | 1–5 | Yes | — | — | — | Yes | Yes | Yes |
| [.com.ng](https://www.domainnameapi.com/docs/tlds/com.ng/) | 1–5 | Yes | — | — | — | Yes | Yes | Yes |
| [.com.pe](https://www.domainnameapi.com/docs/tlds/com.pe/) | 1–5 | Yes | — | — | — | Yes | No | Yes |
| [.com.ph](https://www.domainnameapi.com/docs/tlds/com.ph/) | 1–5, 10 | Yes | — | — | — | Yes | No | Yes |
| [.com.pl](https://www.domainnameapi.com/docs/tlds/com.pl/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.com.ps](https://www.domainnameapi.com/docs/tlds/com.ps/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.com.pt](https://www.domainnameapi.com/docs/tlds/com.pt/) | 1–5 | Yes | 2 | — | — | Yes | Yes | Yes |
| [.com.qa](https://www.domainnameapi.com/docs/tlds/com.qa/) | 1–5 | Yes | — | — | — | Yes | Yes | Yes |
| [.com.ro](https://www.domainnameapi.com/docs/tlds/com.ro/) | 1 | Yes | 3 | — | — | Yes | Yes | Yes |
| [.com.ru](https://www.domainnameapi.com/docs/tlds/com.ru/) | 1 | Yes | 8 | — | — | Yes | No | Yes |
| [.com.sb](https://www.domainnameapi.com/docs/tlds/com.sb/) | 1–10 | Yes | — | — | — | Yes | No | Yes |
| [.com.sc](https://www.domainnameapi.com/docs/tlds/com.sc/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.com.se](https://www.domainnameapi.com/docs/tlds/com.se/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.com.sg](https://www.domainnameapi.com/docs/tlds/com.sg/) | 1, 2 | Yes | 2 | — | — | Yes | Yes | Yes |
| [.com.so](https://www.domainnameapi.com/docs/tlds/com.so/) | 1–10 | Yes | — | — | — | Yes | No | Yes |
| [.com.tc](https://www.domainnameapi.com/docs/tlds/com.tc/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.com.tr](https://www.domainnameapi.com/docs/tlds/com.tr/) | 1–5 | Yes | 4 | Required | — | Yes | Yes | Yes |
| [.com.tw](https://www.domainnameapi.com/docs/tlds/com.tw/) | 1–10 | Yes | 1 | — | — | Yes | Yes | Yes |
| [.com.vc](https://www.domainnameapi.com/docs/tlds/com.vc/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.com.ve](https://www.domainnameapi.com/docs/tlds/com.ve/) | 1 | Yes | — | — | — | Yes | Yes | Yes |
| [.community](https://www.domainnameapi.com/docs/tlds/community/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.company](https://www.domainnameapi.com/docs/tlds/company/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.compare](https://www.domainnameapi.com/docs/tlds/compare/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.computer](https://www.domainnameapi.com/docs/tlds/computer/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.condos](https://www.domainnameapi.com/docs/tlds/condos/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.construction](https://www.domainnameapi.com/docs/tlds/construction/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.consulting](https://www.domainnameapi.com/docs/tlds/consulting/) | 1–5 | Yes | — | — | — | Yes | Yes | Yes |
| [.contact](https://www.domainnameapi.com/docs/tlds/contact/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.contractors](https://www.domainnameapi.com/docs/tlds/contractors/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.cooking](https://www.domainnameapi.com/docs/tlds/cooking/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.cool](https://www.domainnameapi.com/docs/tlds/cool/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.coop](https://www.domainnameapi.com/docs/tlds/coop/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.country](https://www.domainnameapi.com/docs/tlds/country/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.coupons](https://www.domainnameapi.com/docs/tlds/coupons/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.courses](https://www.domainnameapi.com/docs/tlds/courses/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.credit](https://www.domainnameapi.com/docs/tlds/credit/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.creditcard](https://www.domainnameapi.com/docs/tlds/creditcard/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.cricket](https://www.domainnameapi.com/docs/tlds/cricket/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.cruises](https://www.domainnameapi.com/docs/tlds/cruises/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.cv](https://www.domainnameapi.com/docs/tlds/cv/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.cx](https://www.domainnameapi.com/docs/tlds/cx/) | 1–5 | Yes | — | — | — | Yes | Yes | Yes |
| [.cymru](https://www.domainnameapi.com/docs/tlds/cymru/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.cyou](https://www.domainnameapi.com/docs/tlds/cyou/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.cz](https://www.domainnameapi.com/docs/tlds/cz/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.dad](https://www.domainnameapi.com/docs/tlds/dad/) | — | Yes | — | — | — | Yes | Yes | Yes |
| [.dance](https://www.domainnameapi.com/docs/tlds/dance/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.date](https://www.domainnameapi.com/docs/tlds/date/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.dating](https://www.domainnameapi.com/docs/tlds/dating/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.day](https://www.domainnameapi.com/docs/tlds/day/) | — | Yes | — | — | — | Yes | Yes | Yes |
| [.de](https://www.domainnameapi.com/docs/tlds/de/) | 1–10 | Yes | — | Required | — | No | No | Yes |
| [.de.com](https://www.domainnameapi.com/docs/tlds/de.com/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.deals](https://www.domainnameapi.com/docs/tlds/deals/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.degree](https://www.domainnameapi.com/docs/tlds/degree/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.delivery](https://www.domainnameapi.com/docs/tlds/delivery/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.democrat](https://www.domainnameapi.com/docs/tlds/democrat/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.dental](https://www.domainnameapi.com/docs/tlds/dental/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.dentist](https://www.domainnameapi.com/docs/tlds/dentist/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.desi](https://www.domainnameapi.com/docs/tlds/desi/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.design](https://www.domainnameapi.com/docs/tlds/design/) | 1–10 | Yes | — | — | — | Yes | No | Yes |
| [.dev](https://www.domainnameapi.com/docs/tlds/dev/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.diamonds](https://www.domainnameapi.com/docs/tlds/diamonds/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.diet](https://www.domainnameapi.com/docs/tlds/diet/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.digital](https://www.domainnameapi.com/docs/tlds/digital/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.direct](https://www.domainnameapi.com/docs/tlds/direct/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.directory](https://www.domainnameapi.com/docs/tlds/directory/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.discount](https://www.domainnameapi.com/docs/tlds/discount/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.diy](https://www.domainnameapi.com/docs/tlds/diy/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.dk](https://www.domainnameapi.com/docs/tlds/dk/) | 1–5 | Yes | 7 | Required | — | Yes | Yes | Yes |
| [.dm](https://www.domainnameapi.com/docs/tlds/dm/) | — | Yes | — | — | — | Yes | Yes | Yes |
| [.doctor](https://www.domainnameapi.com/docs/tlds/doctor/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.dog](https://www.domainnameapi.com/docs/tlds/dog/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.domains](https://www.domainnameapi.com/docs/tlds/domains/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.download](https://www.domainnameapi.com/docs/tlds/download/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.dr.tr](https://www.domainnameapi.com/docs/tlds/dr.tr/) | 1–5 | Yes | 4 | Required | — | Yes | Yes | Yes |
| [.durban](https://www.domainnameapi.com/docs/tlds/durban/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.earth](https://www.domainnameapi.com/docs/tlds/earth/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.ec](https://www.domainnameapi.com/docs/tlds/ec/) | 1–10 | Yes | — | — | — | Yes | No | Yes |
| [.eco](https://www.domainnameapi.com/docs/tlds/eco/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.edu.pl](https://www.domainnameapi.com/docs/tlds/edu.pl/) | 1, 10 | Yes | — | — | — | Yes | Yes | Yes |
| [.edu.tr](https://www.domainnameapi.com/docs/tlds/edu.tr/) | 1–5 | Yes | 4 | Required | — | Yes | Yes | Yes |
| [.education](https://www.domainnameapi.com/docs/tlds/education/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.ee](https://www.domainnameapi.com/docs/tlds/ee/) | 1–10 | Yes | 3 | — | — | Yes | Yes | Yes |
| [.email](https://www.domainnameapi.com/docs/tlds/email/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.energy](https://www.domainnameapi.com/docs/tlds/energy/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.engineer](https://www.domainnameapi.com/docs/tlds/engineer/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.engineering](https://www.domainnameapi.com/docs/tlds/engineering/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.enterprises](https://www.domainnameapi.com/docs/tlds/enterprises/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.equipment](https://www.domainnameapi.com/docs/tlds/equipment/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.es](https://www.domainnameapi.com/docs/tlds/es/) | 1–10 | Yes | 12 | — | — | No | Yes | Yes |
| [.estate](https://www.domainnameapi.com/docs/tlds/estate/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.eu](https://www.domainnameapi.com/docs/tlds/eu/) | 1–10 | Yes | 4 | — | Available | Yes | Yes | Yes |
| [.eu.com](https://www.domainnameapi.com/docs/tlds/eu.com/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.events](https://www.domainnameapi.com/docs/tlds/events/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.exchange](https://www.domainnameapi.com/docs/tlds/exchange/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.expert](https://www.domainnameapi.com/docs/tlds/expert/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.exposed](https://www.domainnameapi.com/docs/tlds/exposed/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.express](https://www.domainnameapi.com/docs/tlds/express/) | 1, 2 | No | — | — | — | No | No | No |
| [.fail](https://www.domainnameapi.com/docs/tlds/fail/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.faith](https://www.domainnameapi.com/docs/tlds/faith/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.family](https://www.domainnameapi.com/docs/tlds/family/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.fan](https://www.domainnameapi.com/docs/tlds/fan/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.fans](https://www.domainnameapi.com/docs/tlds/fans/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.farm](https://www.domainnameapi.com/docs/tlds/farm/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.fashion](https://www.domainnameapi.com/docs/tlds/fashion/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.feedback](https://www.domainnameapi.com/docs/tlds/feedback/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.fi](https://www.domainnameapi.com/docs/tlds/fi/) | 1–5 | Yes | 4 | Required | — | Yes | Yes | Yes |
| [.film](https://www.domainnameapi.com/docs/tlds/film/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.finance](https://www.domainnameapi.com/docs/tlds/finance/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.financial](https://www.domainnameapi.com/docs/tlds/financial/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.fish](https://www.domainnameapi.com/docs/tlds/fish/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.fishing](https://www.domainnameapi.com/docs/tlds/fishing/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.fit](https://www.domainnameapi.com/docs/tlds/fit/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.fitness](https://www.domainnameapi.com/docs/tlds/fitness/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.flights](https://www.domainnameapi.com/docs/tlds/flights/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.florist](https://www.domainnameapi.com/docs/tlds/florist/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.flowers](https://www.domainnameapi.com/docs/tlds/flowers/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.fm](https://www.domainnameapi.com/docs/tlds/fm/) | 1–5 | Yes | — | — | — | Yes | Yes | Yes |
| [.fo](https://www.domainnameapi.com/docs/tlds/fo/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.food](https://www.domainnameapi.com/docs/tlds/food/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.football](https://www.domainnameapi.com/docs/tlds/football/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.forex](https://www.domainnameapi.com/docs/tlds/forex/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.forsale](https://www.domainnameapi.com/docs/tlds/forsale/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.forum](https://www.domainnameapi.com/docs/tlds/forum/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.foundation](https://www.domainnameapi.com/docs/tlds/foundation/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.fr](https://www.domainnameapi.com/docs/tlds/fr/) | 1–10 | Yes | 15 | Required | Available | Yes | Yes | Yes |
| [.frl](https://www.domainnameapi.com/docs/tlds/frl/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.fun](https://www.domainnameapi.com/docs/tlds/fun/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.fund](https://www.domainnameapi.com/docs/tlds/fund/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.furniture](https://www.domainnameapi.com/docs/tlds/furniture/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.futbol](https://www.domainnameapi.com/docs/tlds/futbol/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.fyi](https://www.domainnameapi.com/docs/tlds/fyi/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.gallery](https://www.domainnameapi.com/docs/tlds/gallery/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.game](https://www.domainnameapi.com/docs/tlds/game/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.games](https://www.domainnameapi.com/docs/tlds/games/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.garden](https://www.domainnameapi.com/docs/tlds/garden/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.gay](https://www.domainnameapi.com/docs/tlds/gay/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.gd](https://www.domainnameapi.com/docs/tlds/gd/) | 1–10 | Yes | — | — | — | Yes | No | Yes |
| [.ge](https://www.domainnameapi.com/docs/tlds/ge/) | 1–10 | Yes | — | — | — | Yes | No | Yes |
| [.gen.tr](https://www.domainnameapi.com/docs/tlds/gen.tr/) | 1–5 | Yes | 4 | Required | — | Yes | Yes | Yes |
| [.gg](https://www.domainnameapi.com/docs/tlds/gg/) | 1, 2 | Yes | — | — | — | Yes | Yes | Yes |
| [.gift](https://www.domainnameapi.com/docs/tlds/gift/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.gifts](https://www.domainnameapi.com/docs/tlds/gifts/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.gives](https://www.domainnameapi.com/docs/tlds/gives/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.giving](https://www.domainnameapi.com/docs/tlds/giving/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.gl](https://www.domainnameapi.com/docs/tlds/gl/) | 1, 2 | Yes | — | — | — | Yes | Yes | Yes |
| [.glass](https://www.domainnameapi.com/docs/tlds/glass/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.global](https://www.domainnameapi.com/docs/tlds/global/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.gmbh](https://www.domainnameapi.com/docs/tlds/gmbh/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.gold](https://www.domainnameapi.com/docs/tlds/gold/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.golf](https://www.domainnameapi.com/docs/tlds/golf/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.gov.tr](https://www.domainnameapi.com/docs/tlds/gov.tr/) | 1–5 | Yes | 4 | Required | — | Yes | Yes | Yes |
| [.gr](https://www.domainnameapi.com/docs/tlds/gr/) | 2, 4, 6, 8, 10 | Yes | — | — | — | Yes | Yes | Yes |
| [.gr.com](https://www.domainnameapi.com/docs/tlds/gr.com/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.graphics](https://www.domainnameapi.com/docs/tlds/graphics/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.gratis](https://www.domainnameapi.com/docs/tlds/gratis/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.green](https://www.domainnameapi.com/docs/tlds/green/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.gripe](https://www.domainnameapi.com/docs/tlds/gripe/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.group](https://www.domainnameapi.com/docs/tlds/group/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.gs](https://www.domainnameapi.com/docs/tlds/gs/) | 1–5 | Yes | — | — | — | Yes | No | Yes |
| [.guide](https://www.domainnameapi.com/docs/tlds/guide/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.guitars](https://www.domainnameapi.com/docs/tlds/guitars/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.guru](https://www.domainnameapi.com/docs/tlds/guru/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.gy](https://www.domainnameapi.com/docs/tlds/gy/) | 1–4 | Yes | — | — | — | Yes | No | Yes |
| [.hair](https://www.domainnameapi.com/docs/tlds/hair/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.hamburg](https://www.domainnameapi.com/docs/tlds/hamburg/) | 1–10 | Yes | — | — | Available | Yes | Yes | Yes |
| [.haus](https://www.domainnameapi.com/docs/tlds/haus/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.health](https://www.domainnameapi.com/docs/tlds/health/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.healthcare](https://www.domainnameapi.com/docs/tlds/healthcare/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.help](https://www.domainnameapi.com/docs/tlds/help/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.hiphop](https://www.domainnameapi.com/docs/tlds/hiphop/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.hiv](https://www.domainnameapi.com/docs/tlds/hiv/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.hk](https://www.domainnameapi.com/docs/tlds/hk/) | 1–5 | Yes | 6 | Required | — | Yes | Yes | Yes |
| [.hn](https://www.domainnameapi.com/docs/tlds/hn/) | 1–10 | Yes | — | — | — | Yes | No | Yes |
| [.hockey](https://www.domainnameapi.com/docs/tlds/hockey/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.holdings](https://www.domainnameapi.com/docs/tlds/holdings/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.holiday](https://www.domainnameapi.com/docs/tlds/holiday/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.homes](https://www.domainnameapi.com/docs/tlds/homes/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.horse](https://www.domainnameapi.com/docs/tlds/horse/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.hospital](https://www.domainnameapi.com/docs/tlds/hospital/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.host](https://www.domainnameapi.com/docs/tlds/host/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.hosting](https://www.domainnameapi.com/docs/tlds/hosting/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.house](https://www.domainnameapi.com/docs/tlds/house/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.how](https://www.domainnameapi.com/docs/tlds/how/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.ht](https://www.domainnameapi.com/docs/tlds/ht/) | 1–5 | Yes | — | — | — | Yes | No | Yes |
| [.hu](https://www.domainnameapi.com/docs/tlds/hu/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.icu](https://www.domainnameapi.com/docs/tlds/icu/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.id](https://www.domainnameapi.com/docs/tlds/id/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.id.au](https://www.domainnameapi.com/docs/tlds/id.au/) | 1–10 | Yes | 8 | — | — | Yes | Yes | Yes |
| [.ie](https://www.domainnameapi.com/docs/tlds/ie/) | 1–10 | Yes | 4 | Required | — | Yes | Yes | Yes |
| [.im](https://www.domainnameapi.com/docs/tlds/im/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.immo](https://www.domainnameapi.com/docs/tlds/immo/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.immobilien](https://www.domainnameapi.com/docs/tlds/immobilien/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.in](https://www.domainnameapi.com/docs/tlds/in/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.inc](https://www.domainnameapi.com/docs/tlds/inc/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.ind.in](https://www.domainnameapi.com/docs/tlds/ind.in/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.industries](https://www.domainnameapi.com/docs/tlds/industries/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.info](https://www.domainnameapi.com/docs/tlds/info/) | 1–7 | Yes | — | — | — | Yes | Yes | Yes |
| [.info.tr](https://www.domainnameapi.com/docs/tlds/info.tr/) | 1–5 | Yes | 4 | Required | — | Yes | Yes | Yes |
| [.ink](https://www.domainnameapi.com/docs/tlds/ink/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.institute](https://www.domainnameapi.com/docs/tlds/institute/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.insure](https://www.domainnameapi.com/docs/tlds/insure/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.international](https://www.domainnameapi.com/docs/tlds/international/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.investments](https://www.domainnameapi.com/docs/tlds/investments/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.io](https://www.domainnameapi.com/docs/tlds/io/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.irish](https://www.domainnameapi.com/docs/tlds/irish/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.is](https://www.domainnameapi.com/docs/tlds/is/) | 1 | Yes | — | — | — | Yes | Yes | Yes |
| [.ist](https://www.domainnameapi.com/docs/tlds/ist/) | 1–10 | Yes | — | — | — | Yes | No | Yes |
| [.istanbul](https://www.domainnameapi.com/docs/tlds/istanbul/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.it](https://www.domainnameapi.com/docs/tlds/it/) | 1 | Yes | 8 | Required | Available | No | Yes | Yes |
| [.it.com](https://www.domainnameapi.com/docs/tlds/it.com/) | 1–10 | Yes | — | — | — | Yes | Yes | No |
| [.je](https://www.domainnameapi.com/docs/tlds/je/) | 1, 2 | Yes | — | — | — | Yes | Yes | Yes |
| [.jetzt](https://www.domainnameapi.com/docs/tlds/jetzt/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.jewelry](https://www.domainnameapi.com/docs/tlds/jewelry/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.jobs](https://www.domainnameapi.com/docs/tlds/jobs/) | 1–10 | Yes | 2 | — | — | Yes | Yes | Yes |
| [.joburg](https://www.domainnameapi.com/docs/tlds/joburg/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.jp](https://www.domainnameapi.com/docs/tlds/jp/) | 1 | Yes | — | Required | — | Yes | Yes | Yes |
| [.juegos](https://www.domainnameapi.com/docs/tlds/juegos/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.k12.tr](https://www.domainnameapi.com/docs/tlds/k12.tr/) | 1–5 | Yes | 4 | Required | — | Yes | Yes | Yes |
| [.kaufen](https://www.domainnameapi.com/docs/tlds/kaufen/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.kep.tr](https://www.domainnameapi.com/docs/tlds/kep.tr/) | 1–5 | Yes | 4 | Required | — | Yes | Yes | Yes |
| [.kim](https://www.domainnameapi.com/docs/tlds/kim/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.kitchen](https://www.domainnameapi.com/docs/tlds/kitchen/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.kiwi](https://www.domainnameapi.com/docs/tlds/kiwi/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.koeln](https://www.domainnameapi.com/docs/tlds/koeln/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.kyoto](https://www.domainnameapi.com/docs/tlds/kyoto/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.kz](https://www.domainnameapi.com/docs/tlds/kz/) | 1–10 | Yes | 2 | — | — | Yes | Yes | Yes |
| [.la](https://www.domainnameapi.com/docs/tlds/la/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.land](https://www.domainnameapi.com/docs/tlds/land/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.lat](https://www.domainnameapi.com/docs/tlds/lat/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.latino](https://www.domainnameapi.com/docs/tlds/latino/) | — | Yes | — | — | — | Yes | Yes | Yes |
| [.law](https://www.domainnameapi.com/docs/tlds/law/) | 1–10 | Yes | 1 | Required | — | Yes | Yes | Yes |
| [.lawyer](https://www.domainnameapi.com/docs/tlds/lawyer/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.lc](https://www.domainnameapi.com/docs/tlds/lc/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.lease](https://www.domainnameapi.com/docs/tlds/lease/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.legal](https://www.domainnameapi.com/docs/tlds/legal/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.lgbt](https://www.domainnameapi.com/docs/tlds/lgbt/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.li](https://www.domainnameapi.com/docs/tlds/li/) | 1 | Yes | — | — | — | Yes | Yes | Yes |
| [.life](https://www.domainnameapi.com/docs/tlds/life/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.lifestyle](https://www.domainnameapi.com/docs/tlds/lifestyle/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.lighting](https://www.domainnameapi.com/docs/tlds/lighting/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.limited](https://www.domainnameapi.com/docs/tlds/limited/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.limo](https://www.domainnameapi.com/docs/tlds/limo/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.link](https://www.domainnameapi.com/docs/tlds/link/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.live](https://www.domainnameapi.com/docs/tlds/live/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.living](https://www.domainnameapi.com/docs/tlds/living/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.llc](https://www.domainnameapi.com/docs/tlds/llc/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.loan](https://www.domainnameapi.com/docs/tlds/loan/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.loans](https://www.domainnameapi.com/docs/tlds/loans/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.lol](https://www.domainnameapi.com/docs/tlds/lol/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.london](https://www.domainnameapi.com/docs/tlds/london/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.lotto](https://www.domainnameapi.com/docs/tlds/lotto/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.love](https://www.domainnameapi.com/docs/tlds/love/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.lt](https://www.domainnameapi.com/docs/tlds/lt/) | 1 | Yes | 1 | Required | — | Yes | Yes | Yes |
| [.ltd](https://www.domainnameapi.com/docs/tlds/ltd/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.ltda](https://www.domainnameapi.com/docs/tlds/ltda/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.lu](https://www.domainnameapi.com/docs/tlds/lu/) | 1 | Yes | — | — | — | Yes | Yes | Yes |
| [.luxe](https://www.domainnameapi.com/docs/tlds/luxe/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.luxury](https://www.domainnameapi.com/docs/tlds/luxury/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.lv](https://www.domainnameapi.com/docs/tlds/lv/) | 1 | Yes | 3 | Required | — | Yes | Yes | Yes |
| [.maison](https://www.domainnameapi.com/docs/tlds/maison/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.makeup](https://www.domainnameapi.com/docs/tlds/makeup/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.management](https://www.domainnameapi.com/docs/tlds/management/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.market](https://www.domainnameapi.com/docs/tlds/market/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.marketing](https://www.domainnameapi.com/docs/tlds/marketing/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.markets](https://www.domainnameapi.com/docs/tlds/markets/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.mba](https://www.domainnameapi.com/docs/tlds/mba/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.me](https://www.domainnameapi.com/docs/tlds/me/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.me.uk](https://www.domainnameapi.com/docs/tlds/me.uk/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.media](https://www.domainnameapi.com/docs/tlds/media/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.melbourne](https://www.domainnameapi.com/docs/tlds/melbourne/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.memorial](https://www.domainnameapi.com/docs/tlds/memorial/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.men](https://www.domainnameapi.com/docs/tlds/men/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.menu](https://www.domainnameapi.com/docs/tlds/menu/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.mg](https://www.domainnameapi.com/docs/tlds/mg/) | 1–5 | Yes | — | — | — | Yes | No | Yes |
| [.miami](https://www.domainnameapi.com/docs/tlds/miami/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.mk](https://www.domainnameapi.com/docs/tlds/mk/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.mn](https://www.domainnameapi.com/docs/tlds/mn/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.mobi](https://www.domainnameapi.com/docs/tlds/mobi/) | 1–10 | Yes | — | — | — | Yes | No | Yes |
| [.moda](https://www.domainnameapi.com/docs/tlds/moda/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.moe](https://www.domainnameapi.com/docs/tlds/moe/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.mom](https://www.domainnameapi.com/docs/tlds/mom/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.money](https://www.domainnameapi.com/docs/tlds/money/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.monster](https://www.domainnameapi.com/docs/tlds/monster/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.mortgage](https://www.domainnameapi.com/docs/tlds/mortgage/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.moscow](https://www.domainnameapi.com/docs/tlds/moscow/) | — | Yes | — | — | Available | No | Yes | Yes |
| [.motorcycles](https://www.domainnameapi.com/docs/tlds/motorcycles/) | 1–10 | No | — | — | — | Yes | No | Yes |
| [.movie](https://www.domainnameapi.com/docs/tlds/movie/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.ms](https://www.domainnameapi.com/docs/tlds/ms/) | 1–10 | Yes | — | — | — | Yes | No | Yes |
| [.mu](https://www.domainnameapi.com/docs/tlds/mu/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.music](https://www.domainnameapi.com/docs/tlds/music/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.mx](https://www.domainnameapi.com/docs/tlds/mx/) | 1–5 | Yes | — | — | — | Yes | Yes | Yes |
| [.my](https://www.domainnameapi.com/docs/tlds/my/) | 1–5 | Yes | — | — | — | Yes | Yes | Yes |
| [.nagoya](https://www.domainnameapi.com/docs/tlds/nagoya/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.name](https://www.domainnameapi.com/docs/tlds/name/) | 1–10 | Yes | 1 | — | — | Yes | Yes | Yes |
| [.name.tr](https://www.domainnameapi.com/docs/tlds/name.tr/) | 1–5 | Yes | 4 | Required | — | Yes | Yes | Yes |
| [.navy](https://www.domainnameapi.com/docs/tlds/navy/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.net](https://www.domainnameapi.com/docs/tlds/net/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.net.br](https://www.domainnameapi.com/docs/tlds/net.br/) | 1–10 | Yes | 1 | — | — | Yes | Yes | Yes |
| [.net.cn](https://www.domainnameapi.com/docs/tlds/net.cn/) | 1–5 | Yes | 3 | — | — | Yes | Yes | Yes |
| [.net.co](https://www.domainnameapi.com/docs/tlds/net.co/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.net.in](https://www.domainnameapi.com/docs/tlds/net.in/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.net.ng](https://www.domainnameapi.com/docs/tlds/net.ng/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.net.ru](https://www.domainnameapi.com/docs/tlds/net.ru/) | 1–5 | Yes | — | — | — | Yes | Yes | Yes |
| [.net.tc](https://www.domainnameapi.com/docs/tlds/net.tc/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.net.tr](https://www.domainnameapi.com/docs/tlds/net.tr/) | 1–5 | Yes | 4 | Required | — | Yes | Yes | Yes |
| [.net.za](https://www.domainnameapi.com/docs/tlds/net.za/) | 1 | Yes | — | — | — | Yes | Yes | Yes |
| [.network](https://www.domainnameapi.com/docs/tlds/network/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.news](https://www.domainnameapi.com/docs/tlds/news/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.nf](https://www.domainnameapi.com/docs/tlds/nf/) | 1–10 | Yes | — | — | — | Yes | No | Yes |
| [.ng](https://www.domainnameapi.com/docs/tlds/ng/) | 1–5 | Yes | — | — | — | Yes | Yes | Yes |
| [.ngo](https://www.domainnameapi.com/docs/tlds/ngo/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.ninja](https://www.domainnameapi.com/docs/tlds/ninja/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.nl](https://www.domainnameapi.com/docs/tlds/nl/) | 1 | Yes | 2 | — | — | Yes | No | Yes |
| [.no](https://www.domainnameapi.com/docs/tlds/no/) | 1 | Yes | 2 | Required | — | Yes | Yes | Yes |
| [.nrw](https://www.domainnameapi.com/docs/tlds/nrw/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.nu](https://www.domainnameapi.com/docs/tlds/nu/) | 1–10 | Yes | 2 | — | — | Yes | Yes | Yes |
| [.nyc](https://www.domainnameapi.com/docs/tlds/nyc/) | 1–10 | Yes | 1 | Required | — | Yes | Yes | Yes |
| [.nz](https://www.domainnameapi.com/docs/tlds/nz/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.observer](https://www.domainnameapi.com/docs/tlds/observer/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.okinawa](https://www.domainnameapi.com/docs/tlds/okinawa/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.one](https://www.domainnameapi.com/docs/tlds/one/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.ong](https://www.domainnameapi.com/docs/tlds/ong/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.onl](https://www.domainnameapi.com/docs/tlds/onl/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.online](https://www.domainnameapi.com/docs/tlds/online/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.ooo](https://www.domainnameapi.com/docs/tlds/ooo/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.org](https://www.domainnameapi.com/docs/tlds/org/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.org.bh](https://www.domainnameapi.com/docs/tlds/org.bh/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.org.br](https://www.domainnameapi.com/docs/tlds/org.br/) | 1–10 | Yes | 1 | — | — | Yes | Yes | Yes |
| [.org.cn](https://www.domainnameapi.com/docs/tlds/org.cn/) | 1–5 | Yes | 3 | — | — | Yes | Yes | Yes |
| [.org.ge](https://www.domainnameapi.com/docs/tlds/org.ge/) | 1–10 | Yes | — | — | — | Yes | No | Yes |
| [.org.in](https://www.domainnameapi.com/docs/tlds/org.in/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.org.kz](https://www.domainnameapi.com/docs/tlds/org.kz/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.org.ms](https://www.domainnameapi.com/docs/tlds/org.ms/) | 1–5 | Yes | — | — | — | Yes | Yes | Yes |
| [.org.mx](https://www.domainnameapi.com/docs/tlds/org.mx/) | — | Yes | — | — | — | Yes | No | Yes |
| [.org.ng](https://www.domainnameapi.com/docs/tlds/org.ng/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.org.pe](https://www.domainnameapi.com/docs/tlds/org.pe/) | — | Yes | — | — | — | Yes | No | Yes |
| [.org.pl](https://www.domainnameapi.com/docs/tlds/org.pl/) | — | Yes | — | — | — | Yes | Yes | Yes |
| [.org.ps](https://www.domainnameapi.com/docs/tlds/org.ps/) | — | Yes | — | — | — | Yes | Yes | Yes |
| [.org.ru](https://www.domainnameapi.com/docs/tlds/org.ru/) | 1–5 | Yes | — | — | — | Yes | No | Yes |
| [.org.tc](https://www.domainnameapi.com/docs/tlds/org.tc/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.org.tr](https://www.domainnameapi.com/docs/tlds/org.tr/) | 1–5 | Yes | 4 | Required | — | Yes | Yes | Yes |
| [.org.uk](https://www.domainnameapi.com/docs/tlds/org.uk/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.org.za](https://www.domainnameapi.com/docs/tlds/org.za/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.organic](https://www.domainnameapi.com/docs/tlds/organic/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.paris](https://www.domainnameapi.com/docs/tlds/paris/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.partners](https://www.domainnameapi.com/docs/tlds/partners/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.parts](https://www.domainnameapi.com/docs/tlds/parts/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.party](https://www.domainnameapi.com/docs/tlds/party/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.pe](https://www.domainnameapi.com/docs/tlds/pe/) | 1–5 | Yes | — | — | — | Yes | Yes | Yes |
| [.pet](https://www.domainnameapi.com/docs/tlds/pet/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.ph](https://www.domainnameapi.com/docs/tlds/ph/) | 1–5, 10 | Yes | — | — | — | Yes | No | Yes |
| [.photo](https://www.domainnameapi.com/docs/tlds/photo/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.photography](https://www.domainnameapi.com/docs/tlds/photography/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.photos](https://www.domainnameapi.com/docs/tlds/photos/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.pics](https://www.domainnameapi.com/docs/tlds/pics/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.pictures](https://www.domainnameapi.com/docs/tlds/pictures/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.pink](https://www.domainnameapi.com/docs/tlds/pink/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.pizza](https://www.domainnameapi.com/docs/tlds/pizza/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.pl](https://www.domainnameapi.com/docs/tlds/pl/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.place](https://www.domainnameapi.com/docs/tlds/place/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.plumbing](https://www.domainnameapi.com/docs/tlds/plumbing/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.plus](https://www.domainnameapi.com/docs/tlds/plus/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.pm](https://www.domainnameapi.com/docs/tlds/pm/) | 1–10 | Yes | 15 | — | Available | Yes | Yes | Yes |
| [.poker](https://www.domainnameapi.com/docs/tlds/poker/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.porn](https://www.domainnameapi.com/docs/tlds/porn/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.press](https://www.domainnameapi.com/docs/tlds/press/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.pro](https://www.domainnameapi.com/docs/tlds/pro/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.pro.tc](https://www.domainnameapi.com/docs/tlds/pro.tc/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.productions](https://www.domainnameapi.com/docs/tlds/productions/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.promo](https://www.domainnameapi.com/docs/tlds/promo/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.properties](https://www.domainnameapi.com/docs/tlds/properties/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.property](https://www.domainnameapi.com/docs/tlds/property/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.protection](https://www.domainnameapi.com/docs/tlds/protection/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.ps](https://www.domainnameapi.com/docs/tlds/ps/) | 1–5 | Yes | — | — | — | Yes | Yes | Yes |
| [.pt](https://www.domainnameapi.com/docs/tlds/pt/) | 1, 3, 5 | Yes | 2 | Required | — | Yes | Yes | Yes |
| [.pub](https://www.domainnameapi.com/docs/tlds/pub/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.pvt.ge](https://www.domainnameapi.com/docs/tlds/pvt.ge/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.pw](https://www.domainnameapi.com/docs/tlds/pw/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.qa](https://www.domainnameapi.com/docs/tlds/qa/) | 1–5 | Yes | — | — | — | Yes | Yes | Yes |
| [.qpon](https://www.domainnameapi.com/docs/tlds/qpon/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.quebec](https://www.domainnameapi.com/docs/tlds/quebec/) | 1–10 | Yes | 1 | — | — | Yes | Yes | Yes |
| [.quest](https://www.domainnameapi.com/docs/tlds/quest/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.racing](https://www.domainnameapi.com/docs/tlds/racing/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.re](https://www.domainnameapi.com/docs/tlds/re/) | 1–10 | Yes | 15 | — | Available | Yes | Yes | Yes |
| [.realty](https://www.domainnameapi.com/docs/tlds/realty/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.recipes](https://www.domainnameapi.com/docs/tlds/recipes/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.red](https://www.domainnameapi.com/docs/tlds/red/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.rehab](https://www.domainnameapi.com/docs/tlds/rehab/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.reise](https://www.domainnameapi.com/docs/tlds/reise/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.reisen](https://www.domainnameapi.com/docs/tlds/reisen/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.reit](https://www.domainnameapi.com/docs/tlds/reit/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.rent](https://www.domainnameapi.com/docs/tlds/rent/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.rentals](https://www.domainnameapi.com/docs/tlds/rentals/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.repair](https://www.domainnameapi.com/docs/tlds/repair/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.report](https://www.domainnameapi.com/docs/tlds/report/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.republican](https://www.domainnameapi.com/docs/tlds/republican/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.rest](https://www.domainnameapi.com/docs/tlds/rest/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.restaurant](https://www.domainnameapi.com/docs/tlds/restaurant/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.review](https://www.domainnameapi.com/docs/tlds/review/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.reviews](https://www.domainnameapi.com/docs/tlds/reviews/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.rich](https://www.domainnameapi.com/docs/tlds/rich/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.rip](https://www.domainnameapi.com/docs/tlds/rip/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.ro](https://www.domainnameapi.com/docs/tlds/ro/) | 1–10 | Yes | 3 | Required | — | Yes | Yes | Yes |
| [.rocks](https://www.domainnameapi.com/docs/tlds/rocks/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.rodeo](https://www.domainnameapi.com/docs/tlds/rodeo/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.rsvp](https://www.domainnameapi.com/docs/tlds/rsvp/) | — | Yes | — | — | — | Yes | Yes | Yes |
| [.ru](https://www.domainnameapi.com/docs/tlds/ru/) | 1 | Yes | — | — | Required | No | Yes | Yes |
| [.ru.com](https://www.domainnameapi.com/docs/tlds/ru.com/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.ruhr](https://www.domainnameapi.com/docs/tlds/ruhr/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.run](https://www.domainnameapi.com/docs/tlds/run/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.sa.com](https://www.domainnameapi.com/docs/tlds/sa.com/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.saarland](https://www.domainnameapi.com/docs/tlds/saarland/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.sale](https://www.domainnameapi.com/docs/tlds/sale/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.salon](https://www.domainnameapi.com/docs/tlds/salon/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.sarl](https://www.domainnameapi.com/docs/tlds/sarl/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.sb](https://www.domainnameapi.com/docs/tlds/sb/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.sbs](https://www.domainnameapi.com/docs/tlds/sbs/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.sc](https://www.domainnameapi.com/docs/tlds/sc/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.school](https://www.domainnameapi.com/docs/tlds/school/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.schule](https://www.domainnameapi.com/docs/tlds/schule/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.science](https://www.domainnameapi.com/docs/tlds/science/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.scot](https://www.domainnameapi.com/docs/tlds/scot/) | 1–10 | Yes | 1 | Required | — | Yes | Yes | Yes |
| [.se](https://www.domainnameapi.com/docs/tlds/se/) | 1–10 | Yes | 2 | Required | — | Yes | Yes | Yes |
| [.security](https://www.domainnameapi.com/docs/tlds/security/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.select](https://www.domainnameapi.com/docs/tlds/select/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.services](https://www.domainnameapi.com/docs/tlds/services/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.sex](https://www.domainnameapi.com/docs/tlds/sex/) | 1–10 | Yes | — | — | — | Yes | No | Yes |
| [.sexy](https://www.domainnameapi.com/docs/tlds/sexy/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.sg](https://www.domainnameapi.com/docs/tlds/sg/) | 1, 2 | Yes | 2 | Required | — | Yes | Yes | Yes |
| [.sh](https://www.domainnameapi.com/docs/tlds/sh/) | 1–5 | Yes | — | — | — | Yes | Yes | Yes |
| [.shiksha](https://www.domainnameapi.com/docs/tlds/shiksha/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.shoes](https://www.domainnameapi.com/docs/tlds/shoes/) | 1–7 | Yes | — | — | — | Yes | Yes | Yes |
| [.shop](https://www.domainnameapi.com/docs/tlds/shop/) | 1–10 | Yes | — | — | — | Yes | No | Yes |
| [.shopping](https://www.domainnameapi.com/docs/tlds/shopping/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.show](https://www.domainnameapi.com/docs/tlds/show/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.si](https://www.domainnameapi.com/docs/tlds/si/) | 1–5 | Yes | — | — | — | Yes | Yes | Yes |
| [.singles](https://www.domainnameapi.com/docs/tlds/singles/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.site](https://www.domainnameapi.com/docs/tlds/site/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.sk](https://www.domainnameapi.com/docs/tlds/sk/) | 1–10 | Yes | 2 | — | — | Yes | Yes | Yes |
| [.ski](https://www.domainnameapi.com/docs/tlds/ski/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.skin](https://www.domainnameapi.com/docs/tlds/skin/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.so](https://www.domainnameapi.com/docs/tlds/so/) | 1–10 | Yes | — | — | — | Yes | No | Yes |
| [.soccer](https://www.domainnameapi.com/docs/tlds/soccer/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.social](https://www.domainnameapi.com/docs/tlds/social/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.software](https://www.domainnameapi.com/docs/tlds/software/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.solar](https://www.domainnameapi.com/docs/tlds/solar/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.solutions](https://www.domainnameapi.com/docs/tlds/solutions/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.soy](https://www.domainnameapi.com/docs/tlds/soy/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.spa](https://www.domainnameapi.com/docs/tlds/spa/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.space](https://www.domainnameapi.com/docs/tlds/space/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.srl](https://www.domainnameapi.com/docs/tlds/srl/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.st](https://www.domainnameapi.com/docs/tlds/st/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.storage](https://www.domainnameapi.com/docs/tlds/storage/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.store](https://www.domainnameapi.com/docs/tlds/store/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.stream](https://www.domainnameapi.com/docs/tlds/stream/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.studio](https://www.domainnameapi.com/docs/tlds/studio/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.study](https://www.domainnameapi.com/docs/tlds/study/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.style](https://www.domainnameapi.com/docs/tlds/style/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.su](https://www.domainnameapi.com/docs/tlds/su/) | 1 | Yes | — | — | Required | Yes | Yes | Yes |
| [.sucks](https://www.domainnameapi.com/docs/tlds/sucks/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.supplies](https://www.domainnameapi.com/docs/tlds/supplies/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.supply](https://www.domainnameapi.com/docs/tlds/supply/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.support](https://www.domainnameapi.com/docs/tlds/support/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.surf](https://www.domainnameapi.com/docs/tlds/surf/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.surgery](https://www.domainnameapi.com/docs/tlds/surgery/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.sv](https://www.domainnameapi.com/docs/tlds/sv/) | — | Yes | — | — | — | Yes | Yes | Yes |
| [.swiss](https://www.domainnameapi.com/docs/tlds/swiss/) | 1–10 | Yes | 3 | Required | — | Yes | Yes | Yes |
| [.sx](https://www.domainnameapi.com/docs/tlds/sx/) | 1–10 | Yes | — | — | — | Yes | No | Yes |
| [.sydney](https://www.domainnameapi.com/docs/tlds/sydney/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.systems](https://www.domainnameapi.com/docs/tlds/systems/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.taipei](https://www.domainnameapi.com/docs/tlds/taipei/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.tattoo](https://www.domainnameapi.com/docs/tlds/tattoo/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.tax](https://www.domainnameapi.com/docs/tlds/tax/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.taxi](https://www.domainnameapi.com/docs/tlds/taxi/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.tc](https://www.domainnameapi.com/docs/tlds/tc/) | 1–10 | Yes | — | — | — | No | Yes | Yes |
| [.team](https://www.domainnameapi.com/docs/tlds/team/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.tech](https://www.domainnameapi.com/docs/tlds/tech/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.technology](https://www.domainnameapi.com/docs/tlds/technology/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.tel](https://www.domainnameapi.com/docs/tlds/tel/) | 1–10 | Yes | 2 | — | — | Yes | Yes | Yes |
| [.tennis](https://www.domainnameapi.com/docs/tlds/tennis/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.tf](https://www.domainnameapi.com/docs/tlds/tf/) | 1–10 | Yes | 15 | — | — | Yes | Yes | Yes |
| [.theater](https://www.domainnameapi.com/docs/tlds/theater/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.theatre](https://www.domainnameapi.com/docs/tlds/theatre/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.tickets](https://www.domainnameapi.com/docs/tlds/tickets/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.tienda](https://www.domainnameapi.com/docs/tlds/tienda/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.tips](https://www.domainnameapi.com/docs/tlds/tips/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.tires](https://www.domainnameapi.com/docs/tlds/tires/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.tirol](https://www.domainnameapi.com/docs/tlds/tirol/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.tk](https://www.domainnameapi.com/docs/tlds/tk/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.tl](https://www.domainnameapi.com/docs/tlds/tl/) | 1–5, 10 | Yes | — | — | — | Yes | No | Yes |
| [.tm](https://www.domainnameapi.com/docs/tlds/tm/) | 1 | Yes | — | — | — | Yes | Yes | Yes |
| [.tn](https://www.domainnameapi.com/docs/tlds/tn/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.to](https://www.domainnameapi.com/docs/tlds/to/) | 1–5, 10 | Yes | — | — | — | Yes | Yes | Yes |
| [.today](https://www.domainnameapi.com/docs/tlds/today/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.tokyo](https://www.domainnameapi.com/docs/tlds/tokyo/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.tools](https://www.domainnameapi.com/docs/tlds/tools/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.top](https://www.domainnameapi.com/docs/tlds/top/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.tours](https://www.domainnameapi.com/docs/tlds/tours/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.town](https://www.domainnameapi.com/docs/tlds/town/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.toys](https://www.domainnameapi.com/docs/tlds/toys/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.tr](https://www.domainnameapi.com/docs/tlds/tr/) | 1–5 | Yes | 4 | Required | — | Yes | Yes | Yes |
| [.trade](https://www.domainnameapi.com/docs/tlds/trade/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.trading](https://www.domainnameapi.com/docs/tlds/trading/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.training](https://www.domainnameapi.com/docs/tlds/training/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.travel](https://www.domainnameapi.com/docs/tlds/travel/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.tube](https://www.domainnameapi.com/docs/tlds/tube/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.tv](https://www.domainnameapi.com/docs/tlds/tv/) | 1–10 | Yes | — | — | — | Yes | No | Yes |
| [.tv.tr](https://www.domainnameapi.com/docs/tlds/tv.tr/) | 1–5 | Yes | 4 | Required | — | Yes | Yes | Yes |
| [.tw](https://www.domainnameapi.com/docs/tlds/tw/) | 1–10 | Yes | 1 | — | — | Yes | Yes | Yes |
| [.uk](https://www.domainnameapi.com/docs/tlds/uk/) | 1–10 | Yes | — | Required | — | Yes | Yes | Yes |
| [.uk.com](https://www.domainnameapi.com/docs/tlds/uk.com/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.uk.net](https://www.domainnameapi.com/docs/tlds/uk.net/) | — | Yes | — | — | — | Yes | Yes | Yes |
| [.university](https://www.domainnameapi.com/docs/tlds/university/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.uno](https://www.domainnameapi.com/docs/tlds/uno/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.us](https://www.domainnameapi.com/docs/tlds/us/) | 1–10 | Yes | 2 | Required | Available | No | No | Yes |
| [.us.com](https://www.domainnameapi.com/docs/tlds/us.com/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.vacations](https://www.domainnameapi.com/docs/tlds/vacations/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.vc](https://www.domainnameapi.com/docs/tlds/vc/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.vegas](https://www.domainnameapi.com/docs/tlds/vegas/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.ventures](https://www.domainnameapi.com/docs/tlds/ventures/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.versicherung](https://www.domainnameapi.com/docs/tlds/versicherung/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.vet](https://www.domainnameapi.com/docs/tlds/vet/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.vg](https://www.domainnameapi.com/docs/tlds/vg/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.viajes](https://www.domainnameapi.com/docs/tlds/viajes/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.video](https://www.domainnameapi.com/docs/tlds/video/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.villas](https://www.domainnameapi.com/docs/tlds/villas/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.vin](https://www.domainnameapi.com/docs/tlds/vin/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.vip](https://www.domainnameapi.com/docs/tlds/vip/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.vision](https://www.domainnameapi.com/docs/tlds/vision/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.vlaanderen](https://www.domainnameapi.com/docs/tlds/vlaanderen/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.vodka](https://www.domainnameapi.com/docs/tlds/vodka/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.vote](https://www.domainnameapi.com/docs/tlds/vote/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.voting](https://www.domainnameapi.com/docs/tlds/voting/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.voto](https://www.domainnameapi.com/docs/tlds/voto/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.voyage](https://www.domainnameapi.com/docs/tlds/voyage/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.vu](https://www.domainnameapi.com/docs/tlds/vu/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.wales](https://www.domainnameapi.com/docs/tlds/wales/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.wang](https://www.domainnameapi.com/docs/tlds/wang/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.watch](https://www.domainnameapi.com/docs/tlds/watch/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.web.tr](https://www.domainnameapi.com/docs/tlds/web.tr/) | 1–5 | Yes | 4 | Required | — | Yes | Yes | Yes |
| [.webcam](https://www.domainnameapi.com/docs/tlds/webcam/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.website](https://www.domainnameapi.com/docs/tlds/website/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.wedding](https://www.domainnameapi.com/docs/tlds/wedding/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.wf](https://www.domainnameapi.com/docs/tlds/wf/) | 1–10 | Yes | 15 | — | — | Yes | Yes | Yes |
| [.wien](https://www.domainnameapi.com/docs/tlds/wien/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.wiki](https://www.domainnameapi.com/docs/tlds/wiki/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.win](https://www.domainnameapi.com/docs/tlds/win/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.wine](https://www.domainnameapi.com/docs/tlds/wine/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.work](https://www.domainnameapi.com/docs/tlds/work/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.works](https://www.domainnameapi.com/docs/tlds/works/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.world](https://www.domainnameapi.com/docs/tlds/world/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.ws](https://www.domainnameapi.com/docs/tlds/ws/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.wtf](https://www.domainnameapi.com/docs/tlds/wtf/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.xxx](https://www.domainnameapi.com/docs/tlds/xxx/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.xyz](https://www.domainnameapi.com/docs/tlds/xyz/) | 1–10 | Yes | — | — | — | Yes | No | Yes |
| [.yachts](https://www.domainnameapi.com/docs/tlds/yachts/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.yoga](https://www.domainnameapi.com/docs/tlds/yoga/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.yokohama](https://www.domainnameapi.com/docs/tlds/yokohama/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.yt](https://www.domainnameapi.com/docs/tlds/yt/) | 1–10 | Yes | 15 | — | — | Yes | Yes | Yes |
| [.zone](https://www.domainnameapi.com/docs/tlds/zone/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.البحرين](https://www.domainnameapi.com/docs/tlds/xn--mgbcpq6gpa1a/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.संगठन](https://www.domainnameapi.com/docs/tlds/xn--i1b6b1a6a2e/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
| [.机构](https://www.domainnameapi.com/docs/tlds/xn--nqv7f/) | 1–10 | Yes | — | — | — | Yes | Yes | Yes |
---
# All endpoints
> Every endpoint on one page, grouped by section, with its method, path, what it does and a link to its request, response and errors.
Every path is relative to `https://api.domainresellerapi.com` and every request needs the [two authentication headers](https://www.domainnameapi.com/docs/getting-started/authentication/). Select a path to see its request, response and errors.
## Contacts
| Method | Path | What it does |
| --- | --- | --- |
| `POST` | [`/api/v1/contacts`](https://www.domainnameapi.com/docs/contacts/endpoints/#post-apiv1contacts) | Creates a contact and returns its handle code. |
| `GET` | [`/api/v1/contacts/{handleCode}`](https://www.domainnameapi.com/docs/contacts/endpoints/#get-apiv1contactshandlecode) | Reads a contact in your account, together with any verification process currently open on it. |
| `PUT` | [`/api/v1/contacts/{handleCode}`](https://www.domainnameapi.com/docs/contacts/endpoints/#put-apiv1contactshandlecode) | Updates a contact. |
| `GET` | [`/api/v1/contacts/verification/check`](https://www.domainnameapi.com/docs/contacts/verification/#get-apiv1contactsverificationcheck) | Current verification state for a handle. |
| `POST` | [`/api/v1/contacts/verification/request`](https://www.domainnameapi.com/docs/contacts/verification/#post-apiv1contactsverificationrequest) | Re-sends the verification e-mail. |
## Domains
| Method | Path | What it does |
| --- | --- | --- |
| `POST` | [`/api/v1/domains/search`](https://www.domainnameapi.com/docs/domains/availability/#post-apiv1domainssearch) | Is this domain available, and what would it cost? |
| `POST` | [`/api/v1/domains/bulk-search`](https://www.domainnameapi.com/docs/domains/availability/#post-apiv1domainsbulk-search) | Up to **30** domains in one call. |
| `POST` | [`/api/v1/domains/register-with-contacts`](https://www.domainnameapi.com/docs/domains/register/#post-apiv1domainsregister-with-contacts) | Registers a domain, creating contact records from the details you send. |
| `POST` | [`/api/v1/domains/register`](https://www.domainnameapi.com/docs/domains/register/#post-apiv1domainsregister) | Registers a domain using contact handles that already exist in your account. |
| `POST` | [`/api/v1/domains/renew/check`](https://www.domainnameapi.com/docs/domains/renew/#post-apiv1domainsrenewcheck) | Dry run: can this domain be renewed for this term, and at what price? |
| `POST` | [`/api/v1/domains/renew`](https://www.domainnameapi.com/docs/domains/renew/#post-apiv1domainsrenew) | Renews the domain and debits your balance. |
| `POST` | [`/api/v1/domains/transfers/check`](https://www.domainnameapi.com/docs/domains/transfer/#post-apiv1domainstransferscheck) | Asks the registry whether the domain can be transferred to you with the authorisation code you hold, and what it would cost. |
| `POST` | [`/api/v1/domains/transfer`](https://www.domainnameapi.com/docs/domains/transfer/#post-apiv1domainstransfer) | Starts the transfer and debits your balance. |
| `POST` | [`/api/v1/domains/transfers/query`](https://www.domainnameapi.com/docs/domains/transfer/#post-apiv1domainstransfersquery) | Status of a transfer in flight. |
| `GET` | [`/api/v1/domains/info`](https://www.domainnameapi.com/docs/domains/info/#get-apiv1domainsinfo) | Everything we know about one of your domains. |
| `GET` | [`/api/v1/domains`](https://www.domainnameapi.com/docs/domains/info/#get-apiv1domains) | Paged list of the domains in your account. |
| `POST` | [`/api/v1/domains/lock`](https://www.domainnameapi.com/docs/domains/lock-privacy-auth-code/#post-apiv1domainslock--post-apiv1domainsunlock) | Turns the registrar transfer lock on or off. |
| `POST` | [`/api/v1/domains/unlock`](https://www.domainnameapi.com/docs/domains/lock-privacy-auth-code/#post-apiv1domainslock--post-apiv1domainsunlock) | Turns the registrar transfer lock on or off. |
| `POST` | [`/api/v1/domains/privacy`](https://www.domainnameapi.com/docs/domains/lock-privacy-auth-code/#post-apiv1domainsprivacy) | Turns WHOIS privacy protection on or off. |
| `PUT` | [`/api/v1/domains/auth`](https://www.domainnameapi.com/docs/domains/lock-privacy-auth-code/#put-apiv1domainsauth) | Generates a new transfer authorisation code and returns it. |
| `PUT` | [`/api/v1/domains/contacts/update`](https://www.domainnameapi.com/docs/domains/contacts/#put-apiv1domainscontactsupdate) | Replaces the contact details for one or more roles on a single domain. |
| `PUT` | [`/api/v1/domains/contacts/update-with-handle`](https://www.domainnameapi.com/docs/domains/contacts/#put-apiv1domainscontactsupdate-with-handle) | Points a domain's roles at handles that already exist in your account. |
| `POST` | [`/api/v1/domains/forwards`](https://www.domainnameapi.com/docs/domains/forwarding/#post-apiv1domainsforwards) | Creates a forwarding record. |
| `GET` | [`/api/v1/domains/forwards`](https://www.domainnameapi.com/docs/domains/forwarding/#get-apiv1domainsforwards--delete-apiv1domainsforwards) | Read or remove the forwarding record. |
| `DELETE` | [`/api/v1/domains/forwards`](https://www.domainnameapi.com/docs/domains/forwarding/#get-apiv1domainsforwards--delete-apiv1domainsforwards) | Read or remove the forwarding record. |
| `POST` | [`/api/v1/domains/restore`](https://www.domainnameapi.com/docs/domains/restore/#post-apiv1domainsrestore) | Recovers a deleted domain from the registry's redemption period. |
| `POST` | [`/api/v1/domains/documents`](https://www.domainnameapi.com/docs/domains/documents/#post-apiv1domainsdocuments) | Uploads one or more documents as Base64 and forwards each to the registry. |
| `GET` | [`/api/v1/domains/documents`](https://www.domainnameapi.com/docs/domains/documents/#get-apiv1domainsdocuments) | Lists the documents uploaded for a domain and their review status. |
## Name servers & DNSSEC
| Method | Path | What it does |
| --- | --- | --- |
| `PUT` | [`/api/v1/domains/dns/name-server`](https://www.domainnameapi.com/docs/name-servers/#put-apiv1domainsdnsname-server) | Replaces the domain's name servers. |
| `POST` | [`/api/v1/domains/dns/host`](https://www.domainnameapi.com/docs/name-servers/hosts/#post-apiv1domainsdnshost) | Creates a host record with its IP addresses. |
| `PUT` | [`/api/v1/domains/dns/host`](https://www.domainnameapi.com/docs/name-servers/hosts/#put-apiv1domainsdnshost--delete-apiv1domainsdnshost) | Rename a host and/or replace its IP addresses, or delete it. |
| `DELETE` | [`/api/v1/domains/dns/host`](https://www.domainnameapi.com/docs/name-servers/hosts/#put-apiv1domainsdnshost--delete-apiv1domainsdnshost) | Rename a host and/or replace its IP addresses, or delete it. |
| `GET` | [`/api/v1/domains/dns/dnssec`](https://www.domainnameapi.com/docs/name-servers/dnssec/#get-apiv1domainsdnsdnssec) | Current DNSSEC state, the published DS records, and what this extension accepts. |
| `POST` | [`/api/v1/domains/dns/dnssec`](https://www.domainnameapi.com/docs/name-servers/dnssec/#post-apiv1domainsdnsdnssec) | Publishes one or more DS records at the registry, enabling DNSSEC. |
| `DELETE` | [`/api/v1/domains/dns/dnssec`](https://www.domainnameapi.com/docs/name-servers/dnssec/#delete-apiv1domainsdnsdnssec--post-apiv1domainsdnsdnssecdisable) | Remove one DS record, or all of them. |
| `POST` | [`/api/v1/domains/dns/dnssec/disable`](https://www.domainnameapi.com/docs/name-servers/dnssec/#delete-apiv1domainsdnsdnssec--post-apiv1domainsdnsdnssecdisable) | Remove one DS record, or all of them. |
## DNS records
| Method | Path | What it does |
| --- | --- | --- |
| `GET` | [`/api/v1/domains/zones`](https://www.domainnameapi.com/docs/dns-records/endpoints/#get-apiv1domainszones) | Reads every record set in the zone. |
| `POST` | [`/api/v1/domains/zones`](https://www.domainnameapi.com/docs/dns-records/endpoints/#post-apiv1domainszones) | Adds one or more values to a record set. |
| `PUT` | [`/api/v1/domains/zones`](https://www.domainnameapi.com/docs/dns-records/endpoints/#put-apiv1domainszones) | Replaces a record set. |
| `DELETE` | [`/api/v1/domains/zones`](https://www.domainnameapi.com/docs/dns-records/endpoints/#delete-apiv1domainszones) | Deletes **one value** from a record set. |
| `POST` | [`/api/v1/domains/zones/apply`](https://www.domainnameapi.com/docs/dns-records/endpoints/#post-apiv1domainszonesapply) | Publishes the zone by delegating the domain to our name servers. |
## SSL certificates
| Method | Path | What it does |
| --- | --- | --- |
| `POST` | [`/api/v1/ssls/generate-csr`](https://www.domainnameapi.com/docs/ssl/prepare/#post-apiv1sslsgenerate-csr) | Generates a CSR and matching private key on our side. |
| `POST` | [`/api/v1/ssls/check-csr`](https://www.domainnameapi.com/docs/ssl/prepare/#post-apiv1sslscheck-csr) | Decodes a CSR so you can confirm its contents before buying. |
| `GET` | [`/api/v1/ssls/approvers`](https://www.domainnameapi.com/docs/ssl/prepare/#get-apiv1sslsapprovers) | Lists the e-mail addresses the CA will accept as the domain's approver, for e-mail-based validation. |
| `POST` | [`/api/v1/ssls/initialize`](https://www.domainnameapi.com/docs/ssl/buy/#post-apiv1sslsinitialize) | |
| `PUT` | [`/api/v1/ssls/configure`](https://www.domainnameapi.com/docs/ssl/configure/#put-apiv1sslsconfigure) | Submits everything the CA needs and **opens the order at the provider**. |
| `PUT` | [`/api/v1/ssls/check-status`](https://www.domainnameapi.com/docs/ssl/issue/#put-apiv1sslscheck-status) | Asks the CA where the order stands and updates our record. |
| `GET` | [`/api/v1/ssls/certificate`](https://www.domainnameapi.com/docs/ssl/issue/#get-apiv1sslscertificate) | Full detail for the certificate on a domain. |
| `GET` | [`/api/v1/ssls/certificate-content`](https://www.domainnameapi.com/docs/ssl/issue/#get-apiv1sslscertificate-content) | Returns the issued certificate and its chain. |
| `POST` | [`/api/v1/ssls/reissue`](https://www.domainnameapi.com/docs/ssl/reissue-revoke-renew/#post-apiv1sslsreissue) | Re-issues an active certificate with a new key pair or a new approver. |
| `DELETE` | [`/api/v1/ssls/revoke`](https://www.domainnameapi.com/docs/ssl/reissue-revoke-renew/#delete-apiv1sslsrevoke) | Revokes the certificate. |
## Hosting
| Method | Path | What it does |
| --- | --- | --- |
| `GET` | [`/api/v1/hostings/packages`](https://www.domainnameapi.com/docs/hosting/#get-apiv1hostingspackages) | Lists what you can sell. |
| `POST` | [`/api/v1/hostings/create`](https://www.domainnameapi.com/docs/hosting/#post-apiv1hostingscreate) | Buys the package and queues provisioning. |
| `GET` | [`/api/v1/hostings/check-status`](https://www.domainnameapi.com/docs/hosting/#get-apiv1hostingscheck-status) | Reports where provisioning got to and, once complete, returns the credentials. |
| `GET` | [`/api/v1/hostings`](https://www.domainnameapi.com/docs/hosting/#get-apiv1hostings--get-apiv1hostingsby-token--get-apiv1hostingsplans) | Look up a hosting record, or read its plan limits. |
| `GET` | [`/api/v1/hostings/by-token`](https://www.domainnameapi.com/docs/hosting/#get-apiv1hostings--get-apiv1hostingsby-token--get-apiv1hostingsplans) | Look up a hosting record, or read its plan limits. |
| `GET` | [`/api/v1/hostings/plans`](https://www.domainnameapi.com/docs/hosting/#get-apiv1hostings--get-apiv1hostingsby-token--get-apiv1hostingsplans) | Look up a hosting record, or read its plan limits. |
## Catalogue & billing
| Method | Path | What it does |
| --- | --- | --- |
| `GET` | [`/api/v1/products/tlds`](https://www.domainnameapi.com/docs/catalogue/#get-apiv1productstlds) | |
| `GET` | [`/api/v1/products/ssls`](https://www.domainnameapi.com/docs/catalogue/ssl/#get-apiv1productsssls) | Certificate packages and their prices. |
| `GET` | [`/api/v1/products/info`](https://www.domainnameapi.com/docs/catalogue/ssl/#get-apiv1productsinfo) | One product with its selling price recalculated for your account right now. |
| `GET` | [`/api/v1/order/{orderCode}`](https://www.domainnameapi.com/docs/catalogue/orders/#get-apiv1orderordercode) | Reads one order with its line items. |
| `GET` | [`/api/v1/deposit/accounts/me`](https://www.domainnameapi.com/docs/catalogue/balance/#get-apiv1depositaccountsme) | Your current balances. |
| `GET` | [`/api/v1/deposit/transactions`](https://www.domainnameapi.com/docs/catalogue/balance/#get-apiv1deposittransactions) | Paged ledger of every balance movement. |
---
# Error codes
> Every error code by area, with what it means and what to do, and the codes you must never retry.
Every error code grouped by area, with what it means and what to do. Branch your code on `code`, show the user `message`, log `details`.
## How to handle errors properly
1. **Read `code`, not `message`.** Messages are localised and get reworded. Codes do not change.
2. **Group codes by what you will do about them.** Most fall into four buckets: *fix the input and retry*, *tell the customer to do something*, *wait and retry*, and *never retry*.
3. **Log `details` and your `X-Correlation-ID` together.** These two make a support ticket resolvable in minutes.
4. **Handle the never-retry codes explicitly.** They are the only ones where a retry actively causes harm.
:::danger[Never retry these five]
| Code | What already happened |
| --- | --- |
| `Dna.DomainService:Domain:10058 *` | The domain **was registered** at the registry but we could not record it. |
| `Dna.DomainService:Domain:10059` | The domain **was renewed** at the registry but we could not record it. |
| `Dna.DomainService:Domain:10060` | The transfer **was started** at the registry but we could not record it. |
| `Ssl:10053` | SSL configuration has already been sent to the CA. |
| `Ssl:10054` | SSL configuration was sent but the outcome could not be verified. |
In every case the operation **succeeded** and a recovery record exists. Retrying creates a duplicate registration or a double charge. Open a support ticket with the domain name and your correlation ID.
\* `10058` has a second, harmless meaning — "Domain name mixes multiple scripts", which means your input was rejected and nothing happened. Read the message to tell them apart.
:::
:::caution[Four codes carry two meanings — read the message as well]
| Code | The two meanings |
| --- | --- |
| `Dna.DomainService:Domain:10058` | "created at the registry but not recorded" (never retry) **or** "mixes multiple scripts" (input rejected). |
| `Dna.DomainService:Domain:10025` | On `/transfers/check`: the extension has no transfer-check facility. On `/transfers/query`: the domain is not in a transfer state. |
| `Ssl:10048` | "certificate not issued yet" **or** "provider order number invalid". If `isIssued` is false, it is the former. |
| `Ssl:10049` | "revoke failed" **or** "the CA could not be reached". |
:::
## Authentication and account
| Code | Meaning and what to do |
| --- | --- |
| (plain text, 401) | Missing or invalid `X-API-KEY` / `__reseller`, or a sub-reseller account. See [Authentication](https://www.domainnameapi.com/docs/getting-started/authentication/). |
| `Dna.DomainService:Reseller:10001` | **Your balance is suspended.** Every paid operation is blocked. Contact us — this is an account matter, not something you can fix in code. |
| `Dna.DomainService:Deposit:10001` | Insufficient balance. `data` gives current balances and the required amount. Top up and retry. |
| `Ssl:10045 / Ssl:10047` | The SSL equivalents of the two above. |
| `Dna.DomainService:General:10001` | An internal error. Retry once; if it persists, open a ticket with your correlation ID. |
| `Dna.DomainService:Epp:10001` | The registry refused for a reason we have no specific code for. **Read `details`** — it carries the registry's own message, which is usually clear. |
## Domain errors
### Not found and ownership
| Code | Meaning and what to do |
| --- | --- |
| `Dna.DomainService:Domain:10007` | Domain not found, **or found but not yours**. We report ownership mismatches as not-found deliberately. |
| `Dna.DomainService:Domain:1021 / 1020 / 1023` | The domain does not belong to you, or to your sub-resellers. |
| `Dna.DomainService:Domain:1024 / 10030` | The domain already belongs to you, or to the reseller you specified. Nothing to do. |
| `Dna.DomainService:Domain:10050` | The domain is in our system but we cannot match the record. Open a ticket. |
### Name and format
| Code | Meaning and what to do |
| --- | --- |
| `Dna.DomainService:Domain:10005` | Invalid domain name. Check for a missing dot, a leading or trailing hyphen in a label, or an empty label. |
| `Dna.DomainService:Domain:10044` | Invalid domain name on a write operation. Same checks as above. |
| `Dna.DomainService:Domain:10058` | The name mixes alphabets within one label — rejected as a look-alike attack. See the note above about this code's second meaning. |
| `Dna.DomainService:Domain:10004` | We do not sell this extension. Do not retry. |
| `Dna.DomainService:Domain:10046` | You sent a subdomain where a registrable domain was expected. |
| `Dna.DomainService:Domain:10012 / 10013 / 10014` | The name is shorter or longer than this extension permits. |
### Period and pricing
| Code | Meaning and what to do |
| --- | --- |
| `Dna.DomainService:Domain:10023` | **Common.** Registering: the `period` is not one this extension sells. Read `registrationPeriods` from the catalogue. |
| `Dna.DomainService:Domain:10002` | Renewing: the `period` is not one of the extension's `renewalPeriods`. |
| `Dna.DomainService:Domain:10022` | `period` above 10. |
| `Dna.DomainService:Domain:1016` | Renewal check only: `period` is 0, or — as `errorMessageKey` — the term is too long (the case `/renew` reports as `1028`). |
| `Dna.DomainService:Domain:1028` | The renewal would push total registration past the longest term in the extension's `renewalPeriods`. Renew for fewer years. |
| `Dna.DomainService:Domain:10071` | Premium domain with `period` above 1. Premium names are one year at a time. |
| `Dna.DomainService:Domain:10072` | The registry's premium price changed since your search. **Nothing was charged.** Search again for the current price. |
| `Dna.DomainService:Domain:10049` | No price configured for this extension and period. Open a ticket. |
| `Dna.DomainService:Domain:10048` | No transfer price configured for that period. |
| `Dna.DomainService:Price:10001` | No pricing information for this extension, so a search cannot be priced. |
### Availability and status
| Code | Meaning and what to do |
| --- | --- |
| `Dna.DomainService:Domain:1026` | Already registered. Search first; consider transfer. |
| `Dna.DomainService:Domain:10016` | The domain's status does not permit this operation. Read `status` and `statusReason` from `/domains/info`. |
| `Dna.DomainService:Domain:1019` | An invalid status value in `statusIds`. |
| `Dna.DomainService:Domain:10017` | Registry search temporarily unavailable. Retry after a pause. |
| `Dna.Domainservice:Domain:10036` | More than 30 domains in one bulk search. Batch them. |
| `Dna.DomainService:Domain:10034` | Invalid `sorting` value. |
### Renewal
| Code | Meaning and what to do |
| --- | --- |
| `Dna.DomainService:Domain:10018` | Not in a renewable state — deleted, transferred out, or pending deletion. |
| `Dna.DomainService:Domain:10019` | Temporarily unavailable — for a renewal, a registry connection problem was recorded for this domain in the last three days. Retry later. |
| `Dna.DomainService:Domain:10020` | The registry already auto-renewed it and the expiry has moved. Re-read the domain. |
| `Dna.DomainService:Domain:10021` | Too early — this extension does not allow renewal this far ahead. |
| `Dna.DomainService:Domain:10051` | Renewed very recently and still inside the registry's grace window. Wait a few days. |
| `Dna.DomainService:Domain:10045` | A renewal prohibition is set at the registry. |
| `Dna.DomainService:Domain:10042` | Renewed at the registry but something failed afterwards. Check the expiry date before acting. |
### Transfer
| Code | Meaning and what to do |
| --- | --- |
| `Dna.DomainService:Domain:10008 / 10047` | Wrong authorisation code. Have the customer re-fetch it from their current registrar. |
| `Dna.DomainService:Domain:10026` | `authCode` missing. |
| `Dna.DomainService:Domain:10035` | Auth code length is outside this extension's limits. `details` gives the min and max. |
| `Dna.DomainService:Domain:10006` | Transfer lock active. The customer must unlock at their current registrar. |
| `Dna.DomainService:Domain:10031 / 10057` | **60-day rule.** Registered or transferred within the last 60 days. Registry policy — you can only wait. |
| `Dna.DomainService:Domain:10028` | You already have a transfer pending on this domain. |
| `Dna.DomainService:Domain:10029` | Another registrar's transfer is pending. Wait for it to resolve. |
| `Dna.DomainService:Domain:10024 / 10011` | Transfer not permitted for this domain, or not supported by this extension. |
| `Dna.DomainService:Domain:10025` | Transfer check not supported — skip it and transfer directly. (Different meaning on `/transfers/query`.) |
| `Dna.DomainService:Domain:10039` | The domain is available, not registered. Register it instead. |
| `Dna.DomainService:Domain:10027` | No transfer history at the registry. |
| `Dna.DomainService:Epp:2303` | The domain does not exist at the registry. |
| `Dna.DomainService:Domain:10040` | The authorisation code could not be changed. |
### Restore, forwarding, lock
| Code | Meaning and what to do |
| --- | --- |
| `Dna.DomainService:Domain:10043` | Not in the redemption period, so restore is impossible. Check `rgpStatues`. |
| `Dna.DomainService:Domain:10038` | No registrant contact on the domain. Open a ticket. |
| `Dna.DomainService:Domain:1017` | No forwarding configured on this domain. |
| `Dna.DomainService:Domain:1018` | `forwardType` could not be resolved to `Standard` or `Frame`. |
| `Dna.DomainService:Domain:1025` | A forward already exists. Delete it first. |
| `Dna.DomainService:Domain:10032` | Unlock refused because an ownership change is pending. |
| `Dna.DomainService:Tld:10001` | This extension does not support WHOIS privacy. |
| `Dna.DomainService:DomainSale:10007` | The domain is listed for sale and uses parking records. Cancel the listing before changing DNS or forwarding. |
### Documents
| Code | Meaning and what to do |
| --- | --- |
| `Dna.DomainService:Domain:10055` | The domain is not expecting documents. Check `status` and `statusReason`. |
| `Dna.DomainService:Domain:10061` | `documents` empty or missing. |
| `Dna.DomainService:Domain:10066` | An entry lacks `fileName` or `fileContent`. |
| `Dna.DomainService:Domain:10065` | Invalid `documentType`. |
| `Dna.DomainService:Domain:10062` | Format not allowed. PDF, DOC, DOCX, ODT, JPG, JPEG, PNG only. |
| `Dna.DomainService:Domain:10067` | Not valid Base64. **Usually a leftover `data:` prefix.** |
| `Dna.DomainService:Domain:10068` | The extension does not match the file's real format. `details` says what it actually is. |
| `Dna.DomainService:Domain:10069 / 10064` | A single file over 10 MB, or the request total over 50 MB. |
| `Dna.DomainService:Domain:10063` | More than 10 documents would be under review. |
## Contact errors
| Code | Meaning and what to do |
| --- | --- |
| `Dna.DomainService:Contact:10018` | **The most common contact error.** A role is missing. On `/domains/register` this usually means a `contactType` capitalisation problem — it must be exactly `Registrant`, `Admin`, `Billing` or `Tech`. |
| `Dna.DomainService:Contact:10022` | Two contacts resolved to the same role. |
| `Dna.DomainService:Contact:10005` | `contactType` could not be resolved. |
| `Dna.DomainService:Contact:10006 / 10007` | Contact information incomplete, or the handle list is empty. |
| `Dna.DomainService:Contact:10008` | The handle does not exist **in your account**. |
| `Dna.DomainService:Contact:10019` | Handle empty or malformed. |
| `Dna.DomainService:Contact:10020` | The handle is linked to a domain you do not own. Nothing was changed. |
| `Dna.DomainService:Contact:10021` | A contact attached to a domain cannot be deleted. |
| `Dna.DomainService:Contact:10026` | The handle is used by several domains in a way that cannot be re-pointed safely. Create a dedicated handle. |
| `Dna.DomainService:Contact:10011` | Invalid e-mail address. |
| `Dna.DomainService:Contact:10012` | **Invalid country.** Must be an ISO 3166-1 alpha-2 code — `GB` not `UK`, `TR` not `Turkey`. |
| `Dna.DomainService:Contact:10013` | Phone country code contains non-digits. **Remove the `+`.** |
| `Dna.DomainService:Contact:10014` | Phone number unusable after normalisation. |
| `Dna.DomainService:Contact:10017` | The phone country code does not match the selected country. |
| `Dna.DomainService:Contact:10023 / 10024` | First or last name became empty after invalid characters were removed. Letters only. |
| `Dna.DomainService:Contact:10025` | A required field is missing. The message names it. |
| `Dna.DomainService:Domain:10037` | The domain uses the trustee service; its contacts cannot be changed. |
### Verification
| Code | Meaning and what to do |
| --- | --- |
| `Dna.DomainService:Contact:Verification:10010` | **Important.** You are changing a name, surname or company but the contact's e-mail is unverified. Verify the e-mail first. |
| `Dna.DomainService:Contact:Verification:10008` | An ownership-change verification is already open. Let it finish. |
| `Dna.DomainService:Contact:Verification:10006` | Handle not found in your account. |
| `Dna.DomainService:Contact:Verification:10005` | No verification record. Usually means the extension is outside verification scope, or verification finished long ago. Treat as "nothing pending". |
| `Dna.DomainService:Contact:Verification:10003` | Already verified. Treat as success. |
| `Dna.DomainService:Contact:Verification:10002` | Inside the 1-minute re-send cooldown. The message says how long to wait. |
| `Dna.DomainService:Contact:Verification:10001` | Send limit reached. The customer likely has a mail-delivery problem. Open a ticket. |
| `Dna.DomainService:Contact:Verification:10007` | Too many e-mail changes in one verification chain. Open a ticket. |
| `Dna.DomainService:Contact:Verification:10009` | This verification is finalised and cannot be re-sent. |
| `Dna.DomainService:Contact:Verification:10004` | The e-mail could not be sent. Retry shortly. |
## Extra registry fields
| Code | Meaning and what to do |
| --- | --- |
| `Dna.DomainService:TldAttribute:10001` | You sent a key this extension does not define. `details` lists them. Read valid keys from the catalogue. |
| `Dna.DomainService:TldAttribute:10002` | A required attribute is missing. `details` names it readably. |
| `Dna.DomainService:TldAttribute:10003` | A value failed validation. For identity numbers, `data.ValidationError` says which rule failed — length, format, repeated digits or checksum. |
| `Dna.DomainService:TldAttribute:10004` | This extension does not support internationalised names. |
| `Dna.DomainService:TldAttribute:10005` | Value longer than the attribute allows. |
## Trustee service
| Code | Meaning and what to do |
| --- | --- |
| `Dna.DomainService:Trustee:10006` | This extension **requires** the trustee service. Send `useTrusteeContact: true`. |
| `Dna.DomainService:Trustee:10002` | The trustee service is not available for this domain. Supply real contact details instead. |
| `Dna.DomainService:Trustee:10004` | This extension does not support the trustee service. |
| `Dna.DomainService:Trustee:10001` | No trustee price configured. Open a ticket. |
| `Dna.DomainService:Trustee:10003 / 10007 / 10008` | Trustee configuration problems on our side. Open a ticket. |
## Name server and host errors
| Code | Meaning and what to do |
| --- | --- |
| `Dna.DomainService:Dns:10022` | **Common.** Too few or too many name servers for this extension. Usually 2 to 13. |
| `Dna.DomainService:Dns:10013` | Duplicate entry in `nameServers`. |
| `Dna.DomainService:Dns:10005` | `nameServers` is empty. |
| `Dna.DomainService:Dns:10025` | The change would drop below the extension's minimum. |
| `Dna.DomainService:Dns:10003` | The name server or DNS record was not found. |
| `Dna.DomainService:Dns:10016` | A name server under this domain needs a glue IP. Create the host record first. |
| `Dna.DomainService:Dns:10019` | The host is not a subdomain of the domain. Most registries only accept glue for in-domain hosts. |
| `Dna.DomainService:Dns:10017` | Glue records are not allowed for this extension. |
| `Dna.DomainService:Dns:10018` | We could not determine how this extension models name servers. Open a ticket. |
| `Dna.DomainService:Dns:10021` | The host already exists on this domain. |
| `Dna.DomainService:Dns:10020 / 10004` | The host does not exist on this domain. |
| `Dna.DomainService:Dns:10023 / 10024` | The host cannot be deleted — it is still in use as a name server. Re-delegate first. |
| `Dna.DomainService:Dns:10007 / 10008` | Malformed IPv4 or IPv6 address. |
| `Dna.DomainService:Dns:10014` | `ipVersion` must be `v4` or `v6`. |
| `Dna.DomainService:Dns:10015` | Duplicate IP address in the request. |
| `Dna.DomainService:Dns:10026` | This extension does not accept IPv6 glue. Send only v4. |
| `Dna.DomainService:Dns:10012` | `hostName` is empty. |
| `Dna.DomainService:Domain:10070` | No DNS change is allowed while the domain is waiting for registry documents. |
## DNSSEC errors
| Code | Meaning and what to do |
| --- | --- |
| `Dna.DomainService:Dnssec:10005` | **The most common one.** The digest is not hexadecimal, or its length does not match the `digestType` you declared. SHA-1 is 40 characters, SHA-256 is 64, SHA-384 is 96. |
| `Dna.DomainService:Dnssec:10001` | This extension does not support DNSSEC. |
| `Dna.DomainService:Dnssec:10003` | Algorithm not permitted. Read `allowedAlgorithms` from `GET /dnssec`. |
| `Dna.DomainService:Dnssec:10004` | Digest type not permitted. Read `allowedDigestTypes`. |
| `Dna.DomainService:Dnssec:10002` | `keyTag` outside 0–65535. |
| `Dna.DomainService:Dnssec:10006` | That DS record already exists, or you sent it twice. **Often caused by resubmitting after `isPending: true`.** |
| `Dna.DomainService:Dnssec:10007` | Delete: no record matches all four fields. Copy them exactly from `GET /dnssec`. |
| `Dna.DomainService:Dnssec:10008` | Would exceed the maximum DS record count. Remove an old record first. |
| `Dna.DomainService:Dnssec:10010` | You are changing name servers while DNSSEC is active. Set `dnssecMode` to 1 or 2. |
| `Dna.DomainService:Dnssec:10011` | DS removal failed, so the name servers were not changed. Nothing was altered. |
| `Dna.DomainService:Dnssec:10012` | DS removal is queued for registry approval. Retry the name-server change afterwards. |
| `Dna.DomainService:Dnssec:10013` | The registry returned no DS record. Local records were preserved. Re-read the state. |
## DNS record errors
| Code | Meaning and what to do |
| --- | --- |
| `ZoneClient:10006` | The zone does not exist. Create the first record with `POST`. |
| `ZoneClient:10007` | No such record set, or no value matching what you sent. Read the zone and copy the value exactly. |
| `ZoneClient:10002` | An `A` record's value is not valid IPv4. |
| `ZoneClient:10003` | An `AAAA` record's value is not valid IPv6. |
| `ZoneClient:10010` | A `CNAME` or `MX` value is an IP address. These need host names. |
| `ZoneClient:10009` | An `MX` priority is not a number. The format is `10 mail.apiname.com`. |
| `ZoneClient:10004` | The record name is required and cannot start with `@`. A CNAME cannot sit at the apex — use `ALIAS`. |
| `ZoneClient:10005` | A `CAA` value is not three space-separated fields. `details` shows the format. |
| `ZoneClient:10011` | The record name does not belong to this zone. |
| `ZoneClient:10008` | The DNS server rejected the value's syntax. |
| `ZoneClient:10001` | The DNS service is temporarily unreachable. Retry shortly. |
| `Dna.DomainService:Zone:10001` | That exact value already exists in the set. Nothing was changed. |
| `ZoneClientValidationError` | A CNAME was sent without a `name`. |
## SSL errors
### Order and timing
| Code | Meaning and what to do |
| --- | --- |
| `Ssl:10026` | No certificate for this domain. Call `initialize` first. |
| `Ssl:10056 / Ssl:10077` | **The 7-day configuration window expired.** The fee is being refunded. Buy a new certificate. |
| `Ssl:10052` | A certificate with a different package is already awaiting configuration for this domain. |
| `Ssl:10013` | An active certificate already exists. Reissue or renew instead. |
| `Ssl:10027 / Ssl:10008 / Ssl:10041` | The certificate's status does not allow this operation. |
| `Ssl:10057` | Renewal is not open yet. The message gives the date. |
| `Ssl:10058 / Ssl:10059` | Already renewed, or not renewable. |
| `Ssl:10055` | The subscription has ended. Buy a new certificate. |
| `Ssl:10067` | The package is no longer on sale. |
| `Ssl:10003` | `packageCode` unknown. |
### CSR, names and configuration
| Code | Meaning and what to do |
| --- | --- |
| `Ssl:10040` | **Common.** The CSR's common name does not match `domainName`. Verify with `check-csr` before buying. |
| `Ssl:10004` | The CSR could not be decoded. Check the BEGIN/END lines. |
| `Ssl:10019` | Wildcard package but the CSR name does not start with `*.` |
| `Ssl:10015 / Ssl:10023` | `sanList` sent to a single-domain package, or missing on a multi-domain package. |
| `Ssl:10016 / Ssl:10022 / Ssl:10024` | `wildcardList` sent to a non-wildcard package, or missing on a wildcard package. |
| `Ssl:10017 / Ssl:10018 / Ssl:10032` | A wildcard or SAN name is invalid, or duplicates the main name. |
| `Ssl:10020 / Ssl:10021` | More than 255 SANs, or duplicates in the list. |
| `Ssl:10035 / Ssl:10030 / Ssl:10051` | The validation method is invalid, or not supported by this package or CA brand. |
| `Ssl:10037` | `webServerType` is not a valid value. |
| `Ssl:10014 / Ssl:10038` | `approverMail` malformed, or not on the approver list. |
| `Ssl:10010 / Ssl:10011 / Ssl:10012` | The `contact` object is missing or incomplete. |
| `Ssl:10001 / Ssl:10005` | Invalid domain name for a certificate. |
### Provider and lifecycle
| Code | Meaning and what to do |
| --- | --- |
| `Ssl:10053` | **Never retry.** Configuration has already been sent to the CA. Poll `check-status`. |
| `Ssl:10054` | **Never retry.** The outcome could not be verified. Open a ticket with the `certificateId`. |
| `Ssl:10048` | Not issued yet (or an invalid provider order — read the message). Keep polling. |
| `Ssl:10049` | The CA could not be reached, or a revoke failed. Read the message. |
| `Ssl:10050` | The CA rejected the request. Their explanation is in the message. |
| `Ssl:10006 / Ssl:10007` | Reissue is unsupported, or failed. |
| `Ssl:10031` | Certificate creation failed at the CA. |
| `Ssl:10070 / Ssl:10075 / Ssl:10076` | This package or operation is handled by our technical team. Open a support ticket. |
| `Ssl:10044 / Ssl:10046` | No price configured for this package. |
## Hosting errors
Hosting returns a plain English `message` without a code. Match on the message text.
| Message | Meaning and what to do |
| --- | --- |
| `Insufficient balance to purchase this hosting package.` | Top up and retry. |
| `The provided domain name is invalid.` | Fix `domainName`. |
| `Hosting not found.` | No matching record for the `serviceId` or `domainName`. |
| `You are not authorized to access this hosting.` | The record belongs to another reseller. |
| `Either serviceId or domainName must be provided.` | You sent neither. |
| `Provide only one of serviceId or domainName, not both.` | You sent both. |
| `No product is defined for package '{name}'.` | Configuration problem. Open a ticket. |
| `No price defined for package '{name}'.` | No price for your account on that package. Open a ticket. |
| `Token is required. / Token not recognized.` | Problem with the `token` on `/by-token`. |
| `Token was not recognized by the panel.` | The hosting panel rejected the token. |
| `No hosting account is available for this hosting.` | Provisioning never completed. Check `check-status`. |
## Validation errors
Requests that fail field validation return HTTP 400 with a `validationErrors` array rather than a single code. The `members` entry is prefixed with the contact role, so you can map it onto your form directly.
| Message pattern | What to fix |
| --- | --- |
| `{Role} first name is required.` | `firstName` missing on that role. |
| `{Role} first name must be at least 2 characters long.` | The name became empty or too short after non-letter characters were removed. |
| `{Role} 'company name' must be at least 2 characters long.` | `companyName` too short. Omit it entirely to have it auto-filled from the name. |
| `{Role} PhoneCountryCode must contain only digits (e.g., 90). Please do not use the '+' sign.` | **Remove the `+`.** |
| `{Role} EMail / Address / Phone / PostalCode / Country / City / State is required.` | That field is missing. `state` cannot be empty — repeat the city if the country has no states. |
| `domainName / privacyStatus / redirectAddress / forwardType field is missing` | Returned under the code `DnaValidationError`. The message names the field. |
---
# Status values
> Every status value in one place: domain status and reason, grace periods, contact roles, order and product types, and the quota cost of each endpoint.
Every status enumeration in one place, for reference.
## Domain status
Returned as a **name** by `GET /domains/info` and as a **number** by `GET /domains`.
| Value | Name | Meaning |
| --- | --- | --- |
| 0 | `Active` | Live and operational. |
| 1 | `WaitingForRegistration` | Registration in progress, or documents awaited. |
| 2 | `WaitingForDocument` | The registry is waiting for documents. **DNS changes are blocked.** |
| 3 | `WaitingForIncomingTransfer` | Transfer in from another reseller. |
| 4 | `TransferredOut` | Transferred away. |
| 5 | `TransferRejected` | Transfer refused. |
| 7 | `PendingDelete` | Queued for deletion. |
| 8 | `Deleted` | Deleted. |
| 9 | `ConfirmationEmailSend` | Transfer confirmation e-mail sent. |
| 11 | `WaitingForOutgoingTransfer` | Transfer out in progress. |
| 12 | `PendingHold` | **Suspended.** Read `statusReason` to find out why. |
| 15 | `ModificationPending` | A change — typically an ownership change — awaits approval. |
| 18 | `InCase` | Held for legal proceedings. |
| 19 | `PendingRestore` | Restore in progress. |
## Domain status reason
Explains *why* a domain is in its status. This is where you discover a suspension.
| Value | Name | Meaning |
| --- | --- | --- |
| 0 | `None` | No special reason. |
| 1 | `DocumentPendingForRegistration` | The registry asked for documents at registration. |
| 2 | `DocumentPendingForOwnerChange` | Documents required for an ownership change. |
| 3 | `DocumentInvalid` | A submitted document was rejected. Upload a corrected one. |
| 4 | `DocumentPendingForDeletion` | Documents required to delete. |
| 5 | `ApplicationCancelled` | Cancelled by the user. |
| 6 | `RddsVerificationPending` | **Suspended because the contact e-mail was never verified.** See [Contact verification](https://www.domainnameapi.com/docs/contacts/verification/). |
| 7 | `TransferCancelledFromClient` | Transfer cancelled by the client. |
| 8 | `TransferRejectedFromOpposed` | Transfer rejected by the other side. |
| 9 | `ApplicationRejected` | Application rejected. |
| 10 | `DomainExpired` | Expired. |
| 11 | `InLegalCase` | Legal hold. |
| 12 | `PhishingFraud` | Suspended for phishing or fraud. |
| 13 | `DocumentUnderReview` | An uploaded document is under registry review. |
## Grace period (`rgpStatues`)
| Value | Meaning |
| --- | --- |
| `ok` | Normal. No grace period in effect. |
| `addPeriod` | Just registered. A deletion now is usually refunded. |
| `autoRenewPeriod` | Auto-renewed at expiry; the renewal can still be reversed. |
| `renewPeriod` | Recently renewed. A further renewal may be refused briefly. |
| `redemptionPeriod` | **Deleted but recoverable.** The only state in which `POST /domains/restore` works. |
| `pendingDelete` | Beyond recovery. The domain will be released publicly. |
## Contact roles
| Value | Name |
| --- | --- |
| 1 | `Registrant — the legal owner` |
| 0 | `Admin — administrative contact` |
| 3 | `Tech — technical contact` |
| 2 | `Billing — billing contact` |
## Order and product types
| Value | orderType | Value | productType |
| --- | --- | --- | --- |
| 1 | `Register` | 1 | Domain |
| 2 | `Renew` | 2 | SSL |
| 3 | `Transfer` | 3 | Deposit |
| 4 | `Restore` | 4 | Domain trustee |
| 6 | `Backorder` | 5 | Hosting |
| 9 | `Trustee` | 6 | Ownership change |
| 10 | `Leasing (hosting)` | | |
| 11 | `Create (SSL, hosting)` | | |
| 12 | `OwnerChange` | | |
## Quick reference: endpoint quota cost
| Cost | Endpoints |
| --- | --- |
| **Free** | `GET /products/tlds` |
| **1 point** | `POST /domains/search` · `GET /domains/info` · `GET /products/info` |
| **10 points** | Everything else, including `POST /domains/bulk-search` |
Threshold is 200 points per area; points decay 20% per minute; above the threshold responses are delayed up to 5 seconds, not rejected. Separately, more than 5 requests per second (2 for search) is rejected with HTTP 429. See [Rate limits](https://www.domainnameapi.com/docs/getting-started/rate-limits/).