# How it works

A domain moves through a handful of states, each with one owner and a fixed check cadence. Every move is recorded and fires one webhook.

## The request path

Your customer adds one DNS record that points their hostname at Apexly. Visitors then reach our edge, which terminates TLS with a certificate issued for that hostname and forwards the request to your app's origin with the original `Host` header and a signature. Your app never handles certificates or DNS.

1. You create the domain: `POST /v1/domains` returns the record to add and a connect link.
2. Your customer adds the record, alone or with the [connect page](/docs/connect-page).
3. We see the record, confirm it from three resolvers, and request a certificate.
4. The domain goes `active` and serves HTTPS. You get `domain.active`.

## The state machine



| State | What it means | Checked |
| --- | --- | --- |
| `pending_dns` | Waiting for the customer's record. `status_reason` says what we found instead. | Every 15 s for the first hour, then every 5 min, for 72 h |
| `verifying` | Record seen once; confirming it from 1.1.1.1, 8.8.8.8 and the zone's own nameservers. | Every 5 s, up to 2 min |
| `issuing` | DNS verified; the certificate is being issued. | Every 5 s, up to 10 min |
| `active` | Serving HTTPS. The certificate renews itself from day 60. | DNS every 6 h, origin every 15 min |
| `dns_broken` | Was active; the record was removed or points elsewhere. The existing certificate keeps serving. | Every 15 s for an hour, then every 5 min |
| `cert_failed` | Issuance or renewal failed after retries. `status_reason` names the cause. | Retries at 1 min, 5 min, 30 min, 2 h, then every 12 h |
| `expired` | The record never arrived within 72 hours. Nothing was billed. | Not checked; kept 30 days |
| `held` | Paused for review before any certificate is requested. A person reviews within one business day. | Not checked until released |
| `deleted` | Removed. Routing stops within 5 seconds and the hostname can be added again. | Not checked |

## What a subdomain needs

One CNAME from the hostname to the `dns.cname.value` in the domain object (or to your white-label host, if you set one). We follow up to five CNAME hops.

## What an apex needs

An apex (`acme.com`) cannot have a CNAME, so it needs the A records in `dns.apex.a` (and AAAA, if the zone has any, set to `dns.apex.aaaa`) plus a TXT record at `_apexly.<hostname>` with the value in `dns.apex.txt`. The TXT record proves control; the A records route traffic. Set `apex_redirect: "www"` to redirect the apex to `www`.

## Reasons

When a domain is not `active`, `status_reason` and `status_detail` explain why in the same words the dashboard and the connect page use. Every reason has a page under Troubleshooting, for example [dns_record_mismatch](/docs/troubleshooting/dns_record_mismatch). Reasons without their own page:

- `confirming_record` (`verifying`): the record landed; we are confirming it from three resolvers.
- `issuing_certificate` (`issuing`): DNS is verified and the certificate is being issued; usually under a minute.
- `serving` (`active`): live; nothing to do.
- `ca_error` (`cert_failed`): the certificate authority refused for a reason we could not classify. We retry with backoff; `POST /v1/domains/{id}/verify` retries now.
- `held_for_review` (`held`): paused for review before issuing a certificate.
- `deleted` (`deleted`): routing stopped.
- `sandbox`: a test domain moving through the states on a timer; see [Test mode](/docs/guides/test-mode).

## Webhooks

Every transition writes an event to `GET /v1/events` and, for `domain.created`, `domain.verified`, `domain.active`, `domain.dns_broken`, `domain.cert_failed`, `domain.certificate_renewed`, `domain.deleted`, `domain.held` and `domain.released`, sends one signed webhook. See [Webhooks](/docs/webhooks).

- [Quickstart](/docs/quickstart)
- [Webhooks](/docs/webhooks)
- [Test mode](/docs/guides/test-mode)
- [Troubleshooting](/docs/troubleshooting/dns_record_missing)
