On this page
Domains
Every site is allocated a docsary.com address when it is created, and that address is already serving. This endpoint is how you inspect it, and how you add a hostname of your own on top.
For the flow end to end — including primary versus staging hosts — see Domains.
All endpoints require an organization API key. :site accepts a slug or an id.
Kinds of domain
kind |
What it is | Who gets one |
|---|---|---|
saas |
The <name>.docsary.com address allocated when the site was created. Verified and serving from the moment it exists. |
Every plan, automatically |
custom |
A hostname you own. Needs a TXT ownership challenge and a CNAME. |
Every plan, up to the custom-domain ceiling |
route |
A hostname set up on your behalf. Attaches already verified. | Provisioned accounts only |
List domains
GET /v1/sites/:site/domains
curl -s -H "authorization: Bearer $DOCSARY_KEY" \
"$DOCSARY_API/v1/sites/acme/domains"
{
"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": "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."
}
},
{
"hostname": "staging.acme.com",
"is_primary": 0,
"kind": "custom",
"verified": false,
"verified_at": null,
"registered": false,
"verification": {
"type": "TXT",
"name": "_docsary.staging.acme.com",
"value": "docsary-verify=8f1c...",
"how": "Publish this TXT record, then POST to /v1/sites/<site>/domains/staging.acme.com/verify. The hostname is not served until it verifies."
},
"traffic": {
"type": "CNAME",
"name": "staging.acme.com",
"value": "ssl.docsary.com",
"how": "..."
}
}
]
}
| Field | Meaning |
|---|---|
kind |
saas, custom, or route — see the table above |
is_primary |
1 on the site's canonical host, 0 otherwise |
verified |
Whether the hostname is serving. Always true for saas |
verified_at |
Millisecond timestamp of verification, or null |
verification |
Present only while a custom hostname is unverified: the record to publish |
traffic |
Present on every custom hostname, verified or not: the CNAME to publish |
registered |
custom only. true once a certificate has been requested for the hostname |
This call is how you recover both records if you lost the attach response.
Attach a domain
POST /v1/sites/:site/domains
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}'
| Field | Type | Required | Notes |
|---|---|---|---|
hostname |
string | yes | Lowercased and trimmed. Must be a dotted hostname with a suffix of two or more letters. May not end in docsary.com. |
primary |
boolean | no | Marks this the site's canonical host and clears the flag from its other domains. |
{
"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."
}
}
201 on success. The attachment exists and is unverified; nothing is served on it, and no certificate is requested, until it verifies.
The verification token is generated per attachment. Detaching and re-attaching a hostname issues a new one, so publish the record from the response you are working with rather than one you saved earlier. The traffic record never changes.
Errors
| Response | Cause |
|---|---|
400 {"error":"invalid hostname"} |
Missing, malformed, or dotless hostname |
400 containing is not attachable |
The hostname ends in docsary.com. Those are allocated at site creation, not attached |
403 with "quota":"custom_domains" |
Your organization's custom-domain ceiling is already reached |
409 {"error":"hostname already attached","to_this_site":false} |
The hostname is attached to another site |
409 {"error":"hostname already attached","to_this_site":true} |
The hostname is already attached to this site |
404 {"error":"site not found"} |
The site slug or id does not resolve |
There is no plan gate on this endpoint. Attaching a hostname you own works on every plan; the only bound is a count:
{
"error": "quota exceeded: custom_domains limit is 3 on plan 'free'",
"quota": "custom_domains",
"limit": 3,
"plan": "free"
}
That ceiling exists because each attached hostname gets a certificate issued and renewed for it, which is real work done on your behalf — not because a larger number is for sale. It is counted across your whole organization rather than per site, and your docsary.com addresses never count against it. If three is not enough for a real project, ask.
Hostnames are unique across every site. to_this_site distinguishes a re-run from a genuine conflict.
Some accounts are provisioned so that a hostname is set up for you rather than challenged. Those attachments come back "kind": "route" and "verified": true, alongside a short setup report — one entry per step, each reading created, exists, failed, or skipped with a reason. Nothing is required of you when that report appears; it is there to be read, not acted on.
Verify a domain
POST /v1/sites/:site/domains/:hostname/verify
Publish the TXT record from the attach response, then call this. It resolves the record live on every call.
curl -s -X POST "$DOCSARY_API/v1/sites/acme/domains/docs.acme.com/verify" \
-H "authorization: Bearer $DOCSARY_KEY"
{
"hostname": "docs.acme.com",
"verified": true,
"traffic": {
"type": "CNAME",
"name": "docs.acme.com",
"value": "ssl.docsary.com",
"how": "..."
},
"certificate": { "status": "created" }
}
The hostname begins serving your site once this returns verified: true, and the traffic block is repeated here so the next thing to do is in front of you.
| Response | Meaning |
|---|---|
200 {"verified":true} |
Verified. The hostname serves as soon as its CNAME is live. |
200 {"verified":true,"already_verified":true} |
It was already verified. If no certificate had been requested yet, this call retries that. |
409 with expected and found |
The record was not found. found lists what did resolve at that name. |
409 {"error":"domain has no verification token; re-attach it"} |
The attachment predates its challenge — detach and attach again. |
502 {"error":"DNS lookup failed: ..."} |
The lookup itself failed. Retry. |
404 {"error":"domain not found"} |
That hostname is not attached to this site. |
A 409 is the ordinary answer to "the record has not propagated yet". Compare expected against found, wait out your provider's TTL, and call again — there is no cached failure to clear.
The certificate block
status |
Meaning |
|---|---|
created |
A certificate was requested for the hostname. It issues once the CNAME resolves to us. |
exists |
One had already been requested. Nothing to do. |
skipped |
That step could not run right now, with a reason. Call verify again later. |
failed |
The request was refused, with an error. Call verify again; if it persists, send us the text. |
A skipped or failed certificate does not undo verification. Ownership is proven, the attachment stands, verified is still true, and re-running verify retries only the certificate. This block is a progress report, not a failure mode.
Detach a domain
DELETE /v1/sites/:site/domains/:hostname
curl -s -X DELETE "$DOCSARY_API/v1/sites/acme/domains/docs.acme.com" \
-H "authorization: Bearer $DOCSARY_KEY"
{ "deleted": "docs.acme.com", "certificate": { "status": "deleted" } }
The hostname stops serving and its certificate is released. certificate reads deleted, absent (there was none to release), skipped, or failed with a reason.
Your DNS records are never touched — they are yours, and removing them is your call.
404 {"error":"domain not found"} if the hostname is not attached to this site.
Detaching your docsary.com address works the same way and frees that name for somebody else, so do it deliberately. Deleting the site detaches everything it had.
When changes take effect
Attaching, verifying, detaching, or changing the primary flag takes effect within about half a minute, with no deploy and nothing to purge. A brand-new custom hostname additionally waits on its certificate, usually a minute or two after its CNAME goes live.
A hostname that is unattached, or attached but unverified, gets a plain-text 404: docsary: no site bound to this host.