{"openapi":"3.1.0","info":{"title":"DropFast API","version":"1.0.0","description":"Publish HTML files (or ZIP archives) to permanent URLs. Designed for AI agents and developers who need stable, shareable, updatable links for generated content.\n\n**Authentication.** Programmatic clients send their API key as a bearer token: `Authorization: Bearer df_sk_…` (canonical). The legacy `x-api-key: df_sk_…` header is still accepted, and `fd_live_…` keys also work; Bearer wins if both headers are sent. The Clerk session cookie is browser-only.\n\n**Discovery surfaces.** Machine-readable spec at `/api/openapi.json`. Interactive docs at `/docs/openapi`. Agent-tailored guide at `/llms.txt`. MCP tool schemas at `/.well-known/tool-schemas.json`. MCP server at `/api/mcp`.","contact":{"name":"DropFast","url":"https://dropfast.dev"}},"servers":[{"url":"https://dropfast.dev","description":"Production"},{"url":"http://localhost:3000","description":"Local development"}],"tags":[{"name":"Sites","description":"Publish, update, and delete sites."},{"name":"Aliases","description":"Short-link aliases that survive site rebuilds."},{"name":"API Keys","description":"Manage your API keys. Session-only."},{"name":"Public","description":"Endpoints that do not require authentication."}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","description":"API key as a bearer token: `Authorization: Bearer df_sk_…`. This is the canonical header. Generate a key at /dashboard/api-keys. Keys begin with `df_sk_` (legacy `fd_live_` keys also work)."},"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"Legacy API-key header `x-api-key: df_sk_…`. Kept for back-compat; new clients should prefer `Authorization: Bearer` (BearerAuth). Bearer wins if both are sent."},"ClerkSession":{"type":"apiKey","in":"cookie","name":"__session","description":"Clerk-managed session cookie. Browser-only — used by the dashboard. Programmatic clients should prefer BearerAuth."}},"schemas":{"ApiKeySummary":{"type":"object","properties":{"id":{"type":"string","description":"Internal key row id."},"label":{"type":["string","null"]},"keyPrefix":{"type":"string","description":"First 12 chars of the key, e.g. `df_sk_XXXXXX`.","example":"df_sk_aB9XyZ"},"lastUsedAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"revokedAt":{"type":["string","null"],"format":"date-time"}},"required":["id","label","keyPrefix","lastUsedAt","createdAt"]},"SuccessOf_ApiKeyList":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeySummary"}}},"required":["success","data"]},"Error":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string","example":"UNAUTHORIZED"},"message":{"type":"string"},"fix":{"type":"string"},"docs_url":{"type":"string","format":"uri"},"retry_after_seconds":{"type":"integer"}},"required":["code","message"]}},"required":["success","error"]},"CreatedApiKey":{"allOf":[{"$ref":"#/components/schemas/ApiKeySummary"},{"type":"object","properties":{"key":{"type":"string","description":"The full secret key, shown once at creation. Store it now — it is not retrievable later."}},"required":["key"]}]},"SuccessOf_CreatedApiKey":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/CreatedApiKey"}},"required":["success","data"]},"CreateApiKeyBody":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":80,"description":"Human-readable label, shown in the dashboard.","example":"My laptop"}}},"RevokeApiKeyResponse":{"type":"object","properties":{"id":{"type":"string"},"revoked":{"type":"boolean","enum":[true]}},"required":["id","revoked"]},"SuccessOf_RevokeApiKey":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/RevokeApiKeyResponse"}},"required":["success","data"]},"SiteSummary":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string","description":"8-char nanoid identifying the site.","example":"abc12345"},"url":{"type":"string","format":"uri","description":"Live URL where the site is served."},"name":{"type":["string","null"]},"accessMode":{"type":"string","enum":["public","private","password"],"description":"Visibility for the published site."},"fileCount":{"type":"integer"},"fileSizeBytes":{"type":"integer"},"commentsEnabled":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","slug","url","name","accessMode","fileCount","fileSizeBytes","createdAt","updatedAt"]},"SuccessOf_SiteList":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/SiteSummary"}}},"required":["success","data"]},"CreateSiteResult":{"allOf":[{"$ref":"#/components/schemas/SiteSummary"},{"type":"object","properties":{"version":{"type":"integer","description":"Version number this write produced (1-indexed).","example":1},"versionUrl":{"type":"string","format":"uri","description":"Permalink pinned to this version via ?v=N."}},"required":["version","versionUrl"]}]},"SuccessOf_CreateSiteResult":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/CreateSiteResult"}},"required":["success","data"]},"CreateSiteForm":{"type":"object","properties":{"file":{"type":"string","description":".html file, .zip archive containing an index.html, or .md file (rendered to HTML server-side).","format":"binary"},"name":{"type":"string","minLength":1,"maxLength":120,"description":"Display name. Defaults to derived from `<title>` or the filename."},"accessMode":{"type":"string","enum":["public","private","password"],"description":"Visibility for the published site."},"password":{"type":"string","minLength":1,"maxLength":200,"description":"Required when accessMode is \"password\"."},"commentsEnabled":{"type":"string","enum":["true","false"],"description":"When \"true\", enables the comments overlay/API on the new site. Multipart string per form-data convention."}}},"SiteDetail":{"allOf":[{"$ref":"#/components/schemas/SiteSummary"},{"type":"object","properties":{"isActive":{"type":"boolean"}}}]},"SuccessOf_SiteDetail":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/SiteDetail"}},"required":["success","data"]},"UpdateSiteFilesResponse":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string","format":"uri"},"version":{"type":"integer","description":"Version number this update produced. A byte-identical re-upload is a no-op that returns the current version.","example":2},"versionUrl":{"type":"string","format":"uri","description":"Permalink pinned to this version via ?v=N."},"fileCount":{"type":"integer"},"fileSizeBytes":{"type":"integer"},"commentsEnabled":{"type":"boolean"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","slug","url","version","versionUrl","fileCount","fileSizeBytes","updatedAt"]},"SuccessOf_UpdateSiteFiles":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/UpdateSiteFilesResponse"}},"required":["success","data"]},"UpdateSiteFilesForm":{"type":"object","properties":{"file":{"type":"string","description":".html file, .zip archive, or .md file that replaces all current files.","format":"binary"}}},"PatchSiteResponse":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":["string","null"]},"accessMode":{"type":"string","enum":["public","private","password"],"description":"Visibility for the published site."},"commentsEnabled":{"type":"boolean"},"updatedAt":{"type":"string","format":"date-time"}},"required":["slug","name","accessMode","updatedAt"]},"SuccessOf_PatchSite":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/PatchSiteResponse"}},"required":["success","data"]},"PatchSiteBody":{"type":"object","properties":{"name":{"type":["string","null"],"minLength":1,"maxLength":120},"accessMode":{"type":"string","enum":["public","private","password"],"description":"Visibility for the published site."},"password":{"type":["string","null"],"minLength":1,"maxLength":200},"metadata":{"type":["object","null"],"additionalProperties":{},"description":"Replaces site.metadata. Use {} to clear, omit to leave unchanged."},"commentsEnabled":{"type":"boolean","description":"Enables the comments overlay/API for this site."}}},"DeleteSiteResponse":{"type":"object","properties":{"slug":{"type":"string"},"deleted":{"type":"boolean","enum":[true]}},"required":["slug","deleted"]},"SuccessOf_DeleteSite":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DeleteSiteResponse"}},"required":["success","data"]},"VersionListItem":{"type":"object","properties":{"version":{"type":"integer","example":3},"createdAt":{"type":"string","example":"2026-05-29T12:00:00.000Z"},"author":{"type":"string","example":"agent:claude"},"message":{"type":["string","null"],"example":"fix hero copy"},"byteSize":{"type":"integer","example":20480},"fileCount":{"type":"integer","example":2},"manifestHash":{"type":"string","example":"a1b2c3…"}},"required":["version","createdAt","author","message","byteSize","fileCount","manifestHash"]},"VersionListPage":{"type":"object","properties":{"versions":{"type":"array","items":{"$ref":"#/components/schemas/VersionListItem"}},"nextCursor":{"type":["string","null"],"description":"Pass into the next request as `?cursor=` to page older versions; null when no more."}},"required":["versions","nextCursor"]},"SuccessOf_VersionList":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/VersionListPage"}},"required":["success","data"]},"VersionFile":{"type":"object","properties":{"path":{"type":"string","example":"index.html"},"blobHash":{"type":"string"},"byteSize":{"type":"integer"}},"required":["path","blobHash","byteSize"]},"VersionDetail":{"allOf":[{"$ref":"#/components/schemas/VersionListItem"},{"type":"object","properties":{"authorApiKeyId":{"type":["string","null"]},"metadataSnapshot":{"type":"object","properties":{"name":{"type":["string","null"]},"accessMode":{"type":"string","enum":["public","private","password"]},"hasPassword":{"type":"boolean"}},"required":["name","accessMode","hasPassword"]},"files":{"type":"array","items":{"$ref":"#/components/schemas/VersionFile"}}},"required":["authorApiKeyId","metadataSnapshot","files"]}]},"SuccessOf_VersionDetail":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/VersionDetail"}},"required":["success","data"]},"CommentTarget":{"type":"object","properties":{"path":{"type":"string","example":"/"},"cssSelector":{"type":"string"},"textQuote":{"type":"object","properties":{"prefix":{"type":"string"},"exact":{"type":"string"},"suffix":{"type":"string"}},"required":["prefix","exact","suffix"]},"x":{"type":"number","minimum":0,"maximum":1},"y":{"type":"number","minimum":0,"maximum":1}},"required":["path"],"description":"A site-local anchor. Must include at least one of: `cssSelector`, `textQuote`, or both `x` and `y`."},"Comment":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["open","resolved"]},"bodyText":{"type":"string","example":"Tighten the hero copy."},"target":{"$ref":"#/components/schemas/CommentTarget"},"author":{"type":"object","properties":{"label":{"type":"string"},"isAgent":{"type":"boolean"}},"required":["label","isAgent"]},"versionAtCreate":{"type":["integer","null"]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"resolvedAt":{"type":["string","null"]},"resolvedByLabel":{"type":["string","null"]}},"required":["id","status","bodyText","target","author","versionAtCreate","createdAt","updatedAt","resolvedAt","resolvedByLabel"]},"CommentList":{"type":"object","properties":{"format":{"type":"string","enum":["dropfast-comment-spike-v1"]},"slug":{"type":"string"},"comments":{"type":"array","items":{"$ref":"#/components/schemas/Comment"}}},"required":["format","slug","comments"]},"SuccessOf_CommentListResult":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/CommentList"}},"required":["success","data"]},"CommentEnvelope":{"type":"object","properties":{"format":{"type":"string","enum":["dropfast-comment-spike-v1"]},"slug":{"type":"string"},"comment":{"$ref":"#/components/schemas/Comment"}},"required":["format","comment"]},"SuccessOf_CreateCommentResult":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/CommentEnvelope"}},"required":["success","data"]},"CreateCommentBody":{"type":"object","properties":{"bodyText":{"type":"string","minLength":1,"maxLength":2000},"target":{"$ref":"#/components/schemas/CommentTarget"}},"required":["bodyText","target"]},"SuccessOf_PatchCommentResult":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/CommentEnvelope"}},"required":["success","data"]},"PatchCommentBody":{"type":"object","properties":{"status":{"type":"string","enum":["open","resolved"]}},"required":["status"]},"VerifyPasswordResponse":{"type":"object","properties":{"slug":{"type":"string"}},"required":["slug"]},"SuccessOf_VerifyPassword":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/VerifyPasswordResponse"}},"required":["success","data"]},"VerifyPasswordBody":{"type":"object","properties":{"password":{"type":"string","minLength":1},"redirectTo":{"type":"string","description":"When the request is form-encoded, the server 303-redirects to this URL on success."}},"required":["password"]},"AliasSummary":{"type":"object","properties":{"id":{"type":"string"},"alias":{"type":"string","description":"The visible short-link slug. Lowercase letters, digits, hyphens. 2–48 chars.","example":"launch"},"targetType":{"type":"string","enum":["site","external"],"description":"`site` resolves to one of your DropFast sites; `external` redirects to an arbitrary URL."},"targetSiteId":{"type":["string","null"]},"targetUrl":{"type":["string","null"]},"url":{"type":"string","format":"uri","description":"Public resolver URL (`https://dropfast.dev/_/<alias>`)."},"isActive":{"type":"boolean"},"hitCount":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","alias","targetType","url","createdAt","updatedAt"]},"SuccessOf_AliasList":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/AliasSummary"}}},"required":["success","data"]},"SuccessOf_CreateAlias":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/AliasSummary"}},"required":["success","data"]},"CreateAliasBody":{"type":"object","properties":{"alias":{"type":"string","minLength":1,"maxLength":64},"targetType":{"type":"string","enum":["site","external"],"description":"`site` resolves to one of your DropFast sites; `external` redirects to an arbitrary URL."},"targetSiteId":{"type":["string","null"],"minLength":1},"targetUrl":{"type":["string","null"],"minLength":1}},"required":["alias","targetType"]},"SuccessOf_AliasDetail":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/AliasSummary"}},"required":["success","data"]},"SuccessOf_PatchAlias":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/AliasSummary"}},"required":["success","data"]},"PatchAliasBody":{"type":"object","properties":{"alias":{"type":"string","minLength":1,"maxLength":64,"description":"Rename the short-link. Subject to the same uniqueness + reserved-name rules."},"targetType":{"type":"string","enum":["site","external"],"description":"`site` resolves to one of your DropFast sites; `external` redirects to an arbitrary URL."},"targetSiteId":{"type":["string","null"],"minLength":1},"targetUrl":{"type":["string","null"],"minLength":1},"isActive":{"type":"boolean","description":"Pause (false) or resume (true) the alias without deleting it."}}},"DeleteAliasResponse":{"type":"object","properties":{"alias":{"type":"string"},"deleted":{"type":"boolean","enum":[true]}},"required":["alias","deleted"]},"SuccessOf_DeleteAlias":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DeleteAliasResponse"}},"required":["success","data"]}},"parameters":{}},"paths":{"/api/v1/keys":{"get":{"tags":["API Keys"],"summary":"List your active API keys","description":"Returns prefix metadata only. The full secret is never returned after creation.","security":[{"ClerkSession":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessOf_ApiKeyList"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["API Keys"],"summary":"Generate a new API key","description":"Creates a new key and returns the full secret **one time only**. Store the value immediately — it is not retrievable later. The key prefix is `df_sk_` for newly generated keys.","security":[{"ClerkSession":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessOf_CreatedApiKey"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/keys/{id}":{"delete":{"tags":["API Keys"],"summary":"Revoke an API key","description":"Sets `revokedAt` on the row. Subsequent requests using this key return 401.","security":[{"ClerkSession":[]}],"parameters":[{"schema":{"type":"string","description":"The key row id from `GET /api/v1/keys`."},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessOf_RevokeApiKey"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/sites":{"get":{"tags":["Sites"],"summary":"List your sites","security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"ClerkSession":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessOf_SiteList"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Sites"],"summary":"Publish a new site","description":"Upload an `.html` file (single page), a `.zip` archive (multi-file site with `index.html` at the root), or a `.md` file (rendered to styled HTML server-side). Returns the live URL.","security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"ClerkSession":[]}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/CreateSiteForm"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessOf_CreateSiteResult"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Upload too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/sites/{slug}":{"get":{"tags":["Sites"],"summary":"Get a site by slug","security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"ClerkSession":[]}],"parameters":[{"schema":{"type":"string","example":"abc12345"},"required":true,"name":"slug","in":"path"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessOf_SiteDetail"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"tags":["Sites"],"summary":"Replace the files of an existing site","description":"Same slug, same URL, new content. Old files are removed from S3 atomically.","security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"ClerkSession":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/UpdateSiteFilesForm"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessOf_UpdateSiteFiles"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Sites"],"summary":"Update a site's name, accessMode, or password","description":"Does not replace files. Use PUT for that. Null values clear optional fields.","security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"ClerkSession":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatchSiteBody"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessOf_PatchSite"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Sites"],"summary":"Delete a site","description":"Deactivates the site, removes S3 files, and cascades any aliases pointing to it (the aliases become inactive but remain visible so you can repoint them).","security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"ClerkSession":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessOf_DeleteSite"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/sites/{slug}/versions":{"get":{"tags":["Sites"],"summary":"List a site’s version history","description":"Owner-scoped. Returns versions newest-first with cursor pagination (`?cursor=`, `?limit=` up to 100). The rendered bytes for a historical version are served at `/s/{slug}/?v={v}` (the versionUrl permalink returned by publish/update).","security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"ClerkSession":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"},{"schema":{"type":"string"},"required":false,"name":"cursor","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessOf_VersionList"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/sites/{slug}/versions/{v}":{"get":{"tags":["Sites"],"summary":"Get one historical version’s metadata + file list","description":"Owner-scoped. Returns the version row plus its content-addressable file manifest. View the rendered bytes at `/s/{slug}/?v={v}`.","security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"ClerkSession":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"},{"schema":{"type":"string","example":"3"},"required":true,"name":"v","in":"path"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessOf_VersionDetail"}}}},"400":{"description":"Version path segment is not a positive integer","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Version (or site) not found — error code `VERSION_NOT_FOUND`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/sites/{slug}/comments":{"get":{"tags":["Sites"],"summary":"List comments on a comments-enabled site","description":"Reads are public for public comments-enabled sites; private/password sites require owner auth. Filter with `?status=open|resolved|all`. Requires the site to have `commentsEnabled: true`.","parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"},{"schema":{"type":"string","enum":["open","resolved","all"]},"required":false,"name":"status","in":"query"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessOf_CommentListResult"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Comments disabled (`COMMENTS_SPIKE_DISABLED`) or not permitted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Sites"],"summary":"Add a comment to a comments-enabled site","description":"Requires auth. Body is plain text (1–2000 chars; HTML rejected with `COMMENT_BODY_INVALID`). The `target` must carry a real anchor. Browser writes are rate-limited by site+IP; API-key writes by key+site at a lower budget.","security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"ClerkSession":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCommentBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessOf_CreateCommentResult"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Comments disabled (`COMMENTS_SPIKE_DISABLED`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/comments/{id}":{"patch":{"tags":["Sites"],"summary":"Resolve or re-open a comment","description":"Owner-scoped. Set `status` to `resolved` (or back to `open`).","security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"ClerkSession":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatchCommentBody"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessOf_PatchCommentResult"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not the comment owner","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/sites/{slug}/verify-password":{"post":{"tags":["Public"],"summary":"Trade a site password for a signed access cookie","description":"Public endpoint. Rate-limited to 5 attempts per IP per minute. On success the server sets a `fd_access_<slug>` cookie (24h TTL) and the user can view the site at `/s/<slug>/`. Form-encoded requests get a 303 redirect; JSON requests get a JSON response.","parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyPasswordBody"}}}},"responses":{"200":{"description":"OK — cookie set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessOf_VerifyPassword"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Incorrect password","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/aliases":{"get":{"tags":["Aliases"],"summary":"List your aliases","security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"ClerkSession":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessOf_AliasList"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Aliases"],"summary":"Create a short-link alias","description":"Creates a globally unique alias that resolves at `/_/<alias>`. Point it at a DropFast site (`targetType: site` with `targetSiteId`) or at any external URL (`targetType: external` with `targetUrl`).","security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"ClerkSession":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAliasBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessOf_CreateAlias"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Alias taken","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/aliases/{alias}":{"get":{"tags":["Aliases"],"summary":"Get an alias by name","security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"ClerkSession":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"alias","in":"path"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessOf_AliasDetail"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Aliases"],"summary":"Repoint, rename, or pause an alias","description":"Pass `isActive: false` to pause without deleting (resolver returns 404 while paused).","security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"ClerkSession":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"alias","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatchAliasBody"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessOf_PatchAlias"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Alias taken","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Aliases"],"summary":"Delete an alias","security":[{"BearerAuth":[]},{"ApiKeyAuth":[]},{"ClerkSession":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"alias","in":"path"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessOf_DeleteAlias"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"webhooks":{}}