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

# Troubleshooting: DOMAIN_NOT_FOUND (404) on a branded console and public resolve

> Resolve the 404 DOMAIN_NOT_FOUND that blocks a white-label console on a custom domain — unclaimed or not-yet-active domain, CNAME drift, removed CNAME mid-provisioning, wrong vs missing host, and branded sign-in fallback rendering.

# Troubleshooting: DOMAIN\_NOT\_FOUND (404)

Your branded console is supposed to load at a custom domain —
`app.acme.example` instead of `orbit.devotel.io` — and the page renders
with the plain Orbit look, or a pre-render lookup fails with a **404** and
code `DOMAIN_NOT_FOUND`:

```json theme={null}
{
  "error": {
    "code": "DOMAIN_NOT_FOUND",
    "status": 404
  }
}
```

Three public lookup surfaces return this code for the same root cause —
no registered custom-domain record in the `active` state matches the
host:

* `GET /api/v1/public/resolve-domain?host=…` — the host-to-organization
  lookup the dashboard runs up-front on every request whose Host is not
  the platform domain.
* `GET /api/v1/public/resolve-org-domain?org_id=…` — the reverse lookup
  that sends a subaccount user home to their branded origin right after
  sign-in.
* `GET /api/v1/public/branding?host=…` — the pre-auth branding lookup
  that renders your logo, colors, and dashboard name on the sign-in,
  signup, and invite screens of the custom domain.

Knowing which surface returned the 404 narrows the cause, but the fix is
always on the custom-domain record itself.

<Note>
  When a lookup misses, the platform **degrades instead of breaking**: the
  console falls back to the neutral default theme, branded sign-in lands
  on `orbit.devotel.io`, and nothing your customers are doing stops
  working. That is the difference between a 404 you need to fix and a
  ticket you need to file — this page walks the self-serve cases first.
</Note>

***

## Cause table

List your organization's custom domains with `GET
/api/v1/organization/domains` and match the row's `status` against the
causes below. The statuses and their lifecycle — `pending → verifying →
active / failed` — are explained in
[Custom domains and managed SSL](/concepts/custom-domains-and-ssl).

| Cause                                   | How to confirm                                                                                                                                                         | Fix                                                                                                                                                                                    |
| --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Domain never claimed                    | The host is absent from `GET /organization/domains`.                                                                                                                   | Register it from **Settings → Branding → Custom domain** (or `POST /api/v1/organization/domains` with the exact hostname).                                                             |
| DNS not yet verified                    | `status: "pending"`. The record exists but the CNAME has not resolved satisfactorily.                                                                                  | Publish the CNAME pointing at the exact `cname_target` returned for the domain, wait out your record TTL, then hit **Verify** (`POST /api/v1/organization/domains/{domainId}/verify`). |
| Certificate still issuing               | `status: "verifying"` — DNS already matched; certificate issuance is in flight (about 15 minutes, longer if HTTPS activation is queued for platform review).           | No action on your side. The lookup flips to resolving on its own when the row reaches `active`. Never remove the CNAME during this window — that is the usual cause of a stall.        |
| CNAME removed mid-provisioning          | `status` bounces back to `pending` or `failed` after you saw it in `verifying`.                                                                                        | Restore the CNAME exactly as before, then verify again. Issuance restarts on the next verify.                                                                                          |
| Terminal issuance failure               | `status: "failed"`; the domain row carries an `error` naming the issuer's reason.                                                                                      | Fix the cause the `error` field names (almost always DNS), then verify again — the platform retries until you delete the domain.                                                       |
| Wrong or mismatched host                | The lookup queries a hostname that differs from the claimed record — an apex domain when a subdomain was claimed, a trailing dot, or a subdomain you never registered. | Claim the exact host the browser resolves. An apex and its subdomains are separate claims; the platform does not wildcard them.                                                        |
| Stale edge cache right after activation | The domain just reached `active` but the first page load still falls back to the neutral theme.                                                                        | Wait up to two minutes. Lookups are edge-cached for about a minute with a short stale-while-revalidate window, so the first refresh after activation self-heals.                       |

***

## Decision checklist

Work through these in order before you change anything:

1. **Reproduce the 404.** `curl "https://api.orbit.devotel.io/api/v1/public/resolve-domain?host=app.acme.example"`
   with the exact host from the browser's address bar. A 200 returns the
   `{ organization_id, tenant_id }` pair and the console will load with
   your branding; a 404 returns `DOMAIN_NOT_FOUND`.
2. **List the claims.** `GET /api/v1/organization/domains` — find the row
   whose `domain` equals the host character-for-character. No row means
   the domain was never claimed. A row with `status` `pending`,
   `verifying`, or `failed` means resolution is by-design 404 until it
   activates.
3. **Check the DNS record.** The CNAME must point at the exact
   `cname_target` the claim returned, with no substitute or old value
   still present. Flattened or chained CNAMEs resolve as long as the
   chain terminates at that target.
4. **Re-verify once.** `POST /api/v1/organization/domains/{domainId}/verify`
   after any DNS change. One verify is enough — re-issuing every few
   minutes does not speed certificate issuance.
5. **Remember the fallback.** While the lookup 404s, sign-in, the
   dashboard, and any API on the host still work under the neutral
   default theme; your team is not locked out.

***

## What NOT to do

* **Do not delete and re-claim the domain while it is `verifying`.**
  Issuance started the moment the CNAME matched; tearing the record down
  mid-flight discards it and pushes activation back out by the full
  provisioning window.
* **Do not point the CNAME at something else and back.** Every change
  re-opens the provisioning window; the publish-once-then-wait pattern is
  the fastest path.
* **Do not retry-loop the public endpoints.** A 404 `DOMAIN_NOT_FOUND` is
  a lookup miss, not a transient failure — the same host 404s identically
  every time until the domain activates. Those endpoints are rate-limited
  per IP and short edge-cached, so looping buys nothing.
* **Do not claim the apex domain and expect subdomains to resolve.**
  Each host (`app.acme.example`, `console.acme.example`) is its own
  claim row.
* **Do not file a ticket for a `pending` domain whose CNAME has never
  published.** The platform cannot verify DNS you have not created.

***

## When to escalate

Escalate to [support@devotel.io](mailto:support@devotel.io) when:

* The row has sat in `verifying` for **more than 24 hours** with the
  CNAME unchanged and correctly pointed.
* The row is `failed` and the `error` field does not describe a DNS
  problem (for example, an issuer-side or platform-side failure).
* The lookup still 404s **after** the domain reached `active`, and the
  two-minute edge-cache window has passed.

Include in the ticket:

* The exact hostname you claimed and the exact `host` query that 404s
* The domain id and current `status` from
  `GET /api/v1/organization/domains`
* The `request_id` from `meta.request_id` on a 404 response, if you have
  one
* Confirmation that the CNAME points at the `cname_target` the claim
  returned (paste the record)

***

## Related

* [Branding console: logo, colors, and custom domain](/guides/branding-console-white-label) —
  the full page walkthrough, including the register → publish → verify →
  TLS flow.
* [Custom domains and managed SSL](/concepts/custom-domains-and-ssl) —
  the lifecycle, status vocabulary, and certificate issuance model behind
  the 404-to-resolving transition.
* [Error Codes reference](/reference/error-codes) — the
  `DOMAIN_NOT_FOUND` row and its sibling public-surface 404s.
* [Email DNS drift and recovery](/troubleshooting/email-dns-drift) — the
  same verify-again discipline for email-sending domains, which run on a
  separate pipeline.
