---
title: Domains
description: Every site gets a docsary.com address the moment it is created. Put it on your own hostname instead — attach, prove ownership with a TXT record, point a CNAME, done.
order: 4
---

# Domains

Every site is readable the moment it exists. Creating a site allocates it an address under `docsary.com`, and that address serves as soon as you push a page — nothing to configure, on every plan.

Your own hostname is the other option: `docs.acme.com` rather than a subdomain of somebody else's brand. That works on every plan, and it takes three short steps.

## The address you get automatically

When you create a site, the response tells you where it lives:

```bash
curl -s -X POST "$DOCSARY_API/v1/sites" \
  -H "authorization: Bearer $DOCSARY_KEY" \
  -H "content-type: application/json" \
  -d '{"slug":"acme","name":"Acme Docs"}'
```

```json
{ "id": "site_...", "slug": "acme", "subdomain": "acme.docsary.com" }
```

That hostname is live immediately and serves over HTTPS. Push a version to the site and it is a real docs site at `https://acme.docsary.com/`.

The name comes from your site slug. If somebody already holds that name you get `<your-org>-<your-site>.docsary.com` instead, so read `subdomain` from the response rather than assuming. A small set of names is reserved — `www`, `api`, `admin`, `mail`, `ssl` and similar — and a site slug matching one of those falls back the same way.

In the rare case where both names are taken, the site is still created, `subdomain` comes back `null`, and a `subdomain_note` says why. Attach your own hostname in that case, or create the site under a different slug.

Your `docsary.com` address keeps working after you attach your own domain, which makes it a free staging URL — see [primary and staging hosts](#primary-and-staging-hosts) below.

## Your own domain

Attaching a hostname you own works on every plan. The only bound is how many you may hold at once — three per organization, because each one gets a certificate issued and renewed for it. Your `docsary.com` addresses do not count against that. If you need more for a real project, [ask](/access#the-ceilings).

Three steps: attach, prove you own it, point it at us.

### 1. Attach

```bash
curl -s -X POST "$DOCSARY_API/v1/sites/acme/domains" \
  -H "authorization: Bearer $DOCSARY_KEY" \
  -H "content-type: application/json" \
  -d '{"hostname":"docs.acme.com","primary":true}'
```

```json
{
  "hostname": "docs.acme.com",
  "kind": "custom",
  "verified": false,
  "verification": {
    "type": "TXT",
    "name": "_docsary.docs.acme.com",
    "value": "docsary-verify=8f1c2d0a4b6e8f1c2d0a4b6e8f1c2d0a",
    "how": "Publish this TXT record, then POST to /v1/sites/<site>/domains/docs.acme.com/verify. The hostname is not served until it verifies."
  },
  "traffic": {
    "type": "CNAME",
    "name": "docs.acme.com",
    "value": "ssl.docsary.com",
    "how": "Point docs.acme.com at ssl.docsary.com with a CNAME once ownership is verified. The certificate is issued and renewed for you; there is nothing to install."
  }
}
```

You get both DNS records you will ever need, up front. `verification` proves the hostname is yours. `traffic` sends visitors to us. They are deliberately separate: publish the challenge today while the hostname still serves your old site, and cut the traffic over whenever you are ready.

The hostname is lowercased and trimmed, and must be a normal dotted hostname. A bare hostname without a dot is rejected with `400`. So is anything ending in `docsary.com` — those names are allocated, not attached.

Nothing is served yet. The attachment exists, unverified.

### 2. Prove you own it

Publish the `TXT` record exactly as given — name `_docsary.<your hostname>`, value `docsary-verify=<token>` — then call:

```bash
curl -s -X POST "$DOCSARY_API/v1/sites/acme/domains/docs.acme.com/verify" \
  -H "authorization: Bearer $DOCSARY_KEY"
```

```json
{
  "hostname": "docs.acme.com",
  "verified": true,
  "traffic": { "type": "CNAME", "name": "docs.acme.com", "value": "ssl.docsary.com", "how": "..." },
  "certificate": { "status": "created" }
}
```

Verification checks live DNS on every call, so nothing is cached against you. If the record has not propagated yet you get a `409` listing what actually resolved at that name:

```json
{
  "hostname": "docs.acme.com",
  "verified": false,
  "expected": { "name": "_docsary.docs.acme.com", "value": "docsary-verify=8f1c..." },
  "found": []
}
```

`found` is usually enough to spot the problem: a record published on the wrong name, a provider that appended your domain to it twice, or a value that lost its `docsary-verify=` prefix. Publish the record, wait out your provider's TTL, call again — there is no penalty for retrying.

Verification is permanent for that attachment. You may remove the `TXT` record afterwards, though leaving it costs nothing.

:::info
Verification exists because a hostname pointed at a docs platform is a claim, not a proof. Requiring it means nobody can attach `docs.yourcompany.com` to their own content, and it is the same check every serious platform makes.
:::

### 3. Point the traffic

Publish the `CNAME` from the `traffic` block:

```
docs.acme.com    CNAME    ssl.docsary.com
```

That is the whole cutover. **You never touch a certificate.** One is requested for your hostname when verification passes, issued once the `CNAME` is live, and renewed for as long as the domain stays attached. There is nothing to upload, nothing to rotate, and nothing that expires at 2am.

Your apex domain — `acme.com` with no subdomain — is a different animal: most DNS providers cannot put a `CNAME` there. Use a subdomain like `docs.acme.com`, or a provider that supports `ALIAS`/`ANAME` flattening at the apex.

### What the certificate block is telling you

The verify response carries a `certificate` block reading `created`, `exists`, `skipped`, or `failed` with a reason. A `skipped` or `failed` does **not** undo your verification: ownership is proven either way, the attachment stands, and calling verify again retries only the certificate. If it stays `failed`, send us the reason text.

## Primary and staging hosts

A site can have several hostnames. One is primary. That flag drives three behaviours:

| Behaviour | Primary host | Non-primary host |
| --- | --- | --- |
| `robots.txt` | `Allow: /`, plus a sitemap reference and a `Content-Signal: search=yes, ai-input=yes` line | `Disallow: /` |
| Page `<head>` | indexable | `<meta name="robots" content="noindex">` |
| Canonical URLs | point at this host | rewritten to point at the primary host |

Your allocated `docsary.com` address starts out primary, because at first it is the site's only address. Attach your own hostname with `"primary": true` and the flag moves: the subdomain keeps serving, stays out of every index, and points its canonical links at production. That is exactly what a staging host should do, and you get it without asking.

Setting `"primary": true` clears the flag from the site's other domains, so there is always at most one.

## Listing

```bash
curl -s -H "authorization: Bearer $DOCSARY_KEY" \
  "$DOCSARY_API/v1/sites/acme/domains"
```

```json
{
  "domains": [
    {
      "hostname": "acme.docsary.com",
      "is_primary": 0,
      "kind": "saas",
      "verified": true,
      "verified_at": 1756300000000
    },
    {
      "hostname": "docs.acme.com",
      "is_primary": 1,
      "kind": "custom",
      "verified": true,
      "verified_at": 1756300000000,
      "registered": true,
      "traffic": { "type": "CNAME", "name": "docs.acme.com", "value": "ssl.docsary.com", "how": "..." }
    }
  ]
}
```

`kind` is `saas` for the address we allocated and `custom` for a hostname you own. A hostname still waiting on its challenge comes back `"verified": false` with its `verification` block, so this call is also how you recover the records to publish if you lost the attach response.

## Detaching

```bash
curl -s -X DELETE "$DOCSARY_API/v1/sites/acme/domains/docs.acme.com" \
  -H "authorization: Bearer $DOCSARY_KEY"
```

```json
{ "deleted": "docs.acme.com", "certificate": { "status": "deleted" } }
```

Detaching stops the hostname serving and releases its certificate. Your DNS records are yours and are not touched — remove them on your own schedule, since those names may be doing other work for you.

Deleting a site detaches everything it had, the `docsary.com` address included, and that name becomes available again.

A hostname that is not attached to any site is answered with a plain `404` reading `docsary: no site bound to this host`. So is one that is attached but not yet verified.

## When changes take effect

Attaching, detaching, verifying, or changing which host is primary takes effect within about half a minute. There is no deploy to run and nothing to purge.

A brand-new custom hostname additionally waits on its certificate, which is usually a minute or two after the `CNAME` goes live and is entirely automatic.

Page content is separate and has no delay at all: a push is visible immediately — see [publishing](/api/publish).
