Custom Domains API: What It Is, How It Works, and What It Costs

A custom domains API is an API your SaaS calls so its users can connect their own domain (say, app.theircompany.com) to your product. The API handles DNS verification, SSL certificates and ongoing monitoring. You make one call per domain. Your customer adds one DNS record. Everyone goes back to their day.
The category goes by a few names: custom-domains-as-a-service, bring your own domain (BYOD), white-label domains. Same idea. Domainee by Common Ninja is a custom-domains-as-a-service API for SaaS products, with automatic SSL, DNS monitoring and webhooks. This page is the reference we wish existed: real endpoints, real limits, real prices.
What is a custom domains API?
Your users ask: "Can I use my own domain?" Your answer today is probably "it's on the roadmap." A custom domains API makes that answer "yes, by Tuesday."
The API sits between your customer's DNS and your app. You send it a hostname and the origin that should serve it. It tells your customer what DNS record to add. Once the record resolves, it issues a certificate and routes traffic. It keeps checking afterward, so you hear about breakage before your customer's support ticket does.
Three jobs, in short:
- Connect: map
app.theircompany.comto your origin. - Secure: issue and renew the SSL certificate. Forever.
- Watch: monitor DNS health and tell you when something changes.
Domainee is white-label too. Your customers never see Domainee.
Looking for API Gateway custom domain names instead?
Quick check. If you want
api.yourcompany.comin front of your own API on AWS API Gateway or Azure API Management, that's a cloud-provider setting. It's not what this guide covers.
The difference is who brings the domain. There, you configure one domain for your own API. Here, your customers bring the domains, and there can be hundreds or thousands of them. For the short definition, see the glossary entry on custom domain API.
How a custom domains API works: one call, one CNAME
Here's the whole flow with Domainee. REST, JSON only, Bearer API keys (sk_live_...), base URL https://api.domainee.dev/v1.
curl -X POST https://api.domainee.dev/v1/domains \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 7d1f2c9e-signup-acme" \
-d '{
"hostname": "app.theircompany.com",
"originUrl": "https://yourapp.com"
}'
The response returns the CNAME your customer needs to add. It also reports status and monitorStatus, so you can show setup progress in your own UI. Want the full request and response shape? See the create a domain endpoint reference.
What your customer does
One thing: adds a CNAME at their DNS provider. That's it.
Apex domains (theircompany.com, no subdomain) are supported too. Some DNS providers disallow a CNAME at the root. Where that's the case, we offer two anycast A records instead.
What happens to SSL
Domainee issues a Let's Encrypt certificate on the first request to the hostname (on-demand TLS). Renewal is automatic. You don't write an ACME client. You don't schedule a renewal cron. You don't get paged at 2am.
What happens to monitoring
Each domain is re-checked every 5 minutes. Need an answer now? Call POST /v1/domains/{id}/check to force a check on demand.
Idempotency
Send an Idempotency-Key header on writes. Domainee honors it for 24 hours, so a retried signup job won't create the same domain twice.
What a good custom domains API should handle for you
Use this as a checklist when you evaluate any option, including ours.
- DNS verification and monitor states. Not "working / not working," but specific states. Domainee reports
unknown,dns_not_resolving,dns_incorrect,pending_ssl,active_ssl,ssl_failedandssl_expired. Each one tells you what to say to your customer. - Automatic SSL. Issued on first request, renewed without you.
- Apex and subdomain support. With a fallback when the DNS provider won't allow a root CNAME.
- CAA preflight. A CAA record can quietly block Let's Encrypt. Preflight warns you before the certificate fails.
- SSRF protection. Your customer supplies a hostname, and you supply the origin. The API rejects private, loopback, link-local and reserved origins, so nobody points a domain at your internal network.
- Webhooks. So you never poll.
- Customer-facing setup. Covered in the next section.
- Buying domains in-app. For users who don't own a domain yet.
Webhooks, specifically
Domainee sends these domain events:
| Event | When |
|---|---|
domain.created | A domain was added |
domain.verified | DNS checks out |
domain.failed | Setup failed |
domain.expired | The domain expired |
domain.monitor_updated | The monitor state changed |
domain.deleted | A domain was removed |
Purchase events (domain_purchase.*) exist as well. Every webhook carries an HMAC-SHA256 signature in the x-domainee-signature header, so verify it before you trust the payload. Delivery retries up to 6 attempts: immediately, then +1 min, +5 min, +30 min, +2 h and +12 h.
Getting your customers through DNS setup
The API call is the easy half. The hard half is a non-technical person editing DNS. Your customer shouldn't need a registrar account or DNS expertise to get there. Here's how Domainee shrinks that part.
- Provider-aware instructions.
GET /v1/domains/{id}/instructionsdetects the DNS provider from public NS records and returns provider-specific steps. No generic "log in to your registrar" wall of text. - One-click Domain Connect. Where supported, your customer approves the change in one click. Cloudflare is supported. GoDaddy is not available.
- Scoped API token. Cloudflare or DigitalOcean customers can hand over a scoped API token via
POST /v1/domains/{id}/dns/apply. We use the token once and never store it. - Embeddable widget. One script tag (
https://domainee.dev/widget.js, mounted withDomainee.mount) drops a setup flow into your app. It polls every 15 seconds and uses short-lived connect-session tokens. One honest limit: there's no theming API yet.
The goal: your customer pastes one record, or clicks once, and moves on.
Build vs buy: what "just add custom domains" actually costs
It starts as a weekend feature. Then you meet the real list:
- ACME rate limits
- Edge TLS termination
- SNI routing
- DNS health checks
- Certificate rotation
Our estimate: a v1 takes 2–4 months, and then the on-call rotation for certificate outages never leaves. We did the four months. We're still doing the ongoing care. You get the API.
When you should build it yourself
Buying isn't always worth it. Build if:
- You have a handful of tenants and one origin, and a few lines of proxy config already cover you.
- Your hosting platform already handles custom hostnames and certificates for you, and you're happy with its limits.
- Certificate and DNS infrastructure is the product you sell.
Buy if your users keep asking, your hostname count is heading toward the hundreds, and nobody on your team wants to own a certificate pager. For head-to-head breakdowns, including the Vercel Platforms Starter Kit build-vs-buy page, see how Domainee compares with other custom domain APIs.
What a custom domains API costs (published numbers)
Every price, every limit, on the pricing page. No contact-sales, no fair-use clauses. Here's the summary from our published pricing:
| Free | Scale (pay-as-you-go) | |
|---|---|---|
| Domains | Up to 20 | $0.20/domain/month after the first 20 |
| Bandwidth | 100 GB/month | $0.05/GB above 100 GB |
| Expires? | Never | n/a |
| Volume discounts | n/a | Start at 1,001 domains, graduating down to $0.10 at 10,001+ domains |
A card on file is required before your first domain. On the free tier it's charged $0. Billing runs through Stripe with proration. Domains and bandwidth show up as two line items on one monthly invoice.
Worked example: 120 domains
Say you run 120 customer domains and stay under 100 GB of bandwidth.
- First 20 domains: free.
- Remaining 100 domains × $0.20 = $20.00.
- Bandwidth within 100 GB: $0.
- Total: $20.00/month.
Now push traffic to 150 GB. That's 50 GB over, at $0.05/GB: $2.50. Bill: $22.50/month.
An enterprise or custom-contract option exists behind "Book a demo". That's the only thing not published. Self-serve pricing stays fully public.
Limits and conventions to know before you integrate
Published numbers only:
- Format: REST, JSON only, Bearer keys.
- Default rate limit: 60 requests/min per key.
POST /v1/domains: 100/hour.- Bulk create (
POST /v1/domains/bulk): 5/hour, 100 domains each. - DNS checks: 600/hour.
- Errors:
{error, message, details}. 402 billing_required: returned when no card is on file, even for the first domain. Add the card first, or your first call will tell you.
Migrating existing customer hostnames? Bulk create is for you: 100 domains per call, so 500 per hour at the limit. The rest is in the quickstart: connect your first domain in the quickstart.
Driving a custom domains API from AI tools
Domainee runs a hosted MCP server at https://mcp.domainee.dev/mcp. It uses HTTP transport only (no stdio). It works with Claude Desktop, Cursor, Claude Code, Windsurf, Continue and Cline.
That means you can ask your editor to work with your domains without leaving the chat. The source is on GitHub: CommonNinja/domainee-mcp-server.
FAQ
What is a custom domains API?
It's an API your SaaS calls so its users can connect their own domain to your product. The API handles DNS verification, SSL and monitoring. Domainee is one: a custom-domains-as-a-service API for SaaS products.
How do I let my SaaS customers use their own domain?
Call POST /v1/domains with the customer's hostname and your originUrl. Show your customer the CNAME that comes back. Once it resolves, SSL is issued and traffic routes to your origin.
How does a custom domains API handle SSL certificates?
Domainee issues a Let's Encrypt certificate on the first request to the hostname (on-demand TLS) and renews it automatically. A CAA preflight warns you if a record would block issuance.
Do customers need a registrar account or DNS expertise to connect a domain?
No. They add one CNAME, or use one-click Domain Connect where supported. GET /v1/domains/{id}/instructions returns provider-specific steps based on the customer's DNS provider.
Does a custom domains API support apex domains?
Domainee does. If an apex provider disallows a CNAME at the root, we offer two anycast A records instead. Subdomains work with a plain CNAME.
How long does it take to build custom domain support yourself?
Our estimate is 2–4 months for a v1, plus ongoing on-call for certificate outages. The work is ACME rate limits, edge TLS termination, SNI routing, DNS health checks and certificate rotation.
How much does a custom domains API cost?
With Domainee, the first 20 domains are free. After that it's $0.20/domain/month, with volume discounts starting at 1,001 domains and reaching $0.10 at 10,001+ domains. Bandwidth is $0.05/GB above 100 GB.
Is there a free custom domains API?
Yes. Domainee's free tier covers up to 20 domains and 100 GB/month and never expires. A card on file is required before the first domain, and it's charged $0 on the free tier.
How do I know when a customer's domain is verified or broken?
Two ways. Read monitorStatus (states like dns_incorrect, pending_ssl, active_ssl and ssl_failed), which updates on a 5-minute check cycle. Or subscribe to webhooks such as domain.verified, domain.failed and domain.monitor_updated.
Can I let users buy a domain inside my app?
Yes. The Buy a Domain API (POST /v1/domain-purchases) covers 500+ TLDs at wholesale price plus a $1 flat fee. The end user is the legal registrant.
Can I manage custom domains from Cursor or Claude Code?
Yes. Connect the hosted MCP server at https://mcp.domainee.dev/mcp over HTTP transport. Claude Desktop, Cursor, Claude Code, Windsurf, Continue and Cline all work with it.
Try it: first domain in an afternoon
Start free: 20 custom domains and 100 GB/month, no expiry. Make your first POST /v1/domains call from the quickstart, or sign up at domainee.dev.
Domainee isn't a weekend experiment. Common Ninja, Embeddable and Vidocu run on it in production. Other customers include SendRaven, Brackets and Trofeo.live. Not household names. Just teams that wanted custom domains to be the boring part of the roadmap.