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.
- You create the domain:
POST /v1/domainsreturns the record to add and a connect link. - Your customer adds the record, alone or with the connect page.
- We see the record, confirm it from three resolvers, and request a certificate.
- The domain goes
activeand serves HTTPS. You getdomain.active.
The state machine
- pending_dns
- record seen
- verifying
- 3 of 3 resolvers agree
- issuing
- certificate stored
- active
- pending_dns
- 72 h, no record
- expired
- issuing
- fails after retries
- cert_failed
- backoff retry, or cause fixed
- issuing
- active
- removed or points elsewhere
- dns_broken
- record restored
- verifying
- any state
- held for review
- held
- released
- previous state
- any state
- DELETE /v1/domains/{id}
- deleted
| 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. 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}/verifyretries 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.
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.