Custom domains for SaaS

Let your customers bring their own domain

Give every workspace in your SaaS its own hostname. One API call returns the DNS records your customer adds; we handle verification, HTTPS and routing each request to the right workspace.

Read the quickstart: about fifteen minutes from sign-up to a customer's hostname on HTTPS, once its DNS records are in place.

1Your backend registers the customer's hostname
POST /v1/domains HTTP/1.1
Host: edge.customdomainapi.com
Authorization: Bearer cd_…
Idempotency-Key: signup-ws_8f3a1c
Content-Type: application/json

{"hostname": "forms.acme.com",
 "reference": "ws_8f3a1c"}
2The response: the two records your customer adds
HTTP/1.1 201 Created
Content-Type: application/json

{
  "id": "6f1c2d3e-4b5a-4c6d-8e9f-0a1b2c3d4e5f",
  "hostname": "forms.acme.com",
  "reference": "ws_8f3a1c",
  "status": "pending_dns",
  "dns_records": [
    {"type": "TXT",
     "name": "_custom-domain-challenge.forms.acme.com",
     "value": "custom-domain-verify=…",
     "purpose": "ownership"},
    {"type": "CNAME",
     "name": "forms.acme.com",
     "value": "edge.customdomainapi.com",
     "purpose": "routing"}
  ],
  "checks": [ … four checks, all "pending" ]
}
3Every request your origin then receives for it
GET /responses HTTP/1.1
Host: forms.acme.com
X-Forwarded-Proto: https
X-Custom-Domain-Assertion: v1.app_….eyJhcHAi….Lq3x…

# the payload, once your origin has verified it
{"app": "…", "dom": "6f1c2d3e-…",
 "ref": "ws_8f3a1c", "host": "forms.acme.com",
 "iat": 1791122400, "exp": 1791122460}

The workspace reference you register comes back, signed, on every request. Field by field: API reference, Verifying requests.

How it works

Four checks, then HTTPS

Ownership, routing, certificate and origin are checked continuously. A hostname goes live only when all four pass, and stops the moment one fails. Certificates come from Let's Encrypt on demand, only for verified hostnames, and renew without you noticing.

One registration, forms.acme.com for workspace ws_8f3a1c: from the API call to ready, then a changed CNAME five days later, and its fix.
WhenWhat happensownershiproutingcertificateoriginDomain
4 Oct 14:00Your backend calls POST /v1/domains and shows your customer the two records.PendingPendingPendingPendingWaiting for DNSpending_dns
14:01First check. The customer hasn't added the records yet; retried in 2 minutes, then 5.Failingtxt_record_not_foundFailingcname_not_foundPendingPendingWaiting for DNSpending_dns
14:08The TXT and CNAME are found. The edge obtains a certificate from Let's Encrypt.PassingPassingPendingPendingProvisioningprovisioning
14:08Through the edge, your origin answers /.well-known/custom-domain-workspace with the workspace from the assertion.PassingPassingPassingPassingReadyreadyServed over HTTPS. domain.ready sent.
9 Oct 09:12The customer changes the CNAME to another host. Serving stops at once.PassingFailingcname_target_mismatchPassingPassingNeeds attentionattention_requireddomain.attention_required sent.
09:40The customer points the CNAME back at the edge, and your backend asks for a re-check with POST /v1/domains/{id}/checks. Serving resumes.PassingPassingPassingPassingReadyreadydomain.recovered sent.

Failing checks are retried after 1, 2, 5, 15 and 30 minutes, then hourly; passing ones every 6 hours. After your customer fixes a record, ask for an early re-check with POST /v1/domains/{id}/checks. A failing check carries a stable error_code and a message in plain words to show your customer.

Signed webhooks tell you when a domain is ready, needs attention, recovers or is deleted, with retries and replay. Every status and check, and the webhooks.

The integration rule

Select the workspace from the assertion, never from Host

In multi-tenant SaaS, one wrong route means one customer seeing another's data. A hostname alone doesn't prove which workspace may be served, so the edge says so in a signature your backend checks.

What your origin receives with a request for forms.acme.com.
HeaderSet bySelects the workspace
HostThe edge, to the customer's hostnameNo: anyone can ask for any hostname
X-Forwarded-HostThe edge, replacing any value the visitor sentNo: for absolute URLs and redirects
X-Custom-Domain-AssertionThe edge, signed with your application's key, valid for 60 seconds. Copies sent by visitors are removed.Yes, once verified: ref is the workspace
With the Python SDK, in FastAPI or Starlette
app.add_middleware(
    CustomDomainMiddleware,
    keys={"app_…": os.environ["CUSTOM_DOMAIN_ASSERTION_SECRET"]},
    application_id=os.environ["CUSTOM_DOMAIN_APPLICATION_ID"],
    workspace_lookup=load_workspace,   # reference -> workspace, or None
)

@app.get("/")
def home(request):
    workspace = load_workspace(request.state.custom_domain.reference)

Not Python? Node.js, and the algorithm for any language: HMAC-SHA256, seven steps.

AI assistants

Manage your domains from Claude, Cursor or any MCP client

The MCP server gives an assistant the v1 API as tools, so you can ask it to register a customer's hostname, explain the records to add, or find out why a domain isn't live yet. It acts as one application, with that application's API key.

Set it up for your client

Add it to Claude Code; other clients run the same uvx command
claude mcp add custom-domain \
  --env CUSTOM_DOMAIN_API_URL=https://edge.customdomainapi.com \
  --env CUSTOM_DOMAIN_API_KEY=cd_... -- uvx custom-domain-mcp
Tools
Seven: register a hostname, get or list domains, write the DNS instructions for your customer, recheck, delete, and list webhooks
Access
Your application's API key only, never an operator token: it can do what your backend can
Left out
Creating or rotating webhooks, because their signing secret would end up in the conversation
Published
On PyPI as custom-domain-mcp, and on the official MCP Registry as io.github.sireto/custom-domain

Hosted or self-hosted

The same open-source service, wherever it runs

Hosted, we run the edge, its certificates and its upgrades, and you manage it in the portal. Self-hosted, it is free and open source under Apache 2.0, on your own server or cloud. Your integration (the API, the SDK and the middleware) doesn't change between them, and with your own edge hostname moving is repointing that one name.

Each option below creates one server with fixed addresses, installs the latest release, and ends with the operator portal open at your edge's own name. Your cloud provider bills you directly.

Or any Ubuntu or Debian server, with one install script: Self-hosting.

Everywhere: the v1 REST API with its OpenAPI document, the Python SDK with ASGI middleware, an MCP server for AI assistants, and signed webhooks. Self-hosted, the operator portal and the custom-domain command manage the rest.

Pricing

Priced by customer domains and bandwidth

Each plan includes a number of domains and a monthly bandwidth allowance, and the table says what happens above them: Free is never billed, paid plans are. Prices in US dollars, excluding VAT; yearly billing gives two months free.

A domain is a customer hostname you have registered and not deleted, including those still waiting for their DNS records.
Free25 customer domains on our shared edge in the EUStarter500 customer domains on your own edge in the EUGrowth5,000 customer domains on your own edge in the EU, backed up dailyScale25,000 customer domains on your own edge, in the EU or the USA
Price$0 / monthNo card needed$29 / monthor $290 a year, two months free$119 / monthor $1,190 a year, two months free$349 / monthor $3,490 a year, two months free
Customer domains included255005,00025,000
EdgeShared edgeDedicated edgeDedicated edgeDedicated edge
Domains above the allowanceUpgrade for more$0.10 a month each, up to 2,000$0.05 a month each, up to 20,000More? Talk to us
Bandwidth included100 GB a month1 TB a month10 TB a month20 TB a month
Bandwidth above the allowanceNot billed: slowed to 60 requests a minute until the month ends$0.05 per GB$0.05 per GB$0.05 per GB
Customers point their CNAME atedge.customdomainapi.comYour own edge hostnameYour own edge hostnameYour own edge hostname
Where the edge runsThe EUFalkenstein or Helsinki (EU)Falkenstein or Helsinki (EU)Falkenstein or Helsinki (EU), or Ashburn (USA)
Fixed addressesNot includedFixed IPv4 and IPv6Fixed IPv4 and IPv6Fixed IPv4 and IPv6
Upgrades and monitoringShared edgeManaged by usManaged by usManaged by us
Backups of the edge's databaseNot includedDownload your own from the portalDaily, kept 30 daysDaily, kept 30 days
Proxied requestsUp to 600 a minute and 100 a secondNo limit of oursNo limit of oursNo limit of ours
SupportCommunity support on GitHubEmail supportEmail supportEmail support
Choose a planStart freeOrder StarterOrder GrowthOrder Scale
  • Free

    $0 / monthNo card needed

    25 customer domains on our shared edge in the EU

    Customer domains included
    25
    Domains above the allowance
    Upgrade for more
    Bandwidth included
    100 GB a month
    Bandwidth above the allowance
    Not billed: slowed to 60 requests a minute until the month ends
    Where the edge runs
    The EU
    Everything in Free
    Edge
    Shared edge
    Customers point their CNAME at
    edge.customdomainapi.com
    Fixed addresses
    Not included
    Upgrades and monitoring
    Shared edge
    Backups of the edge's database
    Not included
    Proxied requests
    Up to 600 a minute and 100 a second
    Support
    Community support on GitHub
    Start free
  • Starter

    $29 / monthor $290 a year, two months free

    500 customer domains on your own edge in the EU

    Customer domains included
    500
    Domains above the allowance
    $0.10 a month each, up to 2,000
    Bandwidth included
    1 TB a month
    Bandwidth above the allowance
    $0.05 per GB
    Where the edge runs
    Falkenstein or Helsinki (EU)
    Everything in Starter
    Edge
    Dedicated edge
    Customers point their CNAME at
    Your own edge hostname
    Fixed addresses
    Fixed IPv4 and IPv6
    Upgrades and monitoring
    Managed by us
    Backups of the edge's database
    Download your own from the portal
    Proxied requests
    No limit of ours
    Support
    Email support
    Order Starter
  • Growth

    $119 / monthor $1,190 a year, two months free

    5,000 customer domains on your own edge in the EU, backed up daily

    Customer domains included
    5,000
    Domains above the allowance
    $0.05 a month each, up to 20,000
    Bandwidth included
    10 TB a month
    Bandwidth above the allowance
    $0.05 per GB
    Where the edge runs
    Falkenstein or Helsinki (EU)
    Everything in Growth
    Edge
    Dedicated edge
    Customers point their CNAME at
    Your own edge hostname
    Fixed addresses
    Fixed IPv4 and IPv6
    Upgrades and monitoring
    Managed by us
    Backups of the edge's database
    Daily, kept 30 days
    Proxied requests
    No limit of ours
    Support
    Email support
    Order Growth
  • Scale

    $349 / monthor $3,490 a year, two months free

    25,000 customer domains on your own edge, in the EU or the USA

    Customer domains included
    25,000
    Domains above the allowance
    More? Talk to us
    Bandwidth included
    20 TB a month
    Bandwidth above the allowance
    $0.05 per GB
    Where the edge runs
    Falkenstein or Helsinki (EU), or Ashburn (USA)
    Everything in Scale
    Edge
    Dedicated edge
    Customers point their CNAME at
    Your own edge hostname
    Fixed addresses
    Fixed IPv4 and IPv6
    Upgrades and monitoring
    Managed by us
    Backups of the edge's database
    Daily, kept 30 days
    Proxied requests
    No limit of ours
    Support
    Email support
    Order Scale

A domain is a customer hostname you have registered and not deleted, including those still waiting for their DNS records.

Ordering a dedicated edge: sign in, choose the plan, monthly or yearly billing, the location and your edge's hostname, and pay with Stripe. We set up the server; once your edge hostname points at its fixed addresses, it is ready within minutes. Cancel any time: the edge runs to the end of the period you paid for, then keeps serving for 14 days while you download a backup and move your customers' hostnames.

Second edge Coming soon
A second edge on any paid plan, for failover or a second region. Tell us if you need it.
Enterprise
Managed in your own cloud account, several regions, an SLA. Talk to us.

Bandwidth is the response bodies the edge sends to visitors, counted per UTC day; 1 GB is 1,000,000,000 bytes and 1 TB is 1,000 GB. On a paid edge it is shared by all its applications. On yearly billing, extra domains and bandwidth are billed monthly. Hosted plans are billed by Sireto B.V.; prices exclude VAT where it applies. Existing domains are never switched off when you reach your limit.

FAQ

Questions about custom domains for SaaS

Not answered here? Email info@sireto.com, or open an issue on GitHub.

How do I let my SaaS customers use their own domain?

Register the customer's hostname with one API call (POST /v1/domains) and show them the two DNS records it returns: a TXT record that proves they own it and a CNAME to the edge. The edge verifies both, issues the HTTPS certificate and forwards every request to your app with a signed assertion naming the workspace. The quickstart takes about fifteen minutes.

What is an edge?

The server your customers' hostnames point at. It holds their certificates, terminates HTTPS and forwards each request to your app with a signed assertion of the workspace it belongs to.

How does my app know which workspace a request is for?

Every forwarded request carries an X-Custom-Domain-Assertion header, signed with your application's key, naming your application, the domain and the workspace. Your backend verifies it and selects the workspace from it, never from the Host header. See verifying requests.

Which hostnames are supported?

Exact customer subdomains, such as forms.acme.com. Apex domains (acme.com) and wildcards are not supported yet.

Does my backend have to be in Python?

No. Any language can use the REST API and verify the assertion: the API reference and verification include Node.js examples and the exact algorithm. The Python SDK and middleware make it a few lines in FastAPI or Starlette.

Can an AI coding agent do the integration?

Yes. Every docs page is also plain Markdown (add .md to its address), /llms.txt lists them, and For AI coding agents is a complete brief with the contracts, the invariants and a checklist to hand to your assistant. The MCP server (uvx custom-domain-mcp) lets the assistant register, inspect and recheck your domains with your application's API key.

What is the difference between Free and the paid plans?

Free runs your application on an edge shared with others, under edge.customdomainapi.com, for up to 25 domains, with up to 600 proxied requests a minute and 100 a second across your hostnames, and one API key at 60 requests a minute, and 100 GB of bandwidth a month. Every paid plan gives you a server of your own, under your own edge hostname, with more domains, more bandwidth (1 TB, 10 TB or 20 TB a month) and no request limit of ours.

Where do the edges run?

On Hetzner Cloud. A paid edge runs in the location you choose when you order it: Falkenstein (Germany) or Helsinki (Finland) on every paid plan, or Ashburn (Virginia, USA) on the Scale plan only. The shared Free edge runs in the European Union. Self-hosted, it runs wherever you deploy it.

What counts as a domain, and what happens at the limit?

Every customer hostname you have registered and not deleted, including those still waiting for their DNS records. Deleted ones don't count. You are warned as you approach the allowance; on Starter each extra domain costs $0.10 a month and on Growth $0.05, and on Free new ones wait until you upgrade. Domains that already work are never switched off.

How is bandwidth counted?

As the response bodies the edge sends to visitors; request bodies and headers don't count, and 1 GB is 1,000,000,000 bytes. On a paid edge, all its applications share the plan's allowance, and what is above it is billed at $0.05 per whole GB. How days, billing periods and yearly plans are counted: Bandwidth in the API reference.

What happens when a Free application uses more than 100 GB in a month?

We email your account at 80% and at 100% of the allowance, with a link to order a dedicated edge. Above 100 GB in a calendar month (UTC), your application's proxied requests are limited to 60 a minute and 5 a second, instead of 600 and 100, until the month ends; requests over the limit get 429 with Retry-After. Nothing is billed, deleted or switched off, and the normal limits come back on the first of the next month (UTC).

Can I move between hosted and self-hosted?

It is the same open-source service everywhere, so your integration (the API, the SDK and the middleware) does not change. Your customers' CNAME records name the edge they point at: with your own edge hostname (a paid plan or self-hosted) moving is repointing that one name, while leaving the shared Free edge means they update their CNAME.

Get started

Give your customers their own domain

Start on Free in minutes, without a card, or order a dedicated edge of your own in the portal, from $29 a month. Self-hosting is available today too.