Custom domains

Attach, list and detach your own domains, so your app answers on them as well as on its default subdomain.

Docs menu

Your app is reachable at <slug>.substrio.com and at every domain you attach with your app key, one call at a time.

Attaching a domain

curl -X POST "$SUBSTRIO_URL/v1/_tenant/domains" \
  -H "X-Substrio-Tenant: my-app" -H "Authorization: Bearer $SUBSTRIO_KEY" \
  -H "Content-Type: application/json" \
  -d '{"domain": "mail.example.com"}'

The domain attaches at once: 200 {"domain", "status": "attached"}, and it routes to your app from that moment. There is no record to publish and no DNS lookup. Point the domain's DNS at your app (a CNAME to my-app.substrio.com, or through a proxy such as Cloudflare) and it serves.

Attaching or detaching also works through the MCP tools substrio_tenant_domain_attach and substrio_tenant_domain_detach.

The certificate is requested the moment the domain attaches: an exact name over HTTP-01, a *. domain over DNS-01. If the domain's DNS does not point at your app yet, the check fails and the request is made again after 1 hour, then 2, 4 and so on up to every 24 hours, and at each 12-hour recheck; the first one after the DNS points here issues it.

Example, with the app's own key:

curl -X POST "$SUBSTRIO_URL/v1/_tenant/domains" \
  -H "X-Substrio-Tenant: shop" -H "Authorization: Bearer $SUBSTRIO_KEY" \
  -H "Content-Type: application/json" \
  -d '{"domain": "shop.example"}'
# {"domain": "shop.example", "status": "attached"}

With shop.example pointing at your app, https://shop.example/ is the app.

Status Meaning
200 Attached (or already this app's)
400 Not a hostname
403 A Substrio domain (substrio.com or a name under it), or the app already holds as many domains as it may (20 by default)
409 Another app holds it

The first app to attach a domain holds it. A second app asking for the same name is refused with 409; the domain never moves between apps this way.

Listing and detaching

curl "$SUBSTRIO_URL/v1/_tenant/domains" \
  -H "X-Substrio-Tenant: my-app" -H "Authorization: Bearer $SUBSTRIO_KEY"
# {"domains": [{"domain": "mail.example.com", "status": "attached"}]}

curl -X DELETE "$SUBSTRIO_URL/v1/_tenant/domains/mail.example.com" \
  -H "X-Substrio-Tenant: my-app" -H "Authorization: Bearer $SUBSTRIO_KEY"
# 204, or 404 when the app does not hold it

Certificates in place

An issued or renewed certificate is served from the next handshake on. The swap never waits for handshakes already running: they finish on the certificates they started with, which are freed once no handshake can still read them.

CLI

substrio domains add mail.example.com      # attached at once
substrio domains list
substrio domains remove mail.example.com