
Custom domains, built
for multi-tenant SaaS.
One API call per customer hostname. Automatic SSL, automatic renewals, webhooks on every state change. The custom-domain layer your tenant table has been waiting for.
50 customer domains and 100 GB bandwidth free, forever.
Trusted by teams building the future of SaaS
Why a Custom Domains API for SaaS
Pass a metadata field on create (tenantId, customerSlug, plan). We echo it back on every webhook and GET. Your DB stays in sync without a lookup table joining our domain IDs to yours.
Building this in-house is a 2-4 month project plus ongoing care. Domainee handles ACME, edge TLS termination, SNI routing, DNS health, renewals, and the 2am pager rotation.
$0.20/domain/month, halving to $0.10 at 10,000+ customer domains. $0.05/GB after 400 GB included. No contact-sales gate, no enterprise-only tier.
Why SaaS teams pick custom domains as a feature: the customers who pay for branded URLs are usually the customers who renew. Letting them point portal.acme.com at your app is a small product change with an outsized impact on plan upgrades and retention.
Two endpoints, one webhook handler.
Your tenant table gets a custom_domain_id column. The rest is two API calls and a webhook receiver.
POST + return the CNAME to the customer
async function connectTenantDomain(tenant, hostname) {
const res = await fetch(
"https://api.domainee.dev/v1/domains",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.DOMAINEE}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
hostname,
originUrl: process.env.MY_APP_ORIGIN,
metadata: { tenantId: tenant.id },
}),
},
);
const { domain } = await res.json();
await db.tenants.update(tenant.id, {
customDomainId: domain.id,
customDomainHostname: hostname,
});
return domain.dnsRecords; // hand the CNAME to your customer's UI
}One webhook, mark the tenant live
app.post("/webhooks/domainee",
express.raw({ type: "application/json" }),
async (req, res) => {
if (!verifyHmac(req)) return res.status(401).end();
const event = JSON.parse(req.body.toString());
if (event.type === "domain.verified") {
const tenantId = event.data.metadata?.tenantId;
await db.tenants.update(tenantId, {
customDomainStatus: "live",
});
}
if (event.type === "domain.failed") {
const tenantId = event.data.metadata?.tenantId;
await db.tenants.update(tenantId, {
customDomainStatus: "broken",
});
}
res.status(200).end();
},
);Read the full step-by-step in the SaaS integration guide.
Who ships custom domains on Domainee
SaaS teams from indie hackers up through scaleups treating 50-5,000 customer hostnames as a routine feature.
Engineering teams at scaleups
50-5,000 customer hostnames is exactly the band where building it yourself costs more than buying. We replace 2-4 months of v1 plus ongoing cert + DNS care.
Indie hackers & solo founders
Ship custom domains on a Tuesday afternoon. No card on file. Revisit billing only when the free tier is no longer enough.
Agencies & platform builders
One Domainee workspace per client. Same API keys, same webhook handler reused across every product you ship for clients.
Builders shipping with AI
Writing the app in Cursor or Claude Code? Connect the Domainee MCP server and let your agent provision, debug, and monitor customer domains.
Multi-tenant infra you don't maintain
- An ACME-v2 client with retry and rate-limit handling.
- An edge cert store with SNI routing for thousands of hostnames.
- A DNS health monitor with drift detection and webhooks.
- A renewal cron with monitoring, alerting, and manual override.
- An SSRF blocklist + private-IP guard for customer origin URLs.
- A hostname-to-tenant mapping table with cascading deletes when a tenant churns.
- A reseller-style billing model for agencies running multiple workspaces.
See the 20+ SaaS use cases covered: white-label, course platforms, membership sites, creator storefronts, link-in-bio, and more.
Frequently asked
- What counts as a SaaS that needs custom domains?
- Any product that lives at a customer-specific URL: dashboards, portals, storefronts, course pages, scheduling links, embedded widgets, AI chat installations, landing-page builders. If your tenant table has a 'subdomain' column, you eventually want a 'custom_domain' column too.
- How does multi-tenant routing work at the edge?
- Each customer registers a hostname through POST /v1/domains. Our Multi-Region edge maintains a hostname-to-origin map shared across regions; on every request we look up the customer's origin URL and proxy. Header forwarding, status pass-through, and cert selection all happen per-hostname, and latency-based DNS routes each end-user to the nearest healthy region automatically.
- Do my customers see Domainee anywhere?
- No. The CNAME target (edge.domainee.dev) is the only Domainee string they encounter, and that's hidden inside their DNS provider. The cert is for their hostname, served from their domain, with your app's content. Domainee never appears in the user-facing path.
- How do I associate a Domainee hostname with my tenant in our DB?
- Pass a metadata field on POST /v1/domains. We echo it back verbatim on every webhook and on every GET. So you can stash { tenantId: 'tnt_77721' } and your webhook handler joins it to your DB without an extra lookup.
- What's the failure mode if a customer's DNS breaks later?
- Our monitor flips domain.monitor_updated with the new state (dns_drift, dns_not_resolving, etc.) and fires a webhook. The customer-facing UI in your dashboard surfaces the issue with specific guidance — you don't write the diagnostic logic.
- Can I let agencies / resellers manage their clients' domains?
- Yes. Use one Domainee workspace per agency. Each workspace has its own API key and webhook endpoints. The pricing is per-workspace, so an agency with 100 clients gets the same per-domain rate, billed back to them.
- Does this work for B2B SaaS where each tenant has its own users?
- Yes. Multi-tenant routing doesn't care about your end-users — only your tenant. The hostname maps to your tenant's origin, your app authenticates the end-user normally. Auth, billing, and tenancy stay in your code.
- What changes when we hit 10,000 customer domains?
- Pricing graduates from $0.20/domain to $0.10/domain (50% off). No code change, no contact-sales gate. The pricing curve is published all the way up — no surprise pricing once you grow.
Still have questions? Ask our team →
Ship custom domains for your SaaS today.
Mint an API key, drop the snippet above into your tenant onboarding flow, give your customers a branded URL by the end of the day.


