## GET /api/v2/shared-hosting/{accountId}/actions/change-main-domain

**Check a main-domain change**

Return whether the main (primary) domain of a shared-hosting account can be changed, and what the change would do. Get `accountId` from `GET /api/v2/shared-hosting` `data[].id`. Without `domain` the response covers the account only: `available` / `reason`, the current `mainDomain`, the other domains attached, and the mailboxes on the main domain. With `domain` it also evaluates that target (`target.available` / `target.reason`), lists how each mailbox address changes, and includes the target's DNS preflight; supplying `domain` additionally requires the `read:dns` scope. The main domain can be changed to a domain from outside the account while it is the only domain on the account. An addon domain that is already on the account can take over as main domain when every other domain on the account is that addon domain or one of its subdomains: `promotableDomains` names it, and its evaluation carries `target.promotion`. Any other mix of attached domains returns `available: false`. A domain registered with HostUp, or with a DNS zone at HostUp, must be on the caller's own account (or covered by its owner's DNS delegation approval). Nothing is changed by this request.

### Related Endpoints

- `POST /api/v2/shared-hosting/{accountId}/actions/change-main-domain`: Change the main domain
- `GET /api/v2/shared-hosting/{accountId}/actions/sso`: Check control-panel SSO availability
- `POST /api/v2/shared-hosting/{accountId}/actions/sso`: Create hosting control-panel SSO link

### Headers

- `Accept`: application/json
- `Authorization`: Bearer YOUR_API_KEY
- Required API scopes: `read:hosting`, `console:services`

### Parameters

- `domain` (query, string): The domain to evaluate as the new main domain, without `www.`. Adds the `read:dns` scope requirement; does not change anything. Example: `example.net`
- `accountId` (path, string, required): Public shared-hosting account ID. Get it from `GET /api/v2/shared-hosting` `data[].id`. Do not invent this value; use the exact ID returned by the referenced API response. Example: `acct_01hxa3b4c5d6e7f8g9h0j1k2m3`

### Request Example

```bash
curl -X GET "https://cloud.hostup.se/api/v2/shared-hosting/acct_01hxa3b4c5d6e7f8g9h0j1k2m3/actions/change-main-domain" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json"
```

### Response Schema

- `available` (boolean, required): Whether the main domain of this account can be changed through the API right now.
- `reason` (string, required, nullable): Why the change is unavailable. `null` when `available` is true. Example: `null`
- `mainDomain` (string, required, nullable): The account's current main domain. Example: `example.com`
- `otherDomains` (array<string>, required): Every other domain attached to the account (addon domains, aliases and subdomains). When this list is not empty, only a domain in `promotableDomains` can become the main domain.
- `promotableDomains` (array<string>, required): Addon domains on the account that can take over as main domain: every other attached domain is that addon domain or one of its subdomains. Empty when the account has no such domain. Example: `[]`
- `emailAccounts` (array<any>, required, nullable): Mailboxes on the current main domain. These get addresses on the new main domain. `null` when the mailboxes could not be read.
- `actions` (object, required)
- `actions.canKeepPreviousDomain` (object, required): Whether `keepPreviousDomain: true` can be used on POST. Keeping the previous domain attaches it to the same website folder and uses one addon domain slot on the plan.
- `actions.canKeepPreviousDomain.allowed` (boolean, required) Example: `true`
- `actions.canKeepPreviousDomain.reason` (string, required, nullable): Nullable (may be null when not applicable). Example: `null`
- `actions.canKeepPreviousDomain.code` (string, optional, nullable): Machine-readable reason code when an action is blocked. Example: `pending_order`
- `target` (object, required, nullable): Evaluation of the `domain` query parameter. `null` when no `domain` was supplied.

### Responses

#### 200 - The account's main-domain state and, when `domain` was supplied, the evaluation of that target.
```json
{
  "available": true,
  "reason": null,
  "mainDomain": "example.com",
  "otherDomains": [],
  "promotableDomains": [],
  "emailAccounts": [
    "info@example.com"
  ],
  "actions": {
    "canKeepPreviousDomain": {
      "allowed": true,
      "reason": null
    }
  },
  "target": {
    "domain": "example.net",
    "available": true,
    "reason": null,
    "emailAccountChanges": [
      {
        "current": "info@example.com",
        "afterChange": "info@example.net"
      }
    ],
    "dnsSetup": {
      "usesHostupNameservers": true,
      "managedRecordsRead": true,
      "nameservers": [
        "primary.ns.hostup.se",
        "secondary.ns.hostup.se"
      ],
      "hasThirdPartyWebsiteRecords": false,
      "hasThirdPartyMailRecords": false,
      "requiresChoice": false,
      "recommendedPreference": "full",
      "records": {
        "website": [],
        "mail": []
      },
      "options": []
    },
    "promotion": null
  }
}
```

#### 400 - `domain` is not a full domain name, or starts with `www.`.
```json
{
  "type": "https://developer.hostup.se/errors/invalid_request",
  "title": "Invalid request",
  "status": 400,
  "detail": "`domain` must be a full domain name such as \"example.com\".",
  "instance": "/api/v2/shared-hosting/acct_01hxa3b4c5d6e7f8g9h0j1k2m3/actions/change-main-domain",
  "code": "invalid_request",
  "errors": [
    {
      "pointer": "/query/domain",
      "detail": "`domain` must be a full domain name such as \"example.com\".",
      "code": "invalid_request"
    }
  ]
}
```

#### 401 - Unauthorized. Authentication is required.
```json
{
  "type": "https://developer.hostup.se/errors/unauthorized",
  "title": "Unauthorized",
  "status": 401,
  "detail": "Authentication is required.",
  "code": "unauthorized",
  "instance": "/api/v2/resource",
  "requestId": "req_01hxa3b4c5d6e7f8g9h0j1k2m3",
  "timestamp": "2026-04-27T12:34:56.000Z"
}
```

#### 403 - Forbidden. The caller lacks a required scope or does not own the resource.
```json
{
  "type": "https://developer.hostup.se/errors/forbidden",
  "title": "Forbidden",
  "status": 403,
  "detail": "The caller lacks a required scope or does not own the resource.",
  "code": "forbidden",
  "instance": "/api/v2/resource",
  "requestId": "req_01hxa3b4c5d6e7f8g9h0j1k2m3",
  "timestamp": "2026-04-27T12:34:56.000Z"
}
```

#### 404 - Not found. The resource does not exist or is not owned by the caller.
```json
{
  "type": "https://developer.hostup.se/errors/not_found",
  "title": "Not found",
  "status": 404,
  "detail": "The requested resource could not be found.",
  "code": "not_found",
  "instance": "/api/v2/resource",
  "requestId": "req_01hxa3b4c5d6e7f8g9h0j1k2m3",
  "timestamp": "2026-04-27T12:34:56.000Z"
}
```

#### 409 - Conflict. `code` is `account_not_eligible_cpanel`.
```json
{
  "type": "https://developer.hostup.se/errors/account_not_eligible_cpanel",
  "title": "Control panel action unavailable",
  "status": 409,
  "detail": "This hosting account runs on a legacy control panel that does not support this action.",
  "code": "account_not_eligible_cpanel",
  "instance": "/api/v2/resource",
  "requestId": "req_01hxa3b4c5d6e7f8g9h0j1k2m3",
  "timestamp": "2026-04-27T12:34:56.000Z"
}
```

#### 429 - Rate limited. Retry after the limit resets. 429 responses include `Retry-After` seconds plus `X-RateLimit-*` headers.
```json
{
  "type": "https://developer.hostup.se/errors/rate_limit_exceeded",
  "title": "Too many requests",
  "status": 429,
  "detail": "Too many requests. Retry after the limit resets.",
  "code": "rate_limit_exceeded",
  "instance": "/api/v2/resource",
  "requestId": "req_01hxa3b4c5d6e7f8g9h0j1k2m3",
  "timestamp": "2026-04-27T12:34:56.000Z"
}
```

#### 500 - Internal error. Retry later or contact support if the issue persists.
```json
{
  "type": "https://developer.hostup.se/errors/internal_error",
  "title": "Internal server error",
  "status": 500,
  "detail": "An unexpected error occurred. Retry later or contact support if the issue persists.",
  "code": "internal_error",
  "instance": "/api/v2/resource",
  "requestId": "req_01hxa3b4c5d6e7f8g9h0j1k2m3",
  "timestamp": "2026-04-27T12:34:56.000Z"
}
```

#### 502 - The hosting account's domains could not be read right now. Retry later.
```json
{
  "type": "https://developer.hostup.se/errors/upstream_failed",
  "title": "Upstream request failed",
  "status": 502,
  "detail": "The hosting account's domains could not be loaded.",
  "instance": "/api/v2/shared-hosting/acct_01hxa3b4c5d6e7f8g9h0j1k2m3/actions/change-main-domain",
  "code": "upstream_failed"
}
```
