# Domains And Slugs

> Give an app a readable apps.userland.fun slug or the customer's own domain.

- Canonical page: https://docs.userland.fun/guides/domains-and-slugs/
- Docs index for agents: https://docs.userland.fun/llms.txt

> **For agents:** Slugs and custom domains are aliases for the canonical `https://<app_id>.apps.userland.fun/` origin. Add them with `userland apps slugs add` or `userland apps domains add`, show the customer the returned `dns_instructions`, then run `userland apps domains verify` until the route is `active`. Both are paid features.

## Slugs

A slug gives an app a readable address under `apps.userland.fun`:

```bash
userland apps slugs add "$APP_ID" pricing-demo
userland apps slugs list "$APP_ID"
userland apps slugs remove "$APP_ID" pricing-demo
```

The app then also serves at `https://pricing-demo.apps.userland.fun/`. Slugs are 1-63 lowercase letters, digits, or hyphens, cannot start or end with a hyphen, cannot look like an app id, and cannot use reserved names such as `www`, `api`, `docs`, `admin`, or `userland`. A slug is active as soon as it is created.

## Custom domains

```bash
userland apps domains add "$APP_ID" portal.example.com
userland apps domains verify "$APP_ID" portal.example.com
userland apps domains list "$APP_ID"
userland apps domains remove "$APP_ID" portal.example.com
```

A new custom domain starts as `pending_dns`. The API response includes `dns_instructions`:

- `traffic`: the record that sends traffic to Userland. For a subdomain such as `portal.example.com`, this is `CNAME portal.example.com customers.userland.fun`.
- `ownership_txt`: a TXT record that proves the customer controls the domain, when one is required.
- `provider_validation_records`: certificate validation records, when the certificate provider asks for them.

For an apex domain such as `example.com`, most DNS providers do not allow a plain `CNAME`. Use the provider's apex `CNAME` flattening, `ALIAS`, or `ANAME` record pointing at `customers.userland.fun`, as described in the `traffic` note.

After the customer adds the records, run `userland apps domains verify` (or `POST /v0/apps/:app_id/domains/:hostname/verify`). The route moves through `pending_certificate` to `active` once DNS and the certificate check out. DNS changes can take minutes to hours; verify again later if the route is still pending. To email the setup instructions to yourself, call `POST /v0/apps/:app_id/domains/:hostname/email-reminder`.

## Plans

| Plan | Slugs | Custom domains |
| --- | --- | --- |
| Free | Not included | Not included |
| Starter | 1 | 1 |
| Business | 5 | 5 |
| Business Plus | 20 | 20 |

Adding a route beyond the plan returns `402 entitlement_required` (the feature is not included) or `402 plan_limit_exceeded` (the plan's count is used up). See [Limits](/reference/limits/).

## Route states

`userland apps routes list` prints every slug and domain with its status:

- `active`: serving.
- `pending_dns` or `pending_certificate`: waiting for DNS or the certificate.
- `disabled_billing`, `disabled_downgrade`, or `disabled_abuse`: turned off by a billing problem, a plan downgrade, or an abuse review. Routes disabled by billing come back when billing recovers.

A disabled or deleted alias returns `route_disabled`. The canonical `https://<app_id>.apps.userland.fun/` origin keeps serving unless the app or account itself is suspended. Removing a route never deletes app data.
