---
title: "Get a site"
method: GET
path: "/api/v1/sites/{slug}"
tags: ["Sites"]
---

# Get a site

`GET /api/v1/sites/{slug}`

## Request

- Base URL: `https://api.dotsy.ai`
- URL: `https://api.dotsy.ai/api/v1/sites/{slug}`
- Auth: one of:
  - HTTP bearer
  - HTTP bearer

One site in full: settings, stats, a window of its pages, recent activity and, while an import is running, build progress. `pages` is a window: it holds up to `pagesLimit` HTML pages (500 by default); follow `nextPagesCursor` for the rest, or use `GET /api/v1/sites/{slug}/pages` for a paged list of every page. Add `brief=1` to include the head of the site brief.

The path accepts the site id (a UUID) as well as the slug. An old slug (after a rename) answers 301 for reads and 308 for writes, and a site id answers 307, both to the canonical slug path. Follow redirects.

## Path parameters

- `slug` string, required

## Query parameters

- `pagesLimit` integer: Max HTML pages returned (default 500). Use with pagesCursor on big clones.
- `pagesCursor` string: Key cursor from a prior response's nextPagesCursor.
- `pagesQ` string: Filter HTML pages whose content key contains this term (case-insensitive).
- `brief` '0' | '1': When 1, include parsed `_intent/site.md` head in `brief` (~1 KB).

## Response `200`

The site.

- Site
  - `id` string, required: Stable site id (UUID). Unlike the slug, it never changes.
  - `slug` string, required
  - `title` string, nullable, required
  - `keyConvention` 'flat' | 'directory', required
  - `backend` 'kv' | 'do-sqlite', required
  - `status` 'published' | 'draft', required
  - `editingMode` 'live' | 'staged', required
  - `publishedAt` number, nullable, required
  - `publicUrl` string, required: Canonical public site URL for this slug.
  - `liveUrl` string, required: Alias of publicUrl.
  - `liveReady` boolean, required: True after first publish; until then the public URL 404s.
  - `build` object, nullable, required: Active clone/build progress, or null when no build is running.
    - `jobId` string, required
    - `phase` 'pages' | 'assets' | 'done' | 'failed', required
    - `pagesDone` number, required
    - `pagesTotal` number, required
    - `pagesLanded` number, required
    - `updatedAt` number, required
  - `building` boolean, required: build != null && build.phase !== 'done' — clone/build still running.
  - `buildPhase` 'pages' | 'assets' | 'done' | 'failed', nullable, required: Current build phase, or null when no build is active.
  - `editorReady` boolean, required: !building && stats.pages > 0 — draft/editor is renderable. Distinct from liveReady (public URL).
  - `createdAt` number, required
  - `updatedAt` number, required
  - `stats` object, required
    - `pages` number, required
    - `assets` number, required: CMS uploads under assets/ only — not mirrored clone CDN bytes (see mirroredAssets).
    - `storageBytes` number, required
    - `lastBuild` number, nullable, required
  - `pages` object[], required
    - `key` string, required
    - `name` string, required
    - `route` string, required
    - `updatedAt` number, required
  - `pagesListTotal` number, required: Total HTML pages matching pagesQ (or all pages when pagesQ is omitted).
  - `nextPagesCursor` string, nullable, required: Present when more HTML pages exist — pass as pagesCursor on the next call.
  - `pagesPartial` boolean: True when `pages` is one window of the page-key space, not all of it (mirrors /pages's own `partial`) — follow nextPagesCursor rather than treating pagesListTotal as exact.
  - `statsPartial` boolean: True when stats.pages/pagesListTotal is a floor from the KV arm's bounded meta-prefix probe, not an exact count. Distinct from pagesPartial, which is about the returned page WINDOW rather than the count.
  - `activity` object[], required
    - `kind` 'published' | 'updated' | 'created', required
    - `label` string, required
    - `at` number, required
  - `brief` object, nullable: Only with `?brief=1`: the head of the site brief (purpose, audience, priorities…), or null when none is set.
    - `purpose` string, required
    - `audience` string
    - `kind` 'exploration' | 'production'
    - `priorities` object
      - `seo` 'must' | 'nice' | 'skip'
      - `analytics` 'must' | 'nice' | 'skip'
      - `design` 'must' | 'nice' | 'skip'
      - `mobile` 'must' | 'nice' | 'skip'
    - `editingModel` 'ai' | 'simple-editor' | 'creator'
    - `design` object
      - `palette` string[]
      - `type` string[]
      - `layout` string
    - `hasBody` boolean, required
  - `guidance` object: Only with `?brief=1`: the site's rules & guidelines for AI agents — each line (a Rule Dotsy checks at publish, or a Guideline), `check` params on Rules (long lists truncated with `more`), short note previews, which sections are still unwritten (`missing`), optional `next: get_skill('guidance')` when `missing` is non-empty, and the AI access level. Present even when the site has no readable brief (everything `missing`).
    - `rules` object[], required
      - `id` string, required
      - `card` 'intent' | 'design' | 'content' | 'seo', required
      - `text` string, required
      - `kind` 'rule' | 'guideline', required
      - `level` 'block' | 'warn'
      - `locked` boolean, required
      - `check` object
        - `type` string, required
    - `notes` object, required
      - `design` string
      - `content` string
      - `seo` string
    - `missing` string[], required
    - `next` 'Before your first change: load get_skill('guidance') and write the missing sections.'
    - `aiAccess` 'viewer' | 'contributor' | 'editor' | 'owner', required
  - `draftLog` object[]
    - `tool` string, required
    - `context` string, required
    - `at` number, required
  - `integrations` object: Pending clone integrations stripped at import (0.27.1).
    - `pending` object[], required
      - `id` string, required
      - `vendor` string, required
      - `sourceId` string, required
      - `status` 'pending', required
      - `pageCount` number, required
      - `mayAffectUi` boolean
  - `mirroredAssets` object: Mirrored external CDN warm progress (assetMirror:full), cumulative across every generation this slug has ever warmed. Bytes land in raw/_cdn/ — not counted in stats.assets or list_assets.
    - `state` string, required
    - `warmMode` string
    - `resolved` boolean: Warm has settled (not pending/running) — 'stop polling', NOT 'assets are fine'. state:"aborted" is also resolved; check assetsReady/mirrorComplete (already exclude aborted) or the `abort` field before reading this as healthy.
    - `counts` object, required
      - `total` number, required
      - `warmed` number, required
      - `failed` number, required
      - `capped` number, required
      - `skipped` number, required
    - `externalCapped` object, required: Fraction of assets left origin-backed (302 to source, not on Dotsy R2) — a fidelity/durability risk even when failed:0. ratio > 0.25 should read as visual PARTIAL minimum per the eval rubric (0.63 §6.4).
      - `count` number, required
      - `total` number, required
      - `ratio` number, required
    - `failedAssetUrls` string[]: Bounded sample of failed asset source URLs for triage (capped at 50). counts.failed is the true total. Present only when there is something to show.
    - `abort` object: Present only when state:"aborted" — which named phase the run reached and why, so a total abort with 0 failures is never read as a clean success with nothing to do.
      - `stage` string
      - `reason` string
    - `generations` number: Manifest generations (import/re-import/segment-recovery attempts) folded into `counts`. Omitted for a single-generation site.
  - `previewReady` boolean: Pages staged — preview/publish allowed while asset warm may still run.
  - `assetsReady` boolean: Import complete and external warm settled with zero failures. False when the latest warm aborted, even with 0 failures recorded (see mirroredAssets.abort).
  - `mirrorComplete` boolean: Alias of assetsReady.
  - `failedAssetUrls` string[]: Sample failed external warm URLs from the latest warm job.
  - `assetsHint` string: Present with mirroredAssets — explains CMS assets/ vs mirrored raw/_cdn/ lanes.

## Other responses

- `400`: A query parameter is not valid (`invalid_request`): `pagesLimit` must be 1–1000, `pagesQ` at most 200 characters, `brief` 0 or 1.
- `401`: Missing or invalid credentials.
- `403`: The key or token is limited to other sites (`forbidden_site_scope`).
- `404`: No such site, or it is not visible to this account.

---

[API](https://skmtc.dev/dotsy/apis/dotsy-api.md) · [All operations](https://skmtc.dev/dotsy/apis/dotsy-api/llms.txt) · [OpenAPI document](https://skmtc.dev/dotsy/apis/dotsy-api/revisions/4272ed3b85d7?raw)
