Docsary
Markdown Ask Claude Ask ChatGPT
On this page

Conventions and errors

Base URL

The API lives at:

https://api.docsary.com/v1

On a docs hostname, /v1 is not the API: that path belongs to the docs site, which is why v1 is a reserved page path.

Authentication

Every endpoint except /__health and the endpoint index takes a bearer token:

Authorization: Bearer dsy_XXXX

Organization API keys begin with dsy_ followed by 64 hexadecimal characters. Each key accesses only its own organization.

Keys are provisioned for you; see Pricing and access.

Scopes. Read-only keys can make GET requests, file reports, and revoke themselves. Other mutations require write access and return 403 with a read-only key:

{ "error": "this API key is read-only (scopes: 'read'); a write-capable scope is required" }

Use read-only keys for inspection tools such as linters or status checks.

Handling. Save keys securely when issued; lost keys cannot be recovered. A write key can change content across your organization. Use a separate named key per tool and keep keys out of source control.

Use GET /v1/orgs/:org/keys to list keys and DELETE /v1/orgs/:org/keys/:id to revoke one. A revoked key returns 401 on its next request. GET /v1/whoami identifies the calling key, scopes, and effective plan.

Identifiers

Every record has a prefixed identifier that says what it is:

Prefix Record
org_ organization
key_ API key
site_ site
ver_ version
pg_ page
ast_ asset
dom_ domain
rd_ redirect
rep_ report

:site and :ver accept either slugs or IDs. IDs continue to identify the same record after a rename.

Pages are addressed by path, not by id.

Requests

Bodies are JSON with content-type: application/json, with one exception: asset uploads send the file as a raw body and use the content-type header to declare the file's own type.

PATCH bodies are sparse — send only the fields you are changing. One exception matters: settings on a site is a whole-object replace, not a merge. Read the current object, modify it, and send it back complete.

Unknown fields in a request body are ignored.

Responses

Success responses are JSON objects. There is no envelope: a list endpoint returns {"sites": [...]}, not {"data": {...}}.

Errors include an error message:

{ "error": "site not found" }

Some errors carry extra fields alongside error: attaching an already-attached hostname adds to_this_site, and a limit refusal adds quota, limit, and plan.

Status codes

Code Meaning
200 Success
201 Created — a new site, version, page, asset, or domain
400 Malformed request: invalid slug, invalid path, unsafe URL or colour, unknown query parameter value, malformed percent-encoding, missing required field
401 Missing or invalid bearer token
403 Read-only key on a write, or a ceiling reached
404 No such site, version, page, asset, or domain
409 Conflict: slug already exists, version slug would shadow existing page URLs, hostname already attached, domain not yet verified
413 Asset over the 20 MB per-file cap, over your organization's storage ceiling, or an import request over the per-request cap
429 A rate limit: too many requests from your address in a short burst, or the hourly report filing limit
502 Domain verification, asset storage, or an enabled billing provider request failed
503 A required service is unavailable, or self-service billing is not enabled

A 404 on a nested route can mean the parent is missing. /v1/sites/acme/versions/1.0/pages returns {"error":"site not found"} when the site is wrong and {"error":"version not found"} when the site is right and the version is not. The message distinguishes them.

Limits

Your plan sets limits for sites, versions, pages, redirects, custom domains, and asset storage. See Pricing and access. Individual allowances may differ; use the limit returned by the API.

Quota errors include quota, limit, and plan. A feature excluded from the plan also returns limit: 0 and required_plan. Custom domains require Pro; allocated docsary.com addresses do not count toward the custom-domain limit.

Most quota refusals return 403; storage refusals return 413. An import can partly succeed: if it reaches the page limit, earlier writes remain live and are listed in the response’s diff.

Rate limits

Request Ceiling Counted per
/v1/* API requests 100 per 10 seconds Calling address
Reports filed 20 per hour Organization

A 429 refuses that request without writing it. Wait before retrying; earlier requests in a multi-request operation may already have succeeded. Send import batches sequentially and avoid rapid retry loops.

Ordinary reader pages are not subject to these API limits. The public MCP server has a separate limit of 100 requests per 10 seconds per client address and hostname.

Request size

Send about six files per import request. Keep chunks small. Chunking is safe: import is additive, so any number of chunks may be posted before a final prune call establishes the complete page set.

One import request may carry at most 100 files and 2,097,152 characters of Markdown. Over either, the call is refused with 413 and nothing is written.

Idempotency

Identical Markdown returns unchanged. To recover from a failed or partial push, fix the error and re-push the complete folder. Check all results before pruning.

Publishing

Writes affect live content without a separate publish call. Imports are incremental: readers may see mixed old and new pages during a push, and failures do not roll back earlier writes. Cached responses can take time to refresh.

Check the served content after publishing. The x-docsary-epoch and x-docsary-cache headers help diagnose caching, but do not prove that every page in a batch succeeded. See Publishing.