Custom domain
Covers 4 API operations in the hostnames category.
| Method | Path | Description |
|---|---|---|
| GET | /v1/orgs/{orgSlug}/projects/{projectName}/hostnames | List of domains attached to the project (runlot domain list) |
| POST | /v1/orgs/{orgSlug}/projects/{projectName}/hostnames | Connects a custom domain (runlot domain add) |
| DELETE | /v1/orgs/{orgSlug}/projects/{projectName}/hostnames/{host} | Disconnects a custom domain (runlot domain rm) |
| POST | /v1/orgs/{orgSlug}/projects/{projectName}/hostnames/{host}/verify | Verify a domain now (runlot domain verify) |
GET /v1/orgs/{orgSlug}/projects/{projectName}/hostnames
Returns the default hostname (kind: default) and custom domains (kind: custom)
together. Each custom domain record includes the DNS record you need to publish
(verify) and its current status. Requires viewer or higher.
operationId listHostnames
| Status code | Description | Response body |
|---|---|---|
| 200 | List | HostnameList |
| 403 | — | — |
| 404 | — | — |
POST /v1/orgs/{orgSlug}/projects/{projectName}/hostnames
The name is normalized to lowercase punycode before it is stored. Wildcards
and names under runlot's own domains (*.runlot.app, *.runlot.dev,
*.runlot.io, the app domain) are not accepted.
The record is created in pending_dns state and reserves that name from
that moment. No other project can use the same name while it is still being
verified. It is not routed until it is connected, so requests to that name
return 404 unknown_hostname in the meantime.
Sending the same name again from the same project returns the existing record
unchanged, so a verification token you have already published stays valid.
Requires member or higher. Recorded in the audit log as hostname.add.
operationId addHostname
Request body: application/json · object
| Status code | Description | Response body |
|---|---|---|
| 200 | A newly created record, or an existing one | Hostname |
| 400 | Not a valid name shape (bad_request), a wildcard, or under our domain | Error |
| 403 | — | — |
| 404 | — | — |
| 409 | Two refusals share this status. hostname_taken — the name already belongs to another project. hostname_limit — the project is already at its plan's ceiling on custom domains (Free 1, Pro 50 per project). details carries limit, count and plan, so a client can build its message from the numbers instead of parsing the text. Re-sending a name the project already owns is not refused this way — it still answers 200. | Error |
DELETE /v1/orgs/{orgSlug}/projects/{projectName}/hostnames/{host}
Removes the custom hostname and its managed record in the runlot DNS zone
together. Requests to that name stop reaching the project.
You cannot delete the default hostname (400). Requires member or higher.
Recorded in the audit log as hostname.delete.
operationId deleteHostname
| Status code | Description | Response body |
|---|---|---|
| 204 | Disconnected | — |
| 400 | This is the default hostname | Error |
| 403 | — | — |
| 404 | — | — |
POST /v1/orgs/{orgSlug}/projects/{projectName}/hostnames/{host}/verify
Runs the same verification the background job runs every minute, immediately.
Ownership passes if any one of three conditions holds: the name sits in a runlot-hosted
zone owned by the same org, the _runlot-verify.<host> TXT record matches, or the
CNAME of <host> points to the fallback origin.
A domain cannot become active without proof of ownership. If verification does
not pass, the status is unchanged and lastError describes what was observed. Requires
member or higher.
operationId verifyHostname
| Status code | Description | Response body |
|---|---|---|
| 200 | The hostname after verification | Hostname |
| 403 | — | — |
| 404 | — | — |