dotsy · Schema

Site

CompanyArtificial IntelligenceWebsite BuilderNo-CodeFree

Properties

Name Type Description
id string Stable site id (UUID). Unlike the slug, it never changes.
slug string
title stringnull
keyConvention string
backend string
status string
editingMode string
publishedAt numbernull
publicUrl string Canonical public site URL for this slug.
liveUrl string Where visitors reach the site: the connected primary custom domain when there is one, else the same as publicUrl.
liveReady boolean True after first publish; until then the public URL 404s.
build objectnull Active clone/build progress, or null when no build is running.
building boolean build != null && build.phase !== 'done' — clone/build still running.
buildPhase stringnull Current build phase, or null when no build is active.
editorReady boolean !building && stats.pages > 0 — draft/editor is renderable. Distinct from liveReady (public URL).
createdAt number
updatedAt number
stats object
pages array
pagesListTotal number Total HTML pages matching pagesQ (or all pages when pagesQ is omitted).
nextPagesCursor stringnull 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 cou
activity array
needsYou integer Only with `?notifications=1` when notifications are enabled: open Needs-you count for this site and the signed-in person (not API keys).
brief objectnull Only with `?brief=1`: the head of the site brief (purpose, audience, priorities…), or null when none is set.
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 p
draftLog array
integrations object Pending clone integrations stripped at import (0.27.1).
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.
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 array Sample failed external warm URLs from the latest warm job.
assetsHint string Present with mirroredAssets — explains CMS assets/ vs mirrored raw/_cdn/ lanes.
aiTrain boolean Whether AI training crawlers may use the live site. false asks them not to. true when the site has not turned training off. Omitted on the shell payload.
ownRobots boolean True when an uploaded robots.txt is served on the live site (distinct from the generated file). Omitted on the shell payload.
View JSON Schema on GitHub

JSON Schema

dotsy-ai-site-schema.json Raw ↑
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/dotsy-ai/json-schema/dotsy-ai-site-schema.json",
  "title": "Site",
  "x-generated": "2026-11-06",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/dotsy-ai-openapi.yml#/components/schemas/Site",
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "Stable site id (UUID). Unlike the slug, it never changes."
    },
    "slug": {
      "type": "string"
    },
    "title": {
      "type": [
        "string",
        "null"
      ]
    },
    "keyConvention": {
      "type": "string",
      "enum": [
        "flat",
        "directory"
      ]
    },
    "backend": {
      "type": "string",
      "enum": [
        "kv",
        "do-sqlite"
      ]
    },
    "status": {
      "type": "string",
      "enum": [
        "published",
        "draft"
      ]
    },
    "editingMode": {
      "type": "string",
      "enum": [
        "live",
        "staged"
      ]
    },
    "publishedAt": {
      "type": [
        "number",
        "null"
      ]
    },
    "publicUrl": {
      "type": "string",
      "description": "Canonical public site URL for this slug."
    },
    "liveUrl": {
      "type": "string",
      "description": "Where visitors reach the site: the connected primary custom domain when there is one, else the same as publicUrl."
    },
    "liveReady": {
      "type": "boolean",
      "description": "True after first publish; until then the public URL 404s."
    },
    "build": {
      "type": [
        "object",
        "null"
      ],
      "properties": {
        "jobId": {
          "type": "string"
        },
        "phase": {
          "type": "string",
          "enum": [
            "pages",
            "assets",
            "done",
            "failed"
          ]
        },
        "pagesDone": {
          "type": "number"
        },
        "pagesTotal": {
          "type": "number"
        },
        "pagesLanded": {
          "type": "number"
        },
        "updatedAt": {
          "type": "number"
        }
      },
      "required": [
        "jobId",
        "phase",
        "pagesDone",
        "pagesTotal",
        "pagesLanded",
        "updatedAt"
      ],
      "description": "Active clone/build progress, or null when no build is running."
    },
    "building": {
      "type": "boolean",
      "description": "build != null && build.phase !== 'done' — clone/build still running."
    },
    "buildPhase": {
      "type": [
        "string",
        "null"
      ],
      "enum": [
        "pages",
        "assets",
        "done",
        "failed"
      ],
      "description": "Current build phase, or null when no build is active."
    },
    "editorReady": {
      "type": "boolean",
      "description": "!building && stats.pages > 0 — draft/editor is renderable. Distinct from liveReady (public URL)."
    },
    "createdAt": {
      "type": "number"
    },
    "updatedAt": {
      "type": "number"
    },
    "stats": {
      "type": "object",
      "properties": {
        "pages": {
          "type": "number"
        },
        "assets": {
          "type": "number",
          "description": "CMS uploads under assets/ only — not mirrored clone CDN bytes (see mirroredAssets)."
        },
        "storageBytes": {
          "type": "number"
        },
        "lastBuild": {
          "type": [
            "number",
            "null"
          ]
        }
      },
      "required": [
        "pages",
        "assets",
        "storageBytes",
        "lastBuild"
      ]
    },
    "pages": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "route": {
            "type": "string"
          },
          "updatedAt": {
            "type": "number"
          }
        },
        "required": [
          "key",
          "name",
          "route",
          "updatedAt"
        ]
      }
    },
    "pagesListTotal": {
      "type": "number",
      "description": "Total HTML pages matching pagesQ (or all pages when pagesQ is omitted)."
    },
    "nextPagesCursor": {
      "type": [
        "string",
        "null"
      ],
      "description": "Present when more HTML pages exist — pass as pagesCursor on the next call."
    },
    "pagesPartial": {
      "type": "boolean",
      "description": "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": {
      "type": "boolean",
      "description": "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": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "published",
              "updated",
              "created"
            ]
          },
          "label": {
            "type": "string"
          },
          "at": {
            "type": "number"
          }
        },
        "required": [
          "kind",
          "label",
          "at"
        ]
      }
    },
    "needsYou": {
      "type": "integer",
      "description": "Only with `?notifications=1` when notifications are enabled: open Needs-you count for this site and the signed-in person (not API keys)."
    },
    "brief": {
      "type": [
        "object",
        "null"
      ],
      "properties": {
        "purpose": {
          "type": "string",
          "minLength": 5,
          "maxLength": 280
        },
        "audience": {
          "type": "string",
          "maxLength": 200
        },
        "kind": {
          "type": "string",
          "enum": [
            "exploration",
            "production"
          ]
        },
        "priorities": {
          "type": "object",
          "properties": {
            "seo": {
              "type": "string",
              "enum": [
                "must",
                "nice",
                "skip"
              ]
            },
            "analytics": {
              "type": "string",
              "enum": [
                "must",
                "nice",
                "skip"
              ]
            },
            "design": {
              "type": "string",
              "enum": [
                "must",
                "nice",
                "skip"
              ]
            },
            "mobile": {
              "type": "string",
              "enum": [
                "must",
                "nice",
                "skip"
              ]
            }
          }
        },
        "editingModel": {
          "type": "string",
          "enum": [
            "ai",
            "simple-editor",
            "creator"
          ]
        },
        "design": {
          "type": "object",
          "properties": {
            "palette": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "maxItems": 8
            },
            "type": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "maxItems": 6
            },
            "layout": {
              "type": "string",
              "maxLength": 80
            }
          },
          "additionalProperties": false
        },
        "hasBody": {
          "type": "boolean"
        },
        "businessName": {
          "type": "string"
        }
      },
      "required": [
        "purpose",
        "hasBody"
      ],
      "description": "Only with `?brief=1`: the head of the site brief (purpose, audience, priorities…), or null when none is set."
    },
    "guidance": {
      "type": "object",
      "properties": {
        "rules": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "pattern": "^[a-z0-9-]{2,40}$"
              },
              "card": {
                "type": "string",
                "enum": [
                  "intent",
                  "design",
                  "content",
                  "seo"
                ]
              },
              "text": {
                "type": "string"
              },
              "kind": {
                "type": "string",
                "enum": [
                  "rule",
                  "guideline"
                ]
              },
              "level": {
                "type": "string",
                "enum": [
                  "block",
                  "warn"
                ]
              },
              "locked": {
                "type": "boolean"
              },
              "check": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string"
                  }
                },
                "required": [
                  "type"
                ]
              }
            },
            "required": [
              "id",
              "card",
              "text",
              "kind",
              "locked"
            ]
          }
        },
        "notes": {
          "type": "object",
          "properties": {
            "design": {
              "type": "string",
              "maxLength": 300
            },
            "content": {
              "type": "string",
              "maxLength": 300
            },
            "seo": {
              "type": "string",
              "maxLength": 300
            }
          }
        },
        "missing": {
          "type": "array",
          "items": {
            "type": "string",
            "enum": [
              "design",
              "content",
              "seo"
            ]
          }
        },
        "next": {
          "type": "string",
          "enum": [
            "Before your first change: load get_skill('guidance') and write the missing sections."
          ]
        },
        "aiAccess": {
          "type": "string",
          "enum": [
            "viewer",
            "contributor",
            "editor",
            "owner"
          ]
        },
        "searchLine": {
          "type": "string"
        }
      },
      "required": [
        "rules",
        "notes",
        "missing",
        "aiAccess"
      ],
      "description": "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`)."
    },
    "draftLog": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "tool": {
            "type": "string",
            "minLength": 1,
            "maxLength": 80
          },
          "context": {
            "type": "string",
            "minLength": 1,
            "maxLength": 500
          },
          "at": {
            "type": "number"
          }
        },
        "required": [
          "tool",
          "context",
          "at"
        ]
      }
    },
    "integrations": {
      "type": "object",
      "properties": {
        "pending": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "vendor": {
                "type": "string"
              },
              "sourceId": {
                "type": "string"
              },
              "status": {
                "type": "string",
                "enum": [
                  "pending"
                ]
              },
              "pageCount": {
                "type": "number"
              },
              "mayAffectUi": {
                "type": "boolean"
              }
            },
            "required": [
              "id",
              "vendor",
              "sourceId",
              "status",
              "pageCount"
            ]
          }
        }
      },
      "required": [
        "pending"
      ],
      "description": "Pending clone integrations stripped at import (0.27.1)."
    },
    "mirroredAssets": {
      "type": "object",
      "properties": {
        "state": {
          "type": "string"
        },
        "warmMode": {
          "type": "string"
        },
        "resolved": {
          "type": "boolean",
          "description": "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": {
          "type": "object",
          "properties": {
            "total": {
              "type": "number"
            },
            "warmed": {
              "type": "number"
            },
            "failed": {
              "type": "number"
            },
            "capped": {
              "type": "number"
            },
            "skipped": {
              "type": "number"
            }
          },
          "required": [
            "total",
            "warmed",
            "failed",
            "capped",
            "skipped"
          ]
        },
        "externalCapped": {
          "type": "object",
          "properties": {
            "count": {
              "type": "number"
            },
            "total": {
              "type": "number"
            },
            "ratio": {
              "type": "number"
            }
          },
          "required": [
            "count",
            "total",
            "ratio"
          ],
          "description": "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)."
        },
        "failedAssetUrls": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "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": {
          "type": "object",
          "properties": {
            "stage": {
              "type": "string"
            },
            "reason": {
              "type": "string"
            }
          },
          "description": "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."
        },
        "generations": {
          "type": "number",
          "description": "Manifest generations (import/re-import/segment-recovery attempts) folded into `counts`. Omitted for a single-generation site."
        }
      },
      "required": [
        "state",
        "counts",
        "externalCapped"
      ],
      "description": "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."
    },
    "previewReady": {
      "type": "boolean",
      "description": "Pages staged — preview/publish allowed while asset warm may still run."
    },
    "assetsReady": {
      "type": "boolean",
      "description": "Import complete and external warm settled with zero failures. False when the latest warm aborted, even with 0 failures recorded (see mirroredAssets.abort)."
    },
    "mirrorComplete": {
      "type": "boolean",
      "description": "Alias of assetsReady."
    },
    "failedAssetUrls": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Sample failed external warm URLs from the latest warm job."
    },
    "assetsHint": {
      "type": "string",
      "description": "Present with mirroredAssets — explains CMS assets/ vs mirrored raw/_cdn/ lanes."
    },
    "aiTrain": {
      "type": "boolean",
      "description": "Whether AI training crawlers may use the live site. false asks them not to. true when the site has not turned training off. Omitted on the shell payload."
    },
    "ownRobots": {
      "type": "boolean",
      "description": "True when an uploaded robots.txt is served on the live site (distinct from the generated file). Omitted on the shell payload."
    }
  },
  "required": [
    "id",
    "slug",
    "title",
    "keyConvention",
    "backend",
    "status",
    "editingMode",
    "publishedAt",
    "publicUrl",
    "liveUrl",
    "liveReady",
    "build",
    "building",
    "buildPhase",
    "editorReady",
    "createdAt",
    "updatedAt",
    "stats",
    "pages",
    "pagesListTotal",
    "nextPagesCursor",
    "activity"
  ]
}

Work with this as data

Every JSON Schema here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for schemas

4 MCP tools reach this
  • find_json_schemasBrowse and filter every JSON Schema in the catalog.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This JSON Schema
curl "https://apis.io/api/v1/json-schemas/dotsy-ai-site"
All schemas
curl "https://apis.io/api/v1/json-schemas?limit=25"

Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.