> ## Documentation Index
> Fetch the complete documentation index at: https://docs.erdo.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom domains

> Serve your published pages from your own hostname — register a branded domain, watch its DNS and certificate go live, and move it between organizations without downtime.

# Custom domains

Published pages normally serve from Erdo's pages host. A **custom domain** puts them on a hostname
you own instead — `pages.acme.com` rather than `pages.erdo.ai` — via a single CNAME record. The
domain belongs to your **organization**, not to one page: once active, every public page the org
publishes is reachable on it, and share links are built on it automatically.

## How a domain goes live

1. **Register the domain.** Use a direct subdomain of a domain you control (e.g. `pages.acme.com`
   — a root domain can't carry the CNAME). Registration returns the DNS records to create.
2. **Create the DNS records.** A routing CNAME pointing at Erdo's pages host, plus a one-time
   `_acme-challenge` delegation CNAME so certificates can issue and renew without you ever
   touching DNS again.
3. **Wait for validation.** Erdo re-checks the domain continuously: ownership is verified from the
   routing CNAME, then a certificate is issued, then the domain starts serving.

The domain's `status` tells you exactly where it is in that walk:

| Status         | Meaning                                                                                                            |
| -------------- | ------------------------------------------------------------------------------------------------------------------ |
| `pending_dns`  | Waiting for the routing CNAME to appear at your DNS provider.                                                      |
| `pending_cert` | Ownership verified; the certificate is issuing.                                                                    |
| `active`       | Serving traffic.                                                                                                   |
| `failed`       | Something is actually wrong — `error_reason` says what (most commonly a CAA record blocking certificate issuance). |
| `disabled`     | The registration no longer exists upstream.                                                                        |

Status is read from the same record the page-serving path uses — never a cached copy that can
drift — and `last_checked_at` says when it was last reconciled, so a domain that has sat in
`pending_cert` for a month is visible for exactly what it is.

## API

All endpoints act on the caller's organization and require an **org admin**. Domains are addressed
by the domain name itself — a name registered to another organization answers `404`, with no hint
that it exists.

List the org's domains with live status:

```bash theme={null}
curl https://api.erdo.ai/v1/custom-domains \
  -H "Authorization: Bearer $ERDO_API_KEY"
```

Register a domain (the response carries `dns_records` — the records to create):

```bash theme={null}
curl -X POST https://api.erdo.ai/v1/custom-domains \
  -H "Authorization: Bearer $ERDO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"domain": "pages.acme.com"}'
```

Remove a registration (the hostname stops serving pages):

```bash theme={null}
curl -X DELETE https://api.erdo.ai/v1/custom-domains/pages.acme.com \
  -H "Authorization: Bearer $ERDO_API_KEY"
```

On the CLI: `erdo pages domains list | add <domain> | remove <domain> | transfer <domain> <org>`.
The MCP tool `erdo_list_custom_domains` gives agents the same read; mutations are deliberately
REST/CLI-only.

## Moving a domain between organizations

When a customer's pages are rebuilt in a new organization — a tenant migration, a portal cutover —
the branded hostname has to start serving the new org's pages. Deleting and re-registering it would
tear down its CDN hostname and force certificate re-issuance: a visible outage on a live domain.
**Transfer** avoids that entirely:

```bash theme={null}
curl -X POST https://api.erdo.ai/v1/custom-domains/pages.acme.com/transfer \
  -H "Authorization: Bearer $ERDO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"target_org": "acme-new"}'
```

The domain keeps its CDN hostname and certificate; only its owning organization changes, so serving
flips to the target org atomically with the move — zero downtime, nothing to re-validate, no DNS
changes for the customer.

Transfer is **two-sided by construction**: you must be an org admin of the organization that owns
the domain *and* of the target organization. A
[manager account](/manager-accounts) satisfies both when steering a domain between its own managed
orgs — which is exactly the cutover case — and nobody who administers only one side can move a
domain in or out. Transfers are idempotent: re-running one that already happened succeeds without
changing anything.

## Scope and limits

* Domains must be **direct subdomains** (`pages.acme.com`, not `acme.com` or `pages.team.acme.com`).
* A domain can be registered to **one organization at a time**, platform-wide.
* Each organization can hold up to **25** custom domains.
* Registration, validation, and certificate mechanics are platform-owned — you only ever create the
  DNS records the API hands you.
