Register a domain
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
Section titled “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:
- Numeric first.
"0"→ Admin,"1"→ Registrant,"2"→ Billing,"3"→ Tech. A number outside 0–3 falls through to the next step. - First letter, case-insensitive. Starts with
A→ Admin,B→ Billing,R→ Registrant,T→ Tech. - 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 |
On /register — exact names only
Registering with contact details
Section titled “Registering with contact details”POST /api/v1/domains/register-with-contacts
Section titled “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
{ "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
{ "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
{ "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. |
Response — 200
{ "success": true, "message": "Domain registration successful", "domainId": "3c9a7e14-82b5-4d60-9f31-c7e8a05b6d42", "status": "Active", "expirationDate": "2027-10-30T12:04:17"}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
Section titled “Registering with handle codes”POST /api/v1/domains/register
Section titled “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
{ "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
{ "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:
{ "success": true, "message": "Domain registration successful", "domainId": "3c9a7e14-82b5-4d60-9f31-c7e8a05b6d42", "status": "Active", "expirationDate": "2027-10-30T12:04:17"}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?
Section titled “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.