# 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. |
