Launch offerThe first 20 customers get 20 domains free. No card.
Five steps, one of them yours

How a domain goes live.

You make one request. Your customer adds one record. Everything between those two moments, and everything after, is ours.

1You

Ask for the domain.

One POST with your customer's hostname. You get back the record they need and a connect link to send them. Subdomains get a CNAME; apex domains like globexcareers.com get an A record and a TXT token.

curl -X POST https://api.apexly.dev/v1/domains \
  -H "Authorization: Bearer sk_live_…" \
  -d '{"hostname":"careers.acme.com"}'{
  "status": "pending_dns",
  "cname": { "value": "d-tuih5b.cname.apexly.dev" },  "connect_url": "https://connect.apexly.dev/c/kuu…"}
2Your customer

They add one record.

The connect page looks up where their DNS lives (we recognise 46 providers, from GoDaddy to Route 53) and shows exactly where to click, in plain words. No support ticket, no screenshot of a DNS panel.

3Apexly

We check it three times.

Cloudflare's resolver, Google's, and the domain's own nameservers must all agree before we move on. If the record is wrong, we say what we expected and what we found.

4Apexly

We get the certificate.

Only for hostnames we verified, never on a guess. Let's Encrypt issues it, ZeroSSL steps in if it can't, and renewal starts 30 days before expiry. You never see a certificate again.

5Apexly

Visitors reach your app.

Our edge terminates HTTPS and forwards each request to your origin with the original Host header and a signature. You get a domain.active webhook and mark the tenant live.

Your app changes one thing.

Read the Host header to find the tenant, and check the signature so nobody can reach your origin pretending to be us. Copy-paste helpers for Next.js, NestJS, Rails, Django, Laravel and Go are in the docs.

Host: careers.acme.com
X-Forwarded-Proto: https
X-Apexly-Domain-Id: dom_8f3a
X-Apexly-Timestamp: 1760587971
X-Apexly-Signature: 9a3f…// signature = HMAC-SHA256(secret, timestamp + "." + host)
const tenant = await tenants.byHost(req.headers.host);

And when something goes wrong, it says so.

Every domain is always in one of these states. Each change fires a signed webhook, shows in the dashboard, and comes with a reason and a fix you can show your customer.

pending_dnsWaiting for your customer's record

We check every 15 seconds for the first hour, then every 5 minutes for 72 hours.

verifyingRecord found, double-checking

Three resolvers must agree, so a stale cache never fools us.

issuingGetting the certificate

Let's Encrypt first, ZeroSSL if it has a bad day.

activeLive over HTTPS

We re-check DNS every 6 hours and renew from day 60 of 90.

dns_brokenYour customer changed their DNS

We keep serving the cert, keep checking, and tell you which record moved.

cert_failedThe CA said no

Usually a CAA record. The error names the exact record to add.

Built so traffic keeps flowing.

The edge that serves your customers is separate from the API and dashboard. It keeps its own copy of every route and certificate, so if our control plane is down for maintenance, your customers' domains keep working.

Control planeAPI, dashboard, DNS checks, certificates, webhooksChanges routes. Never sits in a request.
mTLS, private
EdgeTLS, routing, signaturesServes every request. Keeps serving on its own.

Go make someone's domain live.

Get API key