Skip to content
Coritan Docs

Add a custom domain with the Apps API

Serve an app on your own domain through the Apps API once you prove it is yours with a TXT record and point it at the app.

View as Markdown

Every app answers at its platform name. Add a custom domain, such as www.example.com, to serve the app on your own name as well. You prove the domain is yours with a TXT record, point it at the app with a CNAME record, and we issue its certificate.

In the dashboard, the same domains are on the Domains tab of the app's page under App Deployment (Add a domain and protection). This page covers the Apps API, which scripts written for Apps keep using. The hostname in a path is the domain's hostname, such as www.example.com.

When you create an app, we give it a platform name made of its name on the platform and the platform's app domain, such as web-shop.apps.example.net. It is verified from the start, it goes with the app, and you cannot remove it. The domain list gives it first, with kind platform. Names under the app domain are only given out this way, so you cannot add one as a custom domain. When the platform has no app domain, apps get no platform name and serve only their custom domains.

  1. Add the hostname with POST /api/v1/client/apps/{app_uuid}/domains, without https:// or a path. Wildcard names such as *.example.com are not accepted.

    Shell
    curl -X POST https://api.coritan.com/api/v1/client/apps/3c9e2f4a-8b1d-4f6e-a2c7-5d8b9e0f1a21/domains \
      -H "Authorization: Bearer $CORITAN_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"hostname": "www.example.com"}'
    

    It answers 201 with the domain, in the shape List domains shows, with verified false.

  2. Publish the TXT record in the domain's verification at your DNS host:

    DNS
    _coritan-app.www.example.com.  3600  IN  TXT    "8b7c1d0e2f3a4b5c6d7e8f9012345678"
    

    The name is _coritan-app. followed by your hostname, and the value is the token we gave the domain.

  3. Publish a CNAME record that points the hostname at the domain's cname_target, the app's platform name:

    DNS
    www.example.com.  3600  IN  CNAME  web-shop.apps.example.net.
    

    At the top of a zone, such as example.com, a CNAME is not allowed. Use your DNS host's ALIAS record or CNAME flattening to the same target.

  4. Ask us to check with POST /api/v1/client/apps/{app_uuid}/domains/{hostname}/verify:

    Shell
    curl -X POST https://api.coritan.com/api/v1/client/apps/3c9e2f4a-8b1d-4f6e-a2c7-5d8b9e0f1a21/domains/www.example.com/verify \
      -H "Authorization: Bearer $CORITAN_TOKEN"
    

    When we find the TXT record, it answers {"domain": {...}, "verified": true, "certificates": ["www.example.com"]}, where certificates names the hostnames whose certificate it ordered, and the domain starts serving the app. When we do not, it answers 200 with "verified": false and a message saying which record we looked for. Wait a few minutes for DNS to update, then check again.

The domain gets no route until it is verified, so nothing reaches the app on it before then. A domain that is already verified answers "verified": true with an empty certificates, and a check answers 409 with hostname_in_use when another product took the hostname meanwhile. You can remove the TXT record once the domain is verified.

A verified domain's certificate is ordered once the app has replicas serving it. Its certificate moves from none to pending to issued. The certificate authority checks the domain over HTTP, so the CNAME record from step 3 must be in place for the certificate to be issued.

A hostname can belong to one app at a time. Another app that is still verifying a hostname holds it for 72 hours after adding it. After that, the next app that adds the hostname takes it over. A hostname that another app has verified, or that another product on the platform serves, such as a web proxy, cannot be added.

GET /api/v1/client/apps/{app_uuid}/domains lists the platform name first, then the custom domains:

Shell
curl https://api.coritan.com/api/v1/client/apps/3c9e2f4a-8b1d-4f6e-a2c7-5d8b9e0f1a21/domains \
  -H "Authorization: Bearer $CORITAN_TOKEN"
JSON
{
  "domains": [
    {
      "hostname": "web-shop.apps.example.net",
      "kind": "platform",
      "verified": true,
      "verified_at": "2026-09-20T09:12:00Z",
      "created_at": "2026-09-20T09:12:00Z",
      "url": "https://web-shop.apps.example.net",
      "certificate": "issued",
      "verification": null,
      "cname_target": null
    },
    {
      "hostname": "www.example.com",
      "kind": "custom",
      "verified": false,
      "verified_at": null,
      "created_at": "2026-09-26T10:05:00Z",
      "url": null,
      "certificate": "none",
      "verification": {"type": "TXT", "name": "_coritan-app.www.example.com", "value": "8b7c1d0e2f3a4b5c6d7e8f9012345678"},
      "cname_target": "web-shop.apps.example.net"
    }
  ]
}

kind is platform or custom. url is null until the domain is verified. certificate is none, pending or issued. verification is the TXT record to publish, and null once the domain is verified. cname_target is where a custom domain points, and null for the platform name.

Removing a custom domain stops it reaching the app at once, and deletes its route and certificate. The records at your DNS host stay until you delete them.

DELETE /api/v1/client/apps/{app_uuid}/domains/{hostname} removes a custom domain and answers {"deleted": "www.example.com"}. The platform name answers 409 with {"error": "platform_domain", "message": "The platform name goes with the deployment and cannot be removed"}, and a hostname the app does not have answers 404 with Domain not found.

The domain is verified, and its certificate is issued once the certificate authority has checked it. Visitors reach the app at https://www.example.com, and the domain shows Verified on the app's Domains tab.

Status detail Cause
409 {"error": "domain_exists", "message": "That hostname is already added to this deployment"} The app has it already.
409 {"error": "hostname_in_use", "message": "That hostname is in use on the platform"} Another app has verified it or added it less than 72 hours ago, or another product serves it. If it is yours, remove it there first.
409 {"error": "domain_limit", "message": "A deployment can have at most 20 custom domains"} The app has 20 custom domains. Remove one it no longer needs.
422 {"message": "Give the hostname alone, without http:// or a path", "field": "hostname"} hostname starts with http:// or https://.
422 {"message": "'*.example.com' is not a hostname", "field": "hostname"} hostname is not a hostname.
422 {"message": "Names under apps.example.net are given to deployments by the platform", "field": "hostname"} The name is under the app domain. Each app gets its own name there when it is created.
429 Too many checks for this app. Wait a few minutes; DNS changes take a while anyway. The app asked for 30 checks in the last 10 minutes.
No TXT record at _coritan-app.www.example.com holds the token yet. DNS changes can take a few minutes to appear.
The message of a check that found no record. The record is not published yet, or holds another value. Check its name and value at your DNS host, wait a few minutes, then check again.
The certificate stays pending
The hostname does not point at the app yet. Check the CNAME record, or the ALIAS record at the top of a zone.

API operations on this page

MethodPathWhat it does
GET/api/v1/client/apps/{app_uuid}/domainsList an app's domains: its platform name first, then its custom domains
POST/api/v1/client/apps/{app_uuid}/domainsAdd a custom domain
DELETE/api/v1/client/apps/{app_uuid}/domains/{hostname}Remove a custom domain from an app
POST/api/v1/client/apps/{app_uuid}/domains/{hostname}/verifyLook for the domain's TXT record
GET/api/v1/orgs/{org_slug}/apps/{app_uuid}/domainsList an app's domains: its platform name first, then its custom domains
POST/api/v1/orgs/{org_slug}/apps/{app_uuid}/domainsAdd a custom domain
DELETE/api/v1/orgs/{org_slug}/apps/{app_uuid}/domains/{hostname}Remove a custom domain from an app
POST/api/v1/orgs/{org_slug}/apps/{app_uuid}/domains/{hostname}/verifyLook for the domain's TXT record