# The connection's latest nameserver migration

> The connection's latest nameserver migration: CustomDomain™ API reference in the nameservers group. Covers parameters, request body, responses and error codes.

Source: https://docs.customdomain.ai/docs/api-reference/nameservers/getNameserverMigration

## `GET https://api.customdomain.ai/v1/connections/{id}/nameservers`

The newest nameserver migration started for the connection's domain: its state, the old and new nameservers, what the registry lists now, what it waits on (`waiting_for`) and what a person does next (`next_step`). Poll it while the state is not `active`, `failed` or `rolled_back`. 404 when no migration was started for this connection. Authorized like the other connection routes: an API key within the tenant, or a widget token of the connection's own application. A delegated agent token needs `domains:read`.

### Authentication

`apiKey`, `widgetJWT`, `agentToken`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes |  |

### Responses

| Status | Description |
| --- | --- |
| `200` | The migration |
| `401` | Error envelope: {code, title, details}. |
| `403` | Error envelope: {code, title, details}. |
| `404` | Error envelope: {code, title, details}. |
| `503` | Error envelope: {code, title, details}. |

### `200` response body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes |  |
| `connection_id` | string | no |  |
| `zone` | string | yes | The registrable domain whose nameservers move. |
| `state` | `pending`, `copying`, `needs_review`, `needs_dnssec_off`, `waiting_ds`, `setting`, `propagating`, `active`, `failed`, `rolled_back` | yes | `pending`: target `custom` waits for the platform's zone. `copying`: the zone is being created and the records copied; a copy whose write to the DNS servers failed is retried, never switched to. `needs_review`: the copy is not proven complete (it was read from public DNS, which can't list a zone, or some records could not be carried over); a person checks `copy_warnings` and confirms with `copy_reviewed`. `needs_dnssec_off`: DNSSEC must be turned off at the registrar first. `waiting_ds`: DNSSEC is off; waiting for the registry to stop publishing the DS record and its TTL to pass. `setting`: the nameservers are being changed (`waiting_for` says by whom). `propagating`: changed; waiting for the registry to list every new nameserver (checked every 5 minutes for 2 hours, then hourly up to 48 hours). `active`: the registry lists them (re-checked every 6 hours; a move away is `failed` with `delegation_drift`). `failed`: see `failure_code`. `rolled_back`: moved back. |
| `path` | `api`, `agent`, `manual` | yes |  |
| `target` | `managed`, `dns_host`, `custom` | yes |  |
| `dns_host` | string | no | The DNS host of target `dns_host` (an adapter id such as `cloudflare`). |
| `provider` | string | no | Where the nameservers are changed: the registrar's provider id (`registrar.provider`), or, when `registrar` is null, the DNS host the domain used, as a guess (then `next_step` says "where the domain is registered" and names no company). |
| `registrar` | object | yes | Who the domain is registered with (RDAP, or the account or key the caller brought); null when unknown. |
| `old_dns_host` | string | no | The DNS host the domain used when the move started (a provider id such as `cloudflare`). |
| `old_nameservers` | array of string | yes | What the registry listed when the move started; a rollback sets these. |
| `new_nameservers` | array of string | yes |  |
| `observed_nameservers` | array of string | yes | What the registry listed at the last check. |
| `waiting_for` | `zone_ready`, `zone_served`, `copy_review`, `dnssec_off`, `ds_clear`, `credential`, `registrar_confirm`, `browser_session`, `registrar`, `delegation` | no |  |
| `next_step` | string | no | One sentence for a person. |
| `failure_code` | `zone_copy_failed`, `zone_not_served`, `dnssec_timeout`, `ds_removal_failed`, `credential_refused`, `registrar_refused`, `registrar_locked`, `changed_elsewhere`, `agent_failed`, `delegation_timeout`, `delegation_drift`, `internal` | no | `changed_elsewhere`: the registrar listed other nameservers than the ones the move started from, so the change did not overwrite them. |
| `failure_detail` | string | no |  |
| `records_copied` | integer | yes |  |
| `email_records` | integer | yes | How many of the copied records carry mail (MX, SPF, DKIM, DMARC). |
| `email_kinds` | array of `mx`, `spf`, `dkim`, `dmarc` | yes |  |
| `copy_source` | `api`, `discovery`, `existing_zone` | no | How the records were copied. `api`: the whole zone, read through a key we hold at the DNS host the domain used (a kept sign in or a connected account there); proven complete. `discovery`: read from public DNS at the names domains commonly use; a person confirms it. `existing_zone`: the platform's zone already held records, which were kept. |
| `copy_warnings` | array of string | yes | What a person should check before the switch: records left out (a Cloudflare proxied record answers with Cloudflare's addresses, not the origin), lookups that went unanswered, forwarding that stays at the old host. |
| `copy_reviewed_at` | string | no | When a person confirmed a copy that is not proven complete. |
| `ds_present` | boolean | yes | The registry published a DS record (DNSSEC was on) during the move. |
| `ds_removed_at` | string | no |  |
| `ds_cleared_at` | string | no |  |
| `can_rollback` | boolean | yes |  |
| `rollback_path` | `api`, `agent`, `manual`, `none` | no | How the move back was made: `api` (the registrar's API, done), `agent` (the person signs in to the registrar in the cloud browser with `purpose: nameservers` and approves it), `manual` (`next_step` says what to set or choose), `none` (nothing had changed yet). |
| `rollback_targets` | array of `previous`, `registrar_default` | yes | The move backs possible now; `previous` is left out once the old nameservers no longer answer for the zone. |
| `rollback_default` | `previous`, `registrar_default` | no | Where a move back without `rollback_target` goes. |
| `rollback_target` | `previous`, `registrar_default` | no | Where the move back went. |
| `rollback_set_at` | string | no | When the move back was made at the registrar; absent while a person or the cloud browser still has it to do. |
| `old_dns_serves` | boolean or null | yes | Whether the old nameservers still answered for the zone when last asked (once a day while active, and at a move back); null when not asked yet. |
| `consent` | object | no |  |
| `actor` | `end_user`, `api_key`, `console`, `agent` | no |  |
| `created_at` | string | yes |  |
| `set_at` | string | no | When the nameservers were changed at the registrar (or first seen changed). |
| `active_at` | string | no |  |
| `failed_at` | string | no |  |
| `rolled_back_at` | string | no |  |
| `drifted_at` | string | no |  |
| `checked_at` | string | no |  |
| `next_check_at` | string | no |  |
| `updated_at` | string | yes |  |

The full specification is served at `GET https://api.customdomain.ai/v1/openapi.json`.
