diff --git a/scripts/generate-api-v2.mjs b/scripts/generate-api-v2.mjs
index 41e349d..dbdee42 100644
--- a/scripts/generate-api-v2.mjs
+++ b/scripts/generate-api-v2.mjs
@@ -11,437 +11,91 @@
* operations.md — Operations-tagged endpoints
* models.md — all component schemas
*
- * authentication.md and README.md are hand-written; this script does not touch them.
+ * authentication.md, migration.md, and README.md are hand-written; this script
+ * does not touch them.
+ *
+ * The rendering lives in scripts/lib/openapi-docs.mjs, shared with the Hosted
+ * v1 generator.
*/
-import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
-import { join, dirname } from "path";
+import { dirname, join } from "path";
import { fileURLToPath } from "url";
-import yaml from "yaml";
+import { generateApiDocs } from "./lib/openapi-docs.mjs";
const __dirname = dirname(fileURLToPath(import.meta.url));
-const SPEC_PATH = join(__dirname, "../specs/dolthub-v2.yaml");
-const OUT_DIR = join(
- __dirname,
- "../site/dolt/src/content/products/dolthub/api/v2"
-);
-
-const spec = yaml.parse(readFileSync(SPEC_PATH, "utf-8"));
-
-// ---------------------------------------------------------------------------
-// $ref resolution (with cycle guard)
-// ---------------------------------------------------------------------------
-
-function resolveRef(ref) {
- const parts = ref.replace(/^#\//, "").split("/");
- let obj = spec;
- for (const p of parts) obj = obj[p];
- return obj;
-}
-
-function deref(obj, depth = 0) {
- if (depth > 8) return obj; // cycle guard
- if (typeof obj !== "object" || obj === null) return obj;
- if (Array.isArray(obj)) return obj.map((x) => deref(x, depth + 1));
- if ("$ref" in obj) return deref(resolveRef(obj.$ref), depth + 1);
- return Object.fromEntries(
- Object.entries(obj).map(([k, v]) => [k, deref(v, depth + 1)])
- );
-}
-
-function refName(refStr) {
- return refStr?.split("/").pop();
-}
-
-// ---------------------------------------------------------------------------
-// Formatting helpers
-// ---------------------------------------------------------------------------
-
-const METHOD_LABELS = {
- get: "GET",
- post: "POST",
- put: "PUT",
- patch: "PATCH",
- delete: "DELETE",
-};
-
-function escapeMarkdown(str = "") {
- return str.replace(/\|/g, "\\|").replace(/\n+/g, " ").trim();
-}
-
-// Same palette + markup as the hand-written v1alpha1 pages' .api-method /
-// .api-path spans (see DocsLayout.astro), so v2 endpoint headers match.
-function methodSpan(method) {
- const colors = {
- get: "29E3C1",
- post: "6DB0FC",
- patch: "F0A35C",
- put: "F0A35C",
- delete: "EF5350",
- };
- const color = colors[method] ?? "888888";
- const label = METHOD_LABELS[method] ?? method.toUpperCase();
- return `${label}`;
-}
-
-function curlExample(method, path, operation) {
- const lines = [
- `curl -X ${METHOD_LABELS[method] ?? method.toUpperCase()} 'https://www.dolthub.com${path}'`,
- ` -H 'Authorization: Bearer YOUR_TOKEN'`,
- ];
- if (method !== "get" && method !== "delete") {
- lines.push(` -H 'Content-Type: application/json'`);
- const reqBody = operation.requestBody?.content?.["application/json"]?.schema;
- if (reqBody) {
- const resolved = deref(reqBody);
- const required = resolved.required ?? [];
- const props = resolved.properties ?? {};
- const example = Object.fromEntries(
- Object.entries(props)
- .filter(([k]) => required.includes(k))
- .slice(0, 4)
- .map(([k, v]) => {
- const t = v.type ?? (v.enum ? "enum" : "object");
- const ex =
- v.examples?.[0] ??
- v.example ??
- (t === "string" ? `"example_${k}"` : t === "boolean" ? false : 0);
- return [k, ex];
- })
- );
- if (Object.keys(example).length > 0) {
- lines.push(` -d '${JSON.stringify(example)}'`);
- }
- }
- }
- return lines.join(" \\\n");
-}
-
-function parametersSection(params) {
- if (!params?.length) return "";
- const rows = params
- .map((p) => {
- const resolved = deref(p);
- const location = resolved.in ?? "";
- const name = resolved.name ?? "";
- const required = resolved.required ? "yes" : "no";
- const type = resolved.schema?.type ?? "";
- const desc = escapeMarkdown(resolved.description ?? "");
- return `| \`${name}\` | ${location} | ${type} | ${required} | ${desc} |`;
- })
- .join("\n");
- return `\n**Parameters**\n\n| Name | In | Type | Required | Description |\n|------|----|------|----------|-------------|\n${rows}\n`;
-}
-
-function requestBodySection(requestBody) {
- if (!requestBody) return "";
- const schema = requestBody.content?.["application/json"]?.schema;
- if (!schema) return "";
- const resolved = deref(schema);
- const required = resolved.required ?? [];
- const props = resolved.properties ?? {};
- if (!Object.keys(props).length) return "";
- const rows = Object.entries(props)
- .map(([k, v]) => {
- const req = required.includes(k) ? "yes" : "no";
- const type = v.type ?? (v.$ref ? refName(v.$ref) : "object");
- const desc = escapeMarkdown(v.description ?? "");
- return `| \`${k}\` | ${type} | ${req} | ${desc} |`;
- })
- .join("\n");
- return `\n**Request body**\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n${rows}\n`;
-}
-
-function responseSchemaName(schema) {
- if (!schema) return "";
- if (schema.$ref) return refName(schema.$ref);
- // Common pattern: allOf: [Envelope, { properties: { data: $ref Schema } }]
- if (schema.allOf) {
- for (const s of schema.allOf) {
- if (s.properties?.data?.$ref) return refName(s.properties.data.$ref);
- // List responses: data.items.$ref
- if (s.properties?.data?.items?.$ref)
- return refName(s.properties.data.items.$ref) + "[]";
- }
- }
- return "";
-}
-
-function successExampleBlock(rawResponses) {
- if (!rawResponses) return "";
- const successCode = Object.keys(rawResponses).find((c) => /^2/.test(c));
- if (!successCode) return "";
-
- const rawResp = rawResponses[successCode];
- const resp = rawResp.$ref ? resolveRef(rawResp.$ref) : rawResp;
- const schema = resp.content?.["application/json"]?.schema;
- if (!schema?.allOf) return "";
-
- let dataExample = null;
- let isList = false;
-
- for (const s of schema.allOf) {
- if (s.properties?.data?.$ref) {
- const name = refName(s.properties.data.$ref);
- dataExample = spec.components?.schemas?.[name]?.examples?.[0] ?? null;
- break;
- }
- if (s.properties?.data?.type === "array" && s.properties?.data?.items?.$ref) {
- const name = refName(s.properties.data.items.$ref);
- dataExample = spec.components?.schemas?.[name]?.examples?.[0] ?? null;
- isList = true;
- break;
- }
- }
-
- if (!dataExample) return "";
-
- const body = isList
- ? { data: [dataExample], meta: { next_page_token: "eyJvZmZzZXQiOjI1fQ" } }
- : { data: dataExample };
-
- return `\n**Example response \`${successCode}\`**\n\n\`\`\`json\n${JSON.stringify(body, null, 2)}\n\`\`\`\n`;
-}
-
-function responsesSection(rawResponses) {
- if (!rawResponses) return "";
- const rows = Object.entries(rawResponses)
- .map(([code, rawResp]) => {
- // Resolve top-level $ref (e.g. $ref: "#/components/responses/Unauthorized")
- const resp = rawResp.$ref ? resolveRef(rawResp.$ref) : rawResp;
- const desc = escapeMarkdown(resp.description ?? "");
- const schema = resp.content?.["application/json"]?.schema;
- const name = responseSchemaName(schema);
- const schemaLink = name
- ? `[\`${name}\`](models#model-${name.replace("[]", "").toLowerCase()})`
- : "";
- return `| \`${code}\` | ${desc} | ${schemaLink} |`;
- })
- .join("\n");
- return `\n**Responses**\n\n| Status | Description | Schema |\n|--------|-------------|--------|\n${rows}\n`;
-}
-
-// ---------------------------------------------------------------------------
-// Derive sub-resource label from path (for grouping within the Database page)
-// ---------------------------------------------------------------------------
-function subResource(path) {
+// The Database tag covers every database sub-resource, so its page gets an H2
+// per sub-resource rather than one flat list of ~20 endpoints.
+function databaseSubResource(path) {
// After /databases/{owner}/{database}/...
- const m = path.match(
- /^\/api\/v2\/databases\/\{[^}]+\}\/\{[^}]+\}\/([^/]+)/
- );
+ const m = path.match(/^\/api\/v2\/databases\/\{[^}]+\}\/\{[^}]+\}\/([^/]+)/);
if (m) {
switch (m[1]) {
- case "branches": return "Branches";
- case "tags": return "Tags";
- case "forks": return "Forks";
- case "releases": return "Releases";
+ case "branches":
+ return "Branches";
+ case "tags":
+ return "Tags";
+ case "forks":
+ return "Forks";
+ case "releases":
+ return "Releases";
case "sql":
case "sql-writes":
return "SQL";
- case "pulls": return "Pull Requests";
- case "imports": return "Imports";
- default: return m[1];
+ case "pulls":
+ return "Pull Requests";
+ case "imports":
+ return "Imports";
+ default:
+ return m[1];
}
}
if (path.startsWith("/api/v2/databases")) return "Databases";
return "Other";
}
-// ---------------------------------------------------------------------------
-// Build per-endpoint Markdown block
-// ---------------------------------------------------------------------------
-
-function endpointBlock(method, path, operation, headingLevel = "###") {
- const anchor = `{#${operation.operationId}}`;
- const title = operation.summary
- ? operation.summary.replace(/\.$/, "")
- : `${METHOD_LABELS[method]} ${path}`;
- const heading = `${headingLevel} ${title} ${anchor}\n`;
- const methodPath = `${methodSpan(method)} ${path}\n\n`;
- const description =
- operation.description &&
- operation.description.trim() !== (operation.summary ?? "").trim()
- ? `${operation.description.trim()}\n\n`
- : "";
- const params = parametersSection(operation.parameters);
- const body = requestBodySection(deref(operation.requestBody ?? {}));
- const responses = responsesSection(operation.responses);
- const successExample = successExampleBlock(operation.responses);
- const curl = `\n**Example request**\n\n\`\`\`sh\n${curlExample(method, path, operation)}\n\`\`\`\n`;
- return [heading, methodPath, description, params, body, curl, responses, successExample]
- .filter(Boolean)
- .join("");
-}
-
-// ---------------------------------------------------------------------------
-// Collect operations by tag
-// ---------------------------------------------------------------------------
-
-const byTag = {}; // tag → [{ method, path, operation }]
-
-for (const [path, pathItem] of Object.entries(spec.paths ?? {})) {
- for (const method of [
- "get",
- "post",
- "put",
- "patch",
- "delete",
- "head",
- "options",
- ]) {
- const op = pathItem[method];
- if (!op) continue;
- for (const tag of op.tags ?? ["Untagged"]) {
- if (!byTag[tag]) byTag[tag] = [];
- byTag[tag].push({ method, path, operation: op });
- }
- }
-}
-
-// ---------------------------------------------------------------------------
-// Tag-level page generators
-// ---------------------------------------------------------------------------
-
-function generateTagPage(tag, items, frontmatter) {
- const tagInfo = spec.tags?.find((t) => t.name === tag) ?? {};
- const intro = tagInfo.description ? `${tagInfo.description}\n\n` : "";
-
- // For Database tag, group by sub-resource
- if (tag === "Database") {
- const groups = {};
- for (const item of items) {
- const g = subResource(item.path);
- if (!groups[g]) groups[g] = [];
- groups[g].push(item);
- }
- const order = [
- "Databases",
- "SQL",
- "Branches",
- "Tags",
- "Forks",
- "Releases",
- "Pull Requests",
- "Imports",
- ];
- const sorted = [
- ...order.filter((g) => groups[g]),
- ...Object.keys(groups).filter((g) => !order.includes(g)),
- ];
- const sections = sorted
- .map((g) => {
- const endpoints = groups[g]
- .map((item) =>
- endpointBlock(item.method, item.path, item.operation, "###")
- )
- .join("\n---\n\n");
- return `## ${g}\n\n${endpoints}`;
- })
- .join("\n\n");
- return `${frontmatter}\n\n${intro}${sections}\n`;
- }
-
- // Other tags: flat list
- const content = items
- .map((item) =>
- endpointBlock(item.method, item.path, item.operation, "##")
- )
- .join("\n---\n\n");
- return `${frontmatter}\n\n${intro}${content}\n`;
-}
-
-// ---------------------------------------------------------------------------
-// Models page
-// ---------------------------------------------------------------------------
-
-function schemaBlock(name, schema) {
- const anchor = `{#model-${name.toLowerCase()}}`;
- const heading = `## ${name} ${anchor}\n`;
- const desc = schema.description ? `${schema.description.trim()}\n\n` : "";
-
- if (schema.enum) {
- const descs = schema["x-enum-descriptions"] ?? [];
- const hasDescs = descs.some(Boolean);
- const values = schema.enum
- .map((v, i) =>
- hasDescs
- ? `| \`${v}\` | ${escapeMarkdown(descs[i] ?? "")} |`
- : `| \`${v}\` |`
- )
- .join("\n");
- const header = hasDescs
- ? `| Value | Description |\n|-------|-------------|`
- : `| Value |\n|-------|`;
- return `${heading}${desc}**Enum values**\n\n${header}\n${values}\n`;
- }
-
- const props = schema.properties ?? schema.allOf?.find((s) => s.properties)?.properties;
- if (!props || !Object.keys(props).length) {
- const type = schema.type ?? (schema.allOf ? "object" : "");
- return `${heading}${desc}${type ? `_Type: \`${type}\`_\n` : ""}\n`;
- }
-
- const required = schema.required ?? schema.allOf?.find((s) => s.required)?.required ?? [];
- const rows = Object.entries(props)
- .map(([k, v]) => {
- const req = required.includes(k) ? "yes" : "no";
- const type = v.type ?? (v.$ref ? refName(v.$ref) : v.allOf ? "object" : "object");
- const d = escapeMarkdown(v.description ?? "");
- return `| \`${k}\` | \`${type}\` | ${req} | ${d} |`;
- })
- .join("\n");
-
- return `${heading}${desc}| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n${rows}\n`;
-}
-
-function generateModelsPage() {
- const fm = `---\ntitle: "Models"\ndescription: Request and response schemas for the DoltHub v2 API.\n---\n\n# Models`;
- const schemas = Object.entries(spec.components?.schemas ?? {});
- const blocks = schemas
- .map(([name, schema]) => schemaBlock(name, deref(schema)))
- .join("\n---\n\n");
- return `${fm}\n\nShared request and response types used across the v2 API. See the [error model](#model-problem) for how failures are reported.\n\n${blocks}\n`;
-}
-
-// ---------------------------------------------------------------------------
-// Write output files
-// ---------------------------------------------------------------------------
-
-mkdirSync(OUT_DIR, { recursive: true });
-
-const tagPages = [
- {
- tag: "User",
- file: "user.md",
- frontmatter:
- '---\ntitle: "User"\ndescription: The authenticated user resource in the DoltHub v2 API.\n---\n\n# User',
- },
- {
- tag: "Database",
- file: "database.md",
- frontmatter:
- '---\ntitle: "Database"\ndescription: DoltHub databases, branches, tags, forks, releases, SQL, pull requests, and imports.\n---\n\n# Database',
- },
- {
- tag: "Operations",
- file: "operations.md",
+generateApiDocs({
+ specPath: join(__dirname, "../specs/dolthub-v2.yaml"),
+ outDir: join(__dirname, "../site/dolt/src/content/products/dolthub/api/v2"),
+ tagPages: [
+ {
+ tag: "User",
+ file: "user.md",
+ frontmatter:
+ '---\ntitle: "User"\ndescription: The authenticated user resource in the DoltHub v2 API.\n---\n\n# User',
+ },
+ {
+ tag: "Database",
+ file: "database.md",
+ frontmatter:
+ '---\ntitle: "Database"\ndescription: DoltHub databases, branches, tags, forks, releases, SQL, pull requests, and imports.\n---\n\n# Database',
+ groups: {
+ of: databaseSubResource,
+ order: [
+ "Databases",
+ "SQL",
+ "Branches",
+ "Tags",
+ "Forks",
+ "Releases",
+ "Pull Requests",
+ "Imports",
+ ],
+ },
+ },
+ {
+ tag: "Operations",
+ file: "operations.md",
+ frontmatter:
+ '---\ntitle: "Operations"\ndescription: Long-running async operations in the DoltHub v2 API.\n---\n\n# Operations',
+ },
+ ],
+ models: {
+ file: "models.md",
+ href: "/products/dolthub/api/v2/models",
frontmatter:
- '---\ntitle: "Operations"\ndescription: Long-running async operations in the DoltHub v2 API.\n---\n\n# Operations',
+ '---\ntitle: "Models"\ndescription: Request and response schemas for the DoltHub v2 API.\n---\n\n# Models',
+ intro:
+ "Shared request and response types used across the v2 API. See the [error model](#model-problem) for how failures are reported.",
},
-];
-
-for (const { tag, file, frontmatter } of tagPages) {
- const items = byTag[tag] ?? [];
- if (!items.length) {
- console.warn(`Warning: no endpoints found for tag "${tag}"`);
- continue;
- }
- const content = generateTagPage(tag, items, frontmatter);
- writeFileSync(join(OUT_DIR, file), content);
- console.log(`Wrote ${file} (${items.length} endpoints)`);
-}
-
-const modelsContent = generateModelsPage();
-writeFileSync(join(OUT_DIR, "models.md"), modelsContent);
-console.log(`Wrote models.md (${Object.keys(spec.components?.schemas ?? {}).length} schemas)`);
+});
diff --git a/scripts/generate-hosted-api-v1.mjs b/scripts/generate-hosted-api-v1.mjs
new file mode 100644
index 0000000..4fb913d
--- /dev/null
+++ b/scripts/generate-hosted-api-v1.mjs
@@ -0,0 +1,51 @@
+#!/usr/bin/env node
+/**
+ * Generates per-tag Markdown pages for the Hosted v1 API from the OpenAPI spec.
+ *
+ * Usage:
+ * node scripts/generate-hosted-api-v1.mjs
+ *
+ * Output: site/dolt/src/content/products/hosted/api/v1/
+ * user.md — User-tagged endpoints
+ * deployment.md — Deployment-tagged endpoints
+ * models.md — all component schemas
+ *
+ * authentication.md and README.md are hand-written; this script does not touch
+ * them.
+ *
+ * The rendering lives in scripts/lib/openapi-docs.mjs, shared with the DoltHub
+ * v2 generator.
+ */
+
+import { dirname, join } from "path";
+import { fileURLToPath } from "url";
+import { generateApiDocs } from "./lib/openapi-docs.mjs";
+
+const __dirname = dirname(fileURLToPath(import.meta.url));
+
+generateApiDocs({
+ specPath: join(__dirname, "../specs/hosted-v1.yaml"),
+ outDir: join(__dirname, "../site/dolt/src/content/products/hosted/api/v1"),
+ tagPages: [
+ {
+ tag: "User",
+ file: "user.md",
+ frontmatter:
+ '---\ntitle: "User"\ndescription: The authenticated user resource in the Hosted v1 API.\n---\n\n# User',
+ },
+ {
+ tag: "Deployment",
+ file: "deployment.md",
+ frontmatter:
+ '---\ntitle: "Deployment"\ndescription: Creating, listing, and reading Hosted Dolt deployments and their instances.\n---\n\n# Deployment',
+ },
+ ],
+ models: {
+ file: "models.md",
+ href: "/products/hosted/api/v1/models",
+ frontmatter:
+ '---\ntitle: "Models"\ndescription: Request and response schemas for the Hosted v1 API.\n---\n\n# Models',
+ intro:
+ "Shared request and response types used across the v1 API. See the [error model](#model-problem) for how failures are reported.",
+ },
+});
diff --git a/scripts/lib/openapi-docs.mjs b/scripts/lib/openapi-docs.mjs
new file mode 100644
index 0000000..a5cf870
--- /dev/null
+++ b/scripts/lib/openapi-docs.mjs
@@ -0,0 +1,485 @@
+/**
+ * Shared OpenAPI → Markdown docs generator.
+ *
+ * Both the DoltHub v2 API and the Hosted v1 API are defined by OpenAPI 3.1
+ * specs that share an error model (RFC 9457 `Problem`), a success `Envelope`,
+ * and cursor pagination — deliberately, so the two public APIs don't disagree
+ * about the basics. This module holds the rendering that follows from that
+ * shared shape; the per-API scripts supply only what genuinely differs (spec
+ * path, output directory, page list, and any tag-level grouping).
+ *
+ * See scripts/generate-api-v2.mjs and scripts/generate-hosted-api-v1.mjs.
+ */
+
+import { readFileSync, writeFileSync, mkdirSync } from "fs";
+import { join } from "path";
+import yaml from "yaml";
+
+const METHOD_LABELS = {
+ get: "GET",
+ post: "POST",
+ put: "PUT",
+ patch: "PATCH",
+ delete: "DELETE",
+};
+
+// Same palette + markup as the hand-written v1alpha1 pages' .api-method /
+// .api-path spans (see site/shared/layouts/DocsLayout.astro), so generated
+// endpoint headers match the hand-written ones.
+const METHOD_COLORS = {
+ get: "29E3C1",
+ post: "6DB0FC",
+ patch: "F0A35C",
+ put: "F0A35C",
+ delete: "EF5350",
+};
+
+const HTTP_METHODS = [
+ "get",
+ "post",
+ "put",
+ "patch",
+ "delete",
+ "head",
+ "options",
+];
+
+function escapeMarkdown(str = "") {
+ return str.replace(/\|/g, "\\|").replace(/\n+/g, " ").trim();
+}
+
+function refName(refStr) {
+ return refStr?.split("/").pop();
+}
+
+function methodSpan(method) {
+ const color = METHOD_COLORS[method] ?? "888888";
+ const label = METHOD_LABELS[method] ?? method.toUpperCase();
+ return `${label}`;
+}
+
+/**
+ * Builds a renderer bound to one parsed spec. Everything that needs to walk
+ * `$ref`s closes over `spec`, so nothing is passed around explicitly.
+ */
+function createRenderer(spec, { baseUrl, tokenPlaceholder, modelsHref }) {
+ // -------------------------------------------------------------------------
+ // $ref resolution (with cycle guard)
+ // -------------------------------------------------------------------------
+
+ function resolveRef(ref) {
+ const parts = ref.replace(/^#\//, "").split("/");
+ let obj = spec;
+ for (const p of parts) obj = obj[p];
+ return obj;
+ }
+
+ function deref(obj, depth = 0) {
+ if (depth > 8) return obj; // cycle guard
+ if (typeof obj !== "object" || obj === null) return obj;
+ if (Array.isArray(obj)) return obj.map((x) => deref(x, depth + 1));
+ if ("$ref" in obj) return deref(resolveRef(obj.$ref), depth + 1);
+ return Object.fromEntries(
+ Object.entries(obj).map(([k, v]) => [k, deref(v, depth + 1)])
+ );
+ }
+
+ // -------------------------------------------------------------------------
+ // Examples
+ // -------------------------------------------------------------------------
+
+ // OpenAPI 3.1 permits a media type to carry named `examples`. Prefer the one
+ // named `default`, else the first — a hand-written example beats anything
+ // synthesized from the schema.
+ function mediaTypeExample(mediaType) {
+ if (!mediaType) return undefined;
+ const named = mediaType.examples;
+ if (named && typeof named === "object") {
+ const entry = named.default ?? Object.values(named)[0];
+ if (entry && "value" in entry) return entry.value;
+ }
+ return mediaType.example;
+ }
+
+ function requestExample(operation) {
+ const media = operation.requestBody?.content?.["application/json"];
+ const authored = mediaTypeExample(media);
+ if (authored !== undefined) return authored;
+
+ // Fall back to a minimal object built from the required properties.
+ const schema = media?.schema;
+ if (!schema) return undefined;
+ const resolved = deref(schema);
+ const required = resolved.required ?? [];
+ const props = resolved.properties ?? {};
+ const example = Object.fromEntries(
+ Object.entries(props)
+ .filter(([k]) => required.includes(k))
+ .slice(0, 4)
+ .map(([k, v]) => {
+ const t = v.type ?? (v.enum ? "enum" : "object");
+ const ex =
+ v.examples?.[0] ??
+ v.example ??
+ (t === "string" ? `"example_${k}"` : t === "boolean" ? false : 0);
+ return [k, ex];
+ })
+ );
+ return Object.keys(example).length ? example : undefined;
+ }
+
+ // A value to stand in for a parameter in a curl example: whatever the spec
+ // documents, else the first enum member, else the parameter's own name.
+ function parameterExample(param) {
+ return (
+ param.example ??
+ param.schema?.examples?.[0] ??
+ param.schema?.example ??
+ param.schema?.enum?.[0] ??
+ param.name
+ );
+ }
+
+ // Required query parameters belong in the example URL — without them the
+ // command as printed is a 400 rather than something a reader can paste.
+ // Optional ones are left out so the example shows the minimal call.
+ function requiredQueryString(parameters) {
+ const required = (parameters ?? [])
+ .map((p) => deref(p))
+ .filter((p) => p.in === "query" && p.required);
+ if (!required.length) return "";
+ const pairs = required.map(
+ (p) =>
+ `${encodeURIComponent(p.name)}=${encodeURIComponent(String(parameterExample(p)))}`
+ );
+ return `?${pairs.join("&")}`;
+ }
+
+ function curlExample(method, path, operation) {
+ const url = `${baseUrl}${path}${requiredQueryString(operation.parameters)}`;
+ const lines = [
+ `curl -X ${METHOD_LABELS[method] ?? method.toUpperCase()} '${url}'`,
+ ` -H 'Authorization: Bearer ${tokenPlaceholder}'`,
+ ];
+ if (method !== "get" && method !== "delete") {
+ lines.push(` -H 'Content-Type: application/json'`);
+ const example = requestExample(operation);
+ if (example !== undefined) {
+ lines.push(` -d '${JSON.stringify(example)}'`);
+ }
+ }
+ return lines.join(" \\\n");
+ }
+
+ function successExampleBlock(rawResponses) {
+ if (!rawResponses) return "";
+ const successCode = Object.keys(rawResponses).find((c) => /^2/.test(c));
+ if (!successCode) return "";
+
+ const rawResp = rawResponses[successCode];
+ const resp = rawResp.$ref ? resolveRef(rawResp.$ref) : rawResp;
+ const media = resp.content?.["application/json"];
+
+ // An example authored on the response wins outright — it shows the whole
+ // envelope, including any `meta`, exactly as the API returns it.
+ const authored = mediaTypeExample(media);
+ if (authored !== undefined) {
+ return exampleBlock(successCode, authored);
+ }
+
+ // Otherwise synthesize the envelope from the schema the endpoint narrows
+ // `data` to: allOf: [Envelope, { properties: { data: $ref Schema } }].
+ const schema = media?.schema;
+ if (!schema?.allOf) return "";
+
+ let dataExample = null;
+ let isList = false;
+
+ for (const s of schema.allOf) {
+ if (s.properties?.data?.$ref) {
+ const name = refName(s.properties.data.$ref);
+ dataExample = spec.components?.schemas?.[name]?.examples?.[0] ?? null;
+ break;
+ }
+ if (
+ s.properties?.data?.type === "array" &&
+ s.properties?.data?.items?.$ref
+ ) {
+ const name = refName(s.properties.data.items.$ref);
+ dataExample = spec.components?.schemas?.[name]?.examples?.[0] ?? null;
+ isList = true;
+ break;
+ }
+ }
+
+ if (!dataExample) return "";
+
+ const body = isList
+ ? { data: [dataExample], meta: { next_page_token: "eyJvZmZzZXQiOjI1fQ" } }
+ : { data: dataExample };
+
+ return exampleBlock(successCode, body);
+ }
+
+ function exampleBlock(code, body) {
+ return `\n**Example response \`${code}\`**\n\n\`\`\`json\n${JSON.stringify(body, null, 2)}\n\`\`\`\n`;
+ }
+
+ // -------------------------------------------------------------------------
+ // Endpoint sections
+ // -------------------------------------------------------------------------
+
+ function parametersSection(params) {
+ if (!params?.length) return "";
+ const rows = params
+ .map((p) => {
+ const resolved = deref(p);
+ const location = resolved.in ?? "";
+ const name = resolved.name ?? "";
+ const required = resolved.required ? "yes" : "no";
+ const type = resolved.schema?.type ?? "";
+ const desc = escapeMarkdown(resolved.description ?? "");
+ return `| \`${name}\` | ${location} | ${type} | ${required} | ${desc} |`;
+ })
+ .join("\n");
+ return `\n**Parameters**\n\n| Name | In | Type | Required | Description |\n|------|----|------|----------|-------------|\n${rows}\n`;
+ }
+
+ function requestBodySection(requestBody) {
+ if (!requestBody) return "";
+ const schema = requestBody.content?.["application/json"]?.schema;
+ if (!schema) return "";
+ const resolved = deref(schema);
+ const required = resolved.required ?? [];
+ const props = resolved.properties ?? {};
+ if (!Object.keys(props).length) return "";
+ const rows = Object.entries(props)
+ .map(([k, v]) => {
+ const req = required.includes(k) ? "yes" : "no";
+ const type = v.type ?? (v.$ref ? refName(v.$ref) : "object");
+ const desc = escapeMarkdown(v.description ?? "");
+ return `| \`${k}\` | ${type} | ${req} | ${desc} |`;
+ })
+ .join("\n");
+ return `\n**Request body**\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n${rows}\n`;
+ }
+
+ function responseSchemaName(schema) {
+ if (!schema) return "";
+ if (schema.$ref) return refName(schema.$ref);
+ // Common pattern: allOf: [Envelope, { properties: { data: $ref Schema } }]
+ if (schema.allOf) {
+ for (const s of schema.allOf) {
+ if (s.properties?.data?.$ref) return refName(s.properties.data.$ref);
+ // List responses: data.items.$ref
+ if (s.properties?.data?.items?.$ref)
+ return refName(s.properties.data.items.$ref) + "[]";
+ }
+ }
+ return "";
+ }
+
+ function responsesSection(rawResponses) {
+ if (!rawResponses) return "";
+ const rows = Object.entries(rawResponses)
+ .map(([code, rawResp]) => {
+ // Resolve top-level $ref (e.g. $ref: "#/components/responses/Unauthorized")
+ const resp = rawResp.$ref ? resolveRef(rawResp.$ref) : rawResp;
+ const desc = escapeMarkdown(resp.description ?? "");
+ const schema = resp.content?.["application/json"]?.schema;
+ const name = responseSchemaName(schema);
+ const schemaLink = name
+ ? `[\`${name}\`](${modelsHref}#model-${name.replace("[]", "").toLowerCase()})`
+ : "";
+ return `| \`${code}\` | ${desc} | ${schemaLink} |`;
+ })
+ .join("\n");
+ return `\n**Responses**\n\n| Status | Description | Schema |\n|--------|-------------|--------|\n${rows}\n`;
+ }
+
+ function endpointBlock(method, path, operation, headingLevel = "###") {
+ const anchor = `{#${operation.operationId}}`;
+ const title = operation.summary
+ ? operation.summary.replace(/\.$/, "")
+ : `${METHOD_LABELS[method]} ${path}`;
+ const heading = `${headingLevel} ${title} ${anchor}\n`;
+ const methodPath = `${methodSpan(method)} ${path}\n\n`;
+ const description =
+ operation.description &&
+ operation.description.trim() !== (operation.summary ?? "").trim()
+ ? `${operation.description.trim()}\n\n`
+ : "";
+ const params = parametersSection(operation.parameters);
+ const body = requestBodySection(deref(operation.requestBody ?? {}));
+ const responses = responsesSection(operation.responses);
+ const successExample = successExampleBlock(operation.responses);
+ const curl = `\n**Example request**\n\n\`\`\`sh\n${curlExample(method, path, operation)}\n\`\`\`\n`;
+ return [
+ heading,
+ methodPath,
+ description,
+ params,
+ body,
+ curl,
+ responses,
+ successExample,
+ ]
+ .filter(Boolean)
+ .join("");
+ }
+
+ // -------------------------------------------------------------------------
+ // Models
+ // -------------------------------------------------------------------------
+
+ function schemaBlock(name, schema) {
+ const anchor = `{#model-${name.toLowerCase()}}`;
+ const heading = `## ${name} ${anchor}\n`;
+ const desc = schema.description ? `${schema.description.trim()}\n\n` : "";
+
+ if (schema.enum) {
+ const descs = schema["x-enum-descriptions"] ?? [];
+ const hasDescs = descs.some(Boolean);
+ const values = schema.enum
+ .map((v, i) =>
+ hasDescs
+ ? `| \`${v}\` | ${escapeMarkdown(descs[i] ?? "")} |`
+ : `| \`${v}\` |`
+ )
+ .join("\n");
+ const header = hasDescs
+ ? `| Value | Description |\n|-------|-------------|`
+ : `| Value |\n|-------|`;
+ return `${heading}${desc}**Enum values**\n\n${header}\n${values}\n`;
+ }
+
+ const props =
+ schema.properties ?? schema.allOf?.find((s) => s.properties)?.properties;
+ if (!props || !Object.keys(props).length) {
+ const type = schema.type ?? (schema.allOf ? "object" : "");
+ return `${heading}${desc}${type ? `_Type: \`${type}\`_\n` : ""}\n`;
+ }
+
+ const required =
+ schema.required ?? schema.allOf?.find((s) => s.required)?.required ?? [];
+ const rows = Object.entries(props)
+ .map(([k, v]) => {
+ const req = required.includes(k) ? "yes" : "no";
+ const type =
+ v.type ?? (v.$ref ? refName(v.$ref) : v.allOf ? "object" : "object");
+ const d = escapeMarkdown(v.description ?? "");
+ return `| \`${k}\` | \`${type}\` | ${req} | ${d} |`;
+ })
+ .join("\n");
+
+ return `${heading}${desc}| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n${rows}\n`;
+ }
+
+ return { deref, endpointBlock, schemaBlock };
+}
+
+/**
+ * Renders per-tag Markdown pages plus a models page for one OpenAPI spec.
+ *
+ * @param {object} config
+ * @param {string} config.specPath Absolute path to the OpenAPI YAML.
+ * @param {string} config.outDir Absolute path to write pages into.
+ * @param {string} [config.baseUrl] Base URL for curl examples. Defaults to the spec's first server.
+ * @param {string} [config.tokenPlaceholder] Stand-in token in curl examples.
+ * @param {Array} config.tagPages [{ tag, file, frontmatter, groups? }]
+ * `groups` opts a tag into sub-resource sections: { order: string[], of: (path) => string }.
+ * @param {object} config.models { file, href, frontmatter, intro }
+ * `href` is the site-root-relative path of the models page, e.g.
+ * "/products/hosted/api/v1/models". It must be root-relative rather than a
+ * bare "models": these pages build to `/index.html` and are served
+ * from `/`, so a sibling-relative link would resolve one level too
+ * deep. The rehype base-path plugin prefixes the site base at build time.
+ */
+export function generateApiDocs(config) {
+ const {
+ specPath,
+ outDir,
+ tokenPlaceholder = "YOUR_TOKEN",
+ tagPages,
+ models,
+ } = config;
+
+ const spec = yaml.parse(readFileSync(specPath, "utf-8"));
+ const baseUrl = config.baseUrl ?? spec.servers?.[0]?.url ?? "";
+ const { deref, endpointBlock, schemaBlock } = createRenderer(spec, {
+ baseUrl,
+ tokenPlaceholder,
+ modelsHref: models.href,
+ });
+
+ // Collect operations by tag.
+ const byTag = {}; // tag → [{ method, path, operation }]
+ for (const [path, pathItem] of Object.entries(spec.paths ?? {})) {
+ for (const method of HTTP_METHODS) {
+ const op = pathItem[method];
+ if (!op) continue;
+ for (const tag of op.tags ?? ["Untagged"]) {
+ (byTag[tag] ??= []).push({ method, path, operation: op });
+ }
+ }
+ }
+
+ function generateTagPage(tag, items, { frontmatter, groups }) {
+ const tagInfo = spec.tags?.find((t) => t.name === tag) ?? {};
+ const intro = tagInfo.description ? `${tagInfo.description}\n\n` : "";
+
+ // Tags with many endpoints across sub-resources get an H2 per sub-resource
+ // and endpoints at H3; everything else is a flat list of H2 endpoints.
+ if (groups) {
+ const grouped = {};
+ for (const item of items) {
+ (grouped[groups.of(item.path)] ??= []).push(item);
+ }
+ const sorted = [
+ ...groups.order.filter((g) => grouped[g]),
+ ...Object.keys(grouped).filter((g) => !groups.order.includes(g)),
+ ];
+ const sections = sorted
+ .map((g) => {
+ const endpoints = grouped[g]
+ .map((item) =>
+ endpointBlock(item.method, item.path, item.operation, "###")
+ )
+ .join("\n---\n\n");
+ return `## ${g}\n\n${endpoints}`;
+ })
+ .join("\n\n");
+ return `${frontmatter}\n\n${intro}${sections}\n`;
+ }
+
+ const content = items
+ .map((item) => endpointBlock(item.method, item.path, item.operation, "##"))
+ .join("\n---\n\n");
+ return `${frontmatter}\n\n${intro}${content}\n`;
+ }
+
+ mkdirSync(outDir, { recursive: true });
+
+ for (const page of tagPages) {
+ const items = byTag[page.tag] ?? [];
+ if (!items.length) {
+ console.warn(`Warning: no endpoints found for tag "${page.tag}"`);
+ continue;
+ }
+ writeFileSync(
+ join(outDir, page.file),
+ generateTagPage(page.tag, items, page)
+ );
+ console.log(`Wrote ${page.file} (${items.length} endpoints)`);
+ }
+
+ const schemas = Object.entries(spec.components?.schemas ?? {});
+ const blocks = schemas
+ .map(([name, schema]) => schemaBlock(name, deref(schema)))
+ .join("\n---\n\n");
+ writeFileSync(
+ join(outDir, models.file),
+ `${models.frontmatter}\n\n${models.intro}\n\n${blocks}\n`
+ );
+ console.log(`Wrote ${models.file} (${schemas.length} schemas)`);
+}
diff --git a/site/dolt/package.json b/site/dolt/package.json
index bbe282c..233f4cd 100644
--- a/site/dolt/package.json
+++ b/site/dolt/package.json
@@ -7,7 +7,8 @@
"dev": "astro dev --port 4321",
"build": "node ../../scripts/check-content-frontmatter.mjs src/content && astro build && cp _redirects dist/_redirects && cp _headers dist/_headers && cp dist/docs/404.html dist/404.html && cp dist/docs/llms.txt dist/llms.txt && npx pagefind --site dist/docs",
"preview": "astro preview --port 4321",
- "generate-api-v2": "node ../../scripts/generate-api-v2.mjs"
+ "generate-api-v2": "node ../../scripts/generate-api-v2.mjs",
+ "generate-hosted-api-v1": "node ../../scripts/generate-hosted-api-v1.mjs"
},
"dependencies": {
"@astrojs/markdown-remark": "^7.2.2",
diff --git a/site/dolt/src/content/products/dolthub/api/v2/authentication.md b/site/dolt/src/content/products/dolthub/api/v2/authentication.md
index ecec084..ea69232 100644
--- a/site/dolt/src/content/products/dolthub/api/v2/authentication.md
+++ b/site/dolt/src/content/products/dolthub/api/v2/authentication.md
@@ -37,4 +37,4 @@ Most write operations and all operations on private databases require authentica
Endpoints that require authentication will return `401 Unauthorized` if no valid credential is supplied, and `403 Forbidden` if the credential is valid but lacks permission.
-See [Models → Problem](models#model-problem) for the error response format.
+See [Models → Problem](/products/dolthub/api/v2/models#model-problem) for the error response format.
diff --git a/site/dolt/src/content/products/dolthub/api/v2/database.md b/site/dolt/src/content/products/dolthub/api/v2/database.md
index a51f377..0699152 100644
--- a/site/dolt/src/content/products/dolthub/api/v2/database.md
+++ b/site/dolt/src/content/products/dolthub/api/v2/database.md
@@ -37,13 +37,13 @@ curl -X POST 'https://www.dolthub.com/api/v2/databases' \
| Status | Description | Schema |
|--------|-------------|--------|
-| `201` | The newly-created database. | [`Database`](models#model-database) |
-| `400` | The request was malformed or failed input validation. | [`Problem`](models#model-problem) |
-| `401` | Authentication credentials were missing or invalid. | [`Problem`](models#model-problem) |
-| `403` | Authenticated, but not permitted to perform this action. | [`Problem`](models#model-problem) |
-| `405` | The HTTP method is not supported for this resource. | [`Problem`](models#model-problem) |
-| `409` | The request conflicts with the current state of the resource (e.g. it already exists). | [`Problem`](models#model-problem) |
-| `500` | An unexpected server error occurred. | [`Problem`](models#model-problem) |
+| `201` | The newly-created database. | [`Database`](/products/dolthub/api/v2/models#model-database) |
+| `400` | The request was malformed or failed input validation. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `401` | Authentication credentials were missing or invalid. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `403` | Authenticated, but not permitted to perform this action. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `405` | The HTTP method is not supported for this resource. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `409` | The request conflicts with the current state of the resource (e.g. it already exists). | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `500` | An unexpected server error occurred. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
**Example response `201`**
@@ -88,12 +88,12 @@ curl -X GET 'https://www.dolthub.com/api/v2/databases/{owner}/{database}' \
| Status | Description | Schema |
|--------|-------------|--------|
-| `200` | The database's metadata. | [`Database`](models#model-database) |
-| `400` | The request was malformed or failed input validation. | [`Problem`](models#model-problem) |
-| `401` | Authentication credentials were missing or invalid. | [`Problem`](models#model-problem) |
-| `404` | The requested resource does not exist. | [`Problem`](models#model-problem) |
-| `405` | The HTTP method is not supported for this resource. | [`Problem`](models#model-problem) |
-| `500` | An unexpected server error occurred. | [`Problem`](models#model-problem) |
+| `200` | The database's metadata. | [`Database`](/products/dolthub/api/v2/models#model-database) |
+| `400` | The request was malformed or failed input validation. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `401` | Authentication credentials were missing or invalid. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `404` | The requested resource does not exist. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `405` | The HTTP method is not supported for this resource. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `500` | An unexpected server error occurred. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
**Example response `200`**
@@ -137,7 +137,7 @@ Public databases are readable without authentication; private databases require
**Example request**
```sh
-curl -X GET 'https://www.dolthub.com/api/v2/databases/{owner}/{database}/sql' \
+curl -X GET 'https://www.dolthub.com/api/v2/databases/{owner}/{database}/sql?ref=main&q=SELECT%20name%2C%20year%20FROM%20jails%20LIMIT%2010' \
-H 'Authorization: Bearer YOUR_TOKEN'
```
@@ -145,12 +145,12 @@ curl -X GET 'https://www.dolthub.com/api/v2/databases/{owner}/{database}/sql' \
| Status | Description | Schema |
|--------|-------------|--------|
-| `200` | The query result. SQL-level errors live in `status` + `message`. | [`QueryResult`](models#model-queryresult) |
-| `400` | The request was malformed or failed input validation. | [`Problem`](models#model-problem) |
-| `401` | Authentication credentials were missing or invalid. | [`Problem`](models#model-problem) |
-| `404` | The requested resource does not exist. | [`Problem`](models#model-problem) |
-| `405` | The HTTP method is not supported for this resource. | [`Problem`](models#model-problem) |
-| `500` | An unexpected server error occurred. | [`Problem`](models#model-problem) |
+| `200` | The query result. SQL-level errors live in `status` + `message`. | [`QueryResult`](/products/dolthub/api/v2/models#model-queryresult) |
+| `400` | The request was malformed or failed input validation. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `401` | Authentication credentials were missing or invalid. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `404` | The requested resource does not exist. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `405` | The HTTP method is not supported for this resource. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `500` | An unexpected server error occurred. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
**Example response `200`**
@@ -228,12 +228,12 @@ curl -X POST 'https://www.dolthub.com/api/v2/databases/{owner}/{database}/sql' \
| Status | Description | Schema |
|--------|-------------|--------|
-| `200` | The read query result. SQL-level errors live in `status` + `message`. | [`QueryResult`](models#model-queryresult) |
-| `400` | The request was malformed or failed input validation. | [`Problem`](models#model-problem) |
-| `401` | Authentication credentials were missing or invalid. | [`Problem`](models#model-problem) |
-| `404` | The requested resource does not exist. | [`Problem`](models#model-problem) |
-| `405` | The HTTP method is not supported for this resource. | [`Problem`](models#model-problem) |
-| `500` | An unexpected server error occurred. | [`Problem`](models#model-problem) |
+| `200` | The read query result. SQL-level errors live in `status` + `message`. | [`QueryResult`](/products/dolthub/api/v2/models#model-queryresult) |
+| `400` | The request was malformed or failed input validation. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `401` | Authentication credentials were missing or invalid. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `404` | The requested resource does not exist. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `405` | The HTTP method is not supported for this resource. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `500` | An unexpected server error occurred. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
**Example response `200`**
@@ -310,13 +310,13 @@ curl -X POST 'https://www.dolthub.com/api/v2/databases/{owner}/{database}/sql-wr
| Status | Description | Schema |
|--------|-------------|--------|
-| `202` | The write operation has been accepted and is queued. | [`OperationRef`](models#model-operationref) |
-| `400` | The request was malformed or failed input validation. | [`Problem`](models#model-problem) |
-| `401` | Authentication credentials were missing or invalid. | [`Problem`](models#model-problem) |
-| `403` | Authenticated, but not permitted to perform this action. | [`Problem`](models#model-problem) |
-| `404` | The requested resource does not exist. | [`Problem`](models#model-problem) |
-| `405` | The HTTP method is not supported for this resource. | [`Problem`](models#model-problem) |
-| `500` | An unexpected server error occurred. | [`Problem`](models#model-problem) |
+| `202` | The write operation has been accepted and is queued. | [`OperationRef`](/products/dolthub/api/v2/models#model-operationref) |
+| `400` | The request was malformed or failed input validation. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `401` | Authentication credentials were missing or invalid. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `403` | Authenticated, but not permitted to perform this action. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `404` | The requested resource does not exist. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `405` | The HTTP method is not supported for this resource. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `500` | An unexpected server error occurred. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
## Branches
@@ -346,12 +346,12 @@ curl -X GET 'https://www.dolthub.com/api/v2/databases/{owner}/{database}/branche
| Status | Description | Schema |
|--------|-------------|--------|
-| `200` | The database's branches. | [`Branch[]`](models#model-branch) |
-| `400` | The request was malformed or failed input validation. | [`Problem`](models#model-problem) |
-| `401` | Authentication credentials were missing or invalid. | [`Problem`](models#model-problem) |
-| `404` | The requested resource does not exist. | [`Problem`](models#model-problem) |
-| `405` | The HTTP method is not supported for this resource. | [`Problem`](models#model-problem) |
-| `500` | An unexpected server error occurred. | [`Problem`](models#model-problem) |
+| `200` | The database's branches. | [`Branch[]`](/products/dolthub/api/v2/models#model-branch) |
+| `400` | The request was malformed or failed input validation. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `401` | Authentication credentials were missing or invalid. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `404` | The requested resource does not exist. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `405` | The HTTP method is not supported for this resource. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `500` | An unexpected server error occurred. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
**Example response `200`**
@@ -405,14 +405,14 @@ curl -X POST 'https://www.dolthub.com/api/v2/databases/{owner}/{database}/branch
| Status | Description | Schema |
|--------|-------------|--------|
-| `201` | The newly-created branch. | [`Branch`](models#model-branch) |
-| `400` | The request was malformed or failed input validation. | [`Problem`](models#model-problem) |
-| `401` | Authentication credentials were missing or invalid. | [`Problem`](models#model-problem) |
-| `403` | Authenticated, but not permitted to perform this action. | [`Problem`](models#model-problem) |
-| `404` | The requested resource does not exist. | [`Problem`](models#model-problem) |
-| `405` | The HTTP method is not supported for this resource. | [`Problem`](models#model-problem) |
-| `409` | The request conflicts with the current state of the resource (e.g. it already exists). | [`Problem`](models#model-problem) |
-| `500` | An unexpected server error occurred. | [`Problem`](models#model-problem) |
+| `201` | The newly-created branch. | [`Branch`](/products/dolthub/api/v2/models#model-branch) |
+| `400` | The request was malformed or failed input validation. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `401` | Authentication credentials were missing or invalid. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `403` | Authenticated, but not permitted to perform this action. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `404` | The requested resource does not exist. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `405` | The HTTP method is not supported for this resource. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `409` | The request conflicts with the current state of the resource (e.g. it already exists). | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `500` | An unexpected server error occurred. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
**Example response `201`**
@@ -454,12 +454,12 @@ curl -X GET 'https://www.dolthub.com/api/v2/databases/{owner}/{database}/tags' \
| Status | Description | Schema |
|--------|-------------|--------|
-| `200` | The database's tags. | [`Tag[]`](models#model-tag) |
-| `400` | The request was malformed or failed input validation. | [`Problem`](models#model-problem) |
-| `401` | Authentication credentials were missing or invalid. | [`Problem`](models#model-problem) |
-| `404` | The requested resource does not exist. | [`Problem`](models#model-problem) |
-| `405` | The HTTP method is not supported for this resource. | [`Problem`](models#model-problem) |
-| `500` | An unexpected server error occurred. | [`Problem`](models#model-problem) |
+| `200` | The database's tags. | [`Tag[]`](/products/dolthub/api/v2/models#model-tag) |
+| `400` | The request was malformed or failed input validation. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `401` | Authentication credentials were missing or invalid. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `404` | The requested resource does not exist. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `405` | The HTTP method is not supported for this resource. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `500` | An unexpected server error occurred. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
**Example response `200`**
@@ -515,14 +515,14 @@ curl -X POST 'https://www.dolthub.com/api/v2/databases/{owner}/{database}/tags'
| Status | Description | Schema |
|--------|-------------|--------|
-| `201` | The newly-created tag. | [`Tag`](models#model-tag) |
-| `400` | The request was malformed or failed input validation. | [`Problem`](models#model-problem) |
-| `401` | Authentication credentials were missing or invalid. | [`Problem`](models#model-problem) |
-| `403` | Authenticated, but not permitted to perform this action. | [`Problem`](models#model-problem) |
-| `404` | The requested resource does not exist. | [`Problem`](models#model-problem) |
-| `405` | The HTTP method is not supported for this resource. | [`Problem`](models#model-problem) |
-| `409` | The request conflicts with the current state of the resource (e.g. it already exists). | [`Problem`](models#model-problem) |
-| `500` | An unexpected server error occurred. | [`Problem`](models#model-problem) |
+| `201` | The newly-created tag. | [`Tag`](/products/dolthub/api/v2/models#model-tag) |
+| `400` | The request was malformed or failed input validation. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `401` | Authentication credentials were missing or invalid. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `403` | Authenticated, but not permitted to perform this action. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `404` | The requested resource does not exist. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `405` | The HTTP method is not supported for this resource. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `409` | The request conflicts with the current state of the resource (e.g. it already exists). | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `500` | An unexpected server error occurred. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
**Example response `201`**
@@ -564,12 +564,12 @@ curl -X GET 'https://www.dolthub.com/api/v2/databases/{owner}/{database}/forks'
| Status | Description | Schema |
|--------|-------------|--------|
-| `200` | The database's direct fork children (immediate forks only). | [`DatabaseRef[]`](models#model-databaseref) |
-| `400` | The request was malformed or failed input validation. | [`Problem`](models#model-problem) |
-| `401` | Authentication credentials were missing or invalid. | [`Problem`](models#model-problem) |
-| `404` | The requested resource does not exist. | [`Problem`](models#model-problem) |
-| `405` | The HTTP method is not supported for this resource. | [`Problem`](models#model-problem) |
-| `500` | An unexpected server error occurred. | [`Problem`](models#model-problem) |
+| `200` | The database's direct fork children (immediate forks only). | [`DatabaseRef[]`](/products/dolthub/api/v2/models#model-databaseref) |
+| `400` | The request was malformed or failed input validation. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `401` | Authentication credentials were missing or invalid. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `404` | The requested resource does not exist. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `405` | The HTTP method is not supported for this resource. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `500` | An unexpected server error occurred. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
**Example response `200`**
@@ -621,14 +621,14 @@ curl -X POST 'https://www.dolthub.com/api/v2/databases/{owner}/{database}/forks'
| Status | Description | Schema |
|--------|-------------|--------|
-| `202` | The fork operation has been accepted and is queued. | [`OperationRef`](models#model-operationref) |
-| `400` | The request was malformed or failed input validation. | [`Problem`](models#model-problem) |
-| `401` | Authentication credentials were missing or invalid. | [`Problem`](models#model-problem) |
-| `403` | Authenticated, but not permitted to perform this action. | [`Problem`](models#model-problem) |
-| `404` | The requested resource does not exist. | [`Problem`](models#model-problem) |
-| `405` | The HTTP method is not supported for this resource. | [`Problem`](models#model-problem) |
-| `422` | The request was well-formed but semantically invalid. | [`Problem`](models#model-problem) |
-| `500` | An unexpected server error occurred. | [`Problem`](models#model-problem) |
+| `202` | The fork operation has been accepted and is queued. | [`OperationRef`](/products/dolthub/api/v2/models#model-operationref) |
+| `400` | The request was malformed or failed input validation. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `401` | Authentication credentials were missing or invalid. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `403` | Authenticated, but not permitted to perform this action. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `404` | The requested resource does not exist. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `405` | The HTTP method is not supported for this resource. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `422` | The request was well-formed but semantically invalid. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `500` | An unexpected server error occurred. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
## Releases
@@ -658,12 +658,12 @@ curl -X GET 'https://www.dolthub.com/api/v2/databases/{owner}/{database}/release
| Status | Description | Schema |
|--------|-------------|--------|
-| `200` | The database's releases. | [`Release[]`](models#model-release) |
-| `400` | The request was malformed or failed input validation. | [`Problem`](models#model-problem) |
-| `401` | Authentication credentials were missing or invalid. | [`Problem`](models#model-problem) |
-| `404` | The requested resource does not exist. | [`Problem`](models#model-problem) |
-| `405` | The HTTP method is not supported for this resource. | [`Problem`](models#model-problem) |
-| `500` | An unexpected server error occurred. | [`Problem`](models#model-problem) |
+| `200` | The database's releases. | [`Release[]`](/products/dolthub/api/v2/models#model-release) |
+| `400` | The request was malformed or failed input validation. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `401` | Authentication credentials were missing or invalid. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `404` | The requested resource does not exist. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `405` | The HTTP method is not supported for this resource. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `500` | An unexpected server error occurred. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
**Example response `200`**
@@ -723,14 +723,14 @@ curl -X POST 'https://www.dolthub.com/api/v2/databases/{owner}/{database}/releas
| Status | Description | Schema |
|--------|-------------|--------|
-| `201` | The newly-created release. | [`Release`](models#model-release) |
-| `400` | The request was malformed or failed input validation. | [`Problem`](models#model-problem) |
-| `401` | Authentication credentials were missing or invalid. | [`Problem`](models#model-problem) |
-| `403` | Authenticated, but not permitted to perform this action. | [`Problem`](models#model-problem) |
-| `404` | The requested resource does not exist. | [`Problem`](models#model-problem) |
-| `405` | The HTTP method is not supported for this resource. | [`Problem`](models#model-problem) |
-| `409` | The request conflicts with the current state of the resource (e.g. it already exists). | [`Problem`](models#model-problem) |
-| `500` | An unexpected server error occurred. | [`Problem`](models#model-problem) |
+| `201` | The newly-created release. | [`Release`](/products/dolthub/api/v2/models#model-release) |
+| `400` | The request was malformed or failed input validation. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `401` | Authentication credentials were missing or invalid. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `403` | Authenticated, but not permitted to perform this action. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `404` | The requested resource does not exist. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `405` | The HTTP method is not supported for this resource. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `409` | The request conflicts with the current state of the resource (e.g. it already exists). | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `500` | An unexpected server error occurred. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
**Example response `201`**
@@ -775,12 +775,12 @@ curl -X GET 'https://www.dolthub.com/api/v2/databases/{owner}/{database}/pulls'
| Status | Description | Schema |
|--------|-------------|--------|
-| `200` | The database's pull requests. | [`PullSummary[]`](models#model-pullsummary) |
-| `400` | The request was malformed or failed input validation. | [`Problem`](models#model-problem) |
-| `401` | Authentication credentials were missing or invalid. | [`Problem`](models#model-problem) |
-| `404` | The requested resource does not exist. | [`Problem`](models#model-problem) |
-| `405` | The HTTP method is not supported for this resource. | [`Problem`](models#model-problem) |
-| `500` | An unexpected server error occurred. | [`Problem`](models#model-problem) |
+| `200` | The database's pull requests. | [`PullSummary[]`](/products/dolthub/api/v2/models#model-pullsummary) |
+| `400` | The request was malformed or failed input validation. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `401` | Authentication credentials were missing or invalid. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `404` | The requested resource does not exist. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `405` | The HTTP method is not supported for this resource. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `500` | An unexpected server error occurred. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
**Example response `200`**
@@ -839,14 +839,14 @@ curl -X POST 'https://www.dolthub.com/api/v2/databases/{owner}/{database}/pulls'
| Status | Description | Schema |
|--------|-------------|--------|
-| `201` | The newly-created pull request. | [`Pull`](models#model-pull) |
-| `400` | The request was malformed or failed input validation. | [`Problem`](models#model-problem) |
-| `401` | Authentication credentials were missing or invalid. | [`Problem`](models#model-problem) |
-| `403` | Authenticated, but not permitted to perform this action. | [`Problem`](models#model-problem) |
-| `404` | The requested resource does not exist. | [`Problem`](models#model-problem) |
-| `405` | The HTTP method is not supported for this resource. | [`Problem`](models#model-problem) |
-| `409` | The request conflicts with the current state of the resource (e.g. it already exists). | [`Problem`](models#model-problem) |
-| `500` | An unexpected server error occurred. | [`Problem`](models#model-problem) |
+| `201` | The newly-created pull request. | [`Pull`](/products/dolthub/api/v2/models#model-pull) |
+| `400` | The request was malformed or failed input validation. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `401` | Authentication credentials were missing or invalid. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `403` | Authenticated, but not permitted to perform this action. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `404` | The requested resource does not exist. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `405` | The HTTP method is not supported for this resource. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `409` | The request conflicts with the current state of the resource (e.g. it already exists). | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `500` | An unexpected server error occurred. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
**Example response `201`**
@@ -904,12 +904,12 @@ curl -X GET 'https://www.dolthub.com/api/v2/databases/{owner}/{database}/pulls/{
| Status | Description | Schema |
|--------|-------------|--------|
-| `200` | The requested pull request. | [`Pull`](models#model-pull) |
-| `400` | The request was malformed or failed input validation. | [`Problem`](models#model-problem) |
-| `401` | Authentication credentials were missing or invalid. | [`Problem`](models#model-problem) |
-| `404` | The requested resource does not exist. | [`Problem`](models#model-problem) |
-| `405` | The HTTP method is not supported for this resource. | [`Problem`](models#model-problem) |
-| `500` | An unexpected server error occurred. | [`Problem`](models#model-problem) |
+| `200` | The requested pull request. | [`Pull`](/products/dolthub/api/v2/models#model-pull) |
+| `400` | The request was malformed or failed input validation. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `401` | Authentication credentials were missing or invalid. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `404` | The requested resource does not exist. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `405` | The HTTP method is not supported for this resource. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `500` | An unexpected server error occurred. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
**Example response `200`**
@@ -976,13 +976,13 @@ curl -X PATCH 'https://www.dolthub.com/api/v2/databases/{owner}/{database}/pulls
| Status | Description | Schema |
|--------|-------------|--------|
-| `200` | The updated pull request. | [`Pull`](models#model-pull) |
-| `400` | The request was malformed or failed input validation. | [`Problem`](models#model-problem) |
-| `401` | Authentication credentials were missing or invalid. | [`Problem`](models#model-problem) |
-| `403` | Authenticated, but not permitted to perform this action. | [`Problem`](models#model-problem) |
-| `404` | The requested resource does not exist. | [`Problem`](models#model-problem) |
-| `405` | The HTTP method is not supported for this resource. | [`Problem`](models#model-problem) |
-| `500` | An unexpected server error occurred. | [`Problem`](models#model-problem) |
+| `200` | The updated pull request. | [`Pull`](/products/dolthub/api/v2/models#model-pull) |
+| `400` | The request was malformed or failed input validation. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `401` | Authentication credentials were missing or invalid. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `403` | Authenticated, but not permitted to perform this action. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `404` | The requested resource does not exist. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `405` | The HTTP method is not supported for this resource. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `500` | An unexpected server error occurred. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
**Example response `200`**
@@ -1040,12 +1040,12 @@ curl -X GET 'https://www.dolthub.com/api/v2/databases/{owner}/{database}/pulls/{
| Status | Description | Schema |
|--------|-------------|--------|
-| `200` | The pull request's comments. | [`PullComment[]`](models#model-pullcomment) |
-| `400` | The request was malformed or failed input validation. | [`Problem`](models#model-problem) |
-| `401` | Authentication credentials were missing or invalid. | [`Problem`](models#model-problem) |
-| `404` | The requested resource does not exist. | [`Problem`](models#model-problem) |
-| `405` | The HTTP method is not supported for this resource. | [`Problem`](models#model-problem) |
-| `500` | An unexpected server error occurred. | [`Problem`](models#model-problem) |
+| `200` | The pull request's comments. | [`PullComment[]`](/products/dolthub/api/v2/models#model-pullcomment) |
+| `400` | The request was malformed or failed input validation. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `401` | Authentication credentials were missing or invalid. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `404` | The requested resource does not exist. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `405` | The HTTP method is not supported for this resource. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `500` | An unexpected server error occurred. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
**Example response `200`**
@@ -1101,13 +1101,13 @@ curl -X POST 'https://www.dolthub.com/api/v2/databases/{owner}/{database}/pulls/
| Status | Description | Schema |
|--------|-------------|--------|
-| `201` | The newly-created comment. | [`PullComment`](models#model-pullcomment) |
-| `400` | The request was malformed or failed input validation. | [`Problem`](models#model-problem) |
-| `401` | Authentication credentials were missing or invalid. | [`Problem`](models#model-problem) |
-| `403` | Authenticated, but not permitted to perform this action. | [`Problem`](models#model-problem) |
-| `404` | The requested resource does not exist. | [`Problem`](models#model-problem) |
-| `405` | The HTTP method is not supported for this resource. | [`Problem`](models#model-problem) |
-| `500` | An unexpected server error occurred. | [`Problem`](models#model-problem) |
+| `201` | The newly-created comment. | [`PullComment`](/products/dolthub/api/v2/models#model-pullcomment) |
+| `400` | The request was malformed or failed input validation. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `401` | Authentication credentials were missing or invalid. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `403` | Authenticated, but not permitted to perform this action. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `404` | The requested resource does not exist. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `405` | The HTTP method is not supported for this resource. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `500` | An unexpected server error occurred. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
**Example response `201`**
@@ -1151,14 +1151,14 @@ curl -X POST 'https://www.dolthub.com/api/v2/databases/{owner}/{database}/pulls/
| Status | Description | Schema |
|--------|-------------|--------|
-| `202` | The merge operation has been accepted and is queued. | [`OperationRef`](models#model-operationref) |
-| `400` | The request was malformed or failed input validation. | [`Problem`](models#model-problem) |
-| `401` | Authentication credentials were missing or invalid. | [`Problem`](models#model-problem) |
-| `403` | Authenticated, but not permitted to perform this action. | [`Problem`](models#model-problem) |
-| `404` | The requested resource does not exist. | [`Problem`](models#model-problem) |
-| `405` | The HTTP method is not supported for this resource. | [`Problem`](models#model-problem) |
-| `422` | The request was well-formed but semantically invalid. | [`Problem`](models#model-problem) |
-| `500` | An unexpected server error occurred. | [`Problem`](models#model-problem) |
+| `202` | The merge operation has been accepted and is queued. | [`OperationRef`](/products/dolthub/api/v2/models#model-operationref) |
+| `400` | The request was malformed or failed input validation. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `401` | Authentication credentials were missing or invalid. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `403` | Authenticated, but not permitted to perform this action. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `404` | The requested resource does not exist. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `405` | The HTTP method is not supported for this resource. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `422` | The request was well-formed but semantically invalid. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `500` | An unexpected server error occurred. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
## Imports
@@ -1197,13 +1197,13 @@ curl -X POST 'https://www.dolthub.com/api/v2/databases/{owner}/{database}/import
| Status | Description | Schema |
|--------|-------------|--------|
-| `201` | The multipart upload session. | [`ImportUpload`](models#model-importupload) |
-| `400` | The request was malformed or failed input validation. | [`Problem`](models#model-problem) |
-| `401` | Authentication credentials were missing or invalid. | [`Problem`](models#model-problem) |
-| `403` | Authenticated, but not permitted to perform this action. | [`Problem`](models#model-problem) |
-| `404` | The requested resource does not exist. | [`Problem`](models#model-problem) |
-| `405` | The HTTP method is not supported for this resource. | [`Problem`](models#model-problem) |
-| `500` | An unexpected server error occurred. | [`Problem`](models#model-problem) |
+| `201` | The multipart upload session. | [`ImportUpload`](/products/dolthub/api/v2/models#model-importupload) |
+| `400` | The request was malformed or failed input validation. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `401` | Authentication credentials were missing or invalid. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `403` | Authenticated, but not permitted to perform this action. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `404` | The requested resource does not exist. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `405` | The HTTP method is not supported for this resource. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `500` | An unexpected server error occurred. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
---
@@ -1252,11 +1252,11 @@ curl -X POST 'https://www.dolthub.com/api/v2/databases/{owner}/{database}/import
| Status | Description | Schema |
|--------|-------------|--------|
-| `202` | The import operation has been accepted and is queued. | [`OperationRef`](models#model-operationref) |
-| `400` | The request was malformed or failed input validation. | [`Problem`](models#model-problem) |
-| `401` | Authentication credentials were missing or invalid. | [`Problem`](models#model-problem) |
-| `403` | Authenticated, but not permitted to perform this action. | [`Problem`](models#model-problem) |
-| `404` | The requested resource does not exist. | [`Problem`](models#model-problem) |
-| `405` | The HTTP method is not supported for this resource. | [`Problem`](models#model-problem) |
-| `500` | An unexpected server error occurred. | [`Problem`](models#model-problem) |
+| `202` | The import operation has been accepted and is queued. | [`OperationRef`](/products/dolthub/api/v2/models#model-operationref) |
+| `400` | The request was malformed or failed input validation. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `401` | Authentication credentials were missing or invalid. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `403` | Authenticated, but not permitted to perform this action. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `404` | The requested resource does not exist. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `405` | The HTTP method is not supported for this resource. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `500` | An unexpected server error occurred. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
diff --git a/site/dolt/src/content/products/dolthub/api/v2/migration.md b/site/dolt/src/content/products/dolthub/api/v2/migration.md
index a21f328..fad5426 100644
--- a/site/dolt/src/content/products/dolthub/api/v2/migration.md
+++ b/site/dolt/src/content/products/dolthub/api/v2/migration.md
@@ -5,7 +5,7 @@ description: How to migrate your integrations from the DoltHub v1alpha1 API to v
# Migrating from v1alpha1
-This page covers the mechanical changes needed to move an existing v1alpha1 integration to v2. Read it alongside the [v2 overview](../v2) and the per-resource pages.
+This page covers the mechanical changes needed to move an existing v1alpha1 integration to v2. Read it alongside the [v2 overview](/products/dolthub/api/v2) and the per-resource pages.
## 1. Base URL
@@ -54,7 +54,7 @@ v1alpha1 responses are flat and ad-hoc — each endpoint has its own top-level s
## 3. Error model
-v1alpha1 error shapes vary by endpoint. v2 uses [RFC 9457 Problem Details](https://www.rfc-editor.org/rfc/rfc9457) for every non-2xx response. See [Models → Problem](models#model-problem).
+v1alpha1 error shapes vary by endpoint. v2 uses [RFC 9457 Problem Details](https://www.rfc-editor.org/rfc/rfc9457) for every non-2xx response. See [Models → Problem](/products/dolthub/api/v2/models#model-problem).
```json
{
@@ -104,7 +104,7 @@ v2 uses a single unified protocol: any async mutation returns `202` with an `Ope
}
```
-Poll `GET /api/v2/operations/{operation_id}` until `status` is `succeeded` or `failed`. See [Operations](operations#getOperation).
+Poll `GET /api/v2/operations/{operation_id}` until `status` is `succeeded` or `failed`. See [Operations](/products/dolthub/api/v2/operations#getOperation).
```sh
curl 'https://www.dolthub.com/api/v2/operations/owners/dolthub/repos/us-jails/jobs/abc123' \
@@ -117,29 +117,29 @@ curl 'https://www.dolthub.com/api/v2/operations/owners/dolthub/repos/us-jails/jo
| v1alpha1 | v2 |
|---|---|
-| `GET /user` | [`GET /user`](user#getCurrentUser) |
-| `POST /database` | [`POST /databases`](database#createDatabase) |
-| `GET /{owner}/{database}?q=` | [`GET /databases/{owner}/{database}/sql?q=`](database#runSqlReadQuery) |
-| `GET /{owner}/{database}/{ref}?q=` | [`GET /databases/{owner}/{database}/sql?q=&ref=`](database#runSqlReadQuery) |
-| `POST /{owner}/{database}/write/{from_branch}/{to_branch}` | [`POST /databases/{owner}/{database}/sql-writes`](database#runSqlWriteQuery) |
-| `GET /{owner}/{database}/write` | Poll [`GET /operations/{id}`](operations#getOperation) |
-| `GET /{owner}/{database}/forks` | [`GET /databases/{owner}/{database}/forks`](database#listForks) |
-| `GET /{owner}/{database}/branches` | [`GET /databases/{owner}/{database}/branches`](database#listBranches) |
-| `POST /{owner}/{database}/branches` | [`POST /databases/{owner}/{database}/branches`](database#createBranch) |
-| `GET /{owner}/{database}/pulls` | [`GET /databases/{owner}/{database}/pulls`](database#listPulls) |
-| `POST /{owner}/{database}/pulls` | [`POST /databases/{owner}/{database}/pulls`](database#createPull) |
-| `GET /{owner}/{database}/pulls/{id}` | [`GET /databases/{owner}/{database}/pulls/{pull_number}`](database#getPull) |
-| `PATCH /{owner}/{database}/pulls/{id}` | [`PATCH /databases/{owner}/{database}/pulls/{pull_number}`](database#updatePull) |
-| `POST /{owner}/{database}/pulls/{id}/comments` | [`POST /databases/{owner}/{database}/pulls/{pull_number}/comments`](database#createPullComment) |
-| `POST /{owner}/{database}/pulls/{id}/merge` | [`POST /databases/{owner}/{database}/pulls/{pull_number}/merge`](database#mergePull) |
-| `GET /{owner}/{database}/pulls/{id}/merge` | Poll [`GET /operations/{id}`](operations#getOperation) |
-| `GET /{owner}/{database}/releases` | [`GET /databases/{owner}/{database}/releases`](database#listReleases) |
-| `POST /{owner}/{database}/releases` | [`POST /databases/{owner}/{database}/releases`](database#createRelease) |
-| `GET /{owner}/{database}/tags` | [`GET /databases/{owner}/{database}/tags`](database#listTags) |
-| `POST /{owner}/{database}/tags` | [`POST /databases/{owner}/{database}/tags`](database#createTag) |
-| `POST /{owner}/{database}/upload` | [`POST .../imports/uploads`](database#createImportUpload) then [`POST .../imports`](database#createImport) |
-| `GET /{owner}/{database}/upload` | Poll [`GET /operations/{id}`](operations#getOperation) |
-| `POST /fork` | [`POST /databases/{owner}/{database}/forks`](database#createFork) |
-| `GET /fork` | Poll [`GET /operations/{id}`](operations#getOperation) |
-| `GET /{owner}/{database}/jobs` | [`GET /databases/{owner}/{database}/operations`](operations#listOperations) |
-| `GET /users/{username}/operations` | [`GET /databases/{owner}/{database}/operations`](operations#listOperations) |
+| `GET /user` | [`GET /user`](/products/dolthub/api/v2/user#getCurrentUser) |
+| `POST /database` | [`POST /databases`](/products/dolthub/api/v2/database#createDatabase) |
+| `GET /{owner}/{database}?q=` | [`GET /databases/{owner}/{database}/sql?q=`](/products/dolthub/api/v2/database#runSqlReadQuery) |
+| `GET /{owner}/{database}/{ref}?q=` | [`GET /databases/{owner}/{database}/sql?q=&ref=`](/products/dolthub/api/v2/database#runSqlReadQuery) |
+| `POST /{owner}/{database}/write/{from_branch}/{to_branch}` | [`POST /databases/{owner}/{database}/sql-writes`](/products/dolthub/api/v2/database#runSqlWriteQuery) |
+| `GET /{owner}/{database}/write` | Poll [`GET /operations/{id}`](/products/dolthub/api/v2/operations#getOperation) |
+| `GET /{owner}/{database}/forks` | [`GET /databases/{owner}/{database}/forks`](/products/dolthub/api/v2/database#listForks) |
+| `GET /{owner}/{database}/branches` | [`GET /databases/{owner}/{database}/branches`](/products/dolthub/api/v2/database#listBranches) |
+| `POST /{owner}/{database}/branches` | [`POST /databases/{owner}/{database}/branches`](/products/dolthub/api/v2/database#createBranch) |
+| `GET /{owner}/{database}/pulls` | [`GET /databases/{owner}/{database}/pulls`](/products/dolthub/api/v2/database#listPulls) |
+| `POST /{owner}/{database}/pulls` | [`POST /databases/{owner}/{database}/pulls`](/products/dolthub/api/v2/database#createPull) |
+| `GET /{owner}/{database}/pulls/{id}` | [`GET /databases/{owner}/{database}/pulls/{pull_number}`](/products/dolthub/api/v2/database#getPull) |
+| `PATCH /{owner}/{database}/pulls/{id}` | [`PATCH /databases/{owner}/{database}/pulls/{pull_number}`](/products/dolthub/api/v2/database#updatePull) |
+| `POST /{owner}/{database}/pulls/{id}/comments` | [`POST /databases/{owner}/{database}/pulls/{pull_number}/comments`](/products/dolthub/api/v2/database#createPullComment) |
+| `POST /{owner}/{database}/pulls/{id}/merge` | [`POST /databases/{owner}/{database}/pulls/{pull_number}/merge`](/products/dolthub/api/v2/database#mergePull) |
+| `GET /{owner}/{database}/pulls/{id}/merge` | Poll [`GET /operations/{id}`](/products/dolthub/api/v2/operations#getOperation) |
+| `GET /{owner}/{database}/releases` | [`GET /databases/{owner}/{database}/releases`](/products/dolthub/api/v2/database#listReleases) |
+| `POST /{owner}/{database}/releases` | [`POST /databases/{owner}/{database}/releases`](/products/dolthub/api/v2/database#createRelease) |
+| `GET /{owner}/{database}/tags` | [`GET /databases/{owner}/{database}/tags`](/products/dolthub/api/v2/database#listTags) |
+| `POST /{owner}/{database}/tags` | [`POST /databases/{owner}/{database}/tags`](/products/dolthub/api/v2/database#createTag) |
+| `POST /{owner}/{database}/upload` | [`POST .../imports/uploads`](/products/dolthub/api/v2/database#createImportUpload) then [`POST .../imports`](/products/dolthub/api/v2/database#createImport) |
+| `GET /{owner}/{database}/upload` | Poll [`GET /operations/{id}`](/products/dolthub/api/v2/operations#getOperation) |
+| `POST /fork` | [`POST /databases/{owner}/{database}/forks`](/products/dolthub/api/v2/database#createFork) |
+| `GET /fork` | Poll [`GET /operations/{id}`](/products/dolthub/api/v2/operations#getOperation) |
+| `GET /{owner}/{database}/jobs` | [`GET /databases/{owner}/{database}/operations`](/products/dolthub/api/v2/operations#listOperations) |
+| `GET /users/{username}/operations` | [`GET /databases/{owner}/{database}/operations`](/products/dolthub/api/v2/operations#listOperations) |
diff --git a/site/dolt/src/content/products/dolthub/api/v2/operations.md b/site/dolt/src/content/products/dolthub/api/v2/operations.md
index 9b40b69..0cc891b 100644
--- a/site/dolt/src/content/products/dolthub/api/v2/operations.md
+++ b/site/dolt/src/content/products/dolthub/api/v2/operations.md
@@ -32,12 +32,12 @@ curl -X GET 'https://www.dolthub.com/api/v2/databases/{owner}/{database}/operati
| Status | Description | Schema |
|--------|-------------|--------|
-| `200` | The database's async operations. | [`Operation[]`](models#model-operation) |
-| `400` | The request was malformed or failed input validation. | [`Problem`](models#model-problem) |
-| `401` | Authentication credentials were missing or invalid. | [`Problem`](models#model-problem) |
-| `404` | The requested resource does not exist. | [`Problem`](models#model-problem) |
-| `405` | The HTTP method is not supported for this resource. | [`Problem`](models#model-problem) |
-| `500` | An unexpected server error occurred. | [`Problem`](models#model-problem) |
+| `200` | The database's async operations. | [`Operation[]`](/products/dolthub/api/v2/models#model-operation) |
+| `400` | The request was malformed or failed input validation. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `401` | Authentication credentials were missing or invalid. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `404` | The requested resource does not exist. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `405` | The HTTP method is not supported for this resource. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `500` | An unexpected server error occurred. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
---
@@ -64,10 +64,10 @@ curl -X GET 'https://www.dolthub.com/api/v2/operations/{operation_id}' \
| Status | Description | Schema |
|--------|-------------|--------|
-| `200` | The current state of the operation. | [`Operation`](models#model-operation) |
-| `401` | Authentication credentials were missing or invalid. | [`Problem`](models#model-problem) |
-| `403` | Authenticated, but not permitted to perform this action. | [`Problem`](models#model-problem) |
-| `404` | The requested resource does not exist. | [`Problem`](models#model-problem) |
-| `405` | The HTTP method is not supported for this resource. | [`Problem`](models#model-problem) |
-| `500` | An unexpected server error occurred. | [`Problem`](models#model-problem) |
+| `200` | The current state of the operation. | [`Operation`](/products/dolthub/api/v2/models#model-operation) |
+| `401` | Authentication credentials were missing or invalid. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `403` | Authenticated, but not permitted to perform this action. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `404` | The requested resource does not exist. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `405` | The HTTP method is not supported for this resource. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `500` | An unexpected server error occurred. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
diff --git a/site/dolt/src/content/products/dolthub/api/v2/user.md b/site/dolt/src/content/products/dolthub/api/v2/user.md
index 62c0481..d204b4f 100644
--- a/site/dolt/src/content/products/dolthub/api/v2/user.md
+++ b/site/dolt/src/content/products/dolthub/api/v2/user.md
@@ -24,10 +24,10 @@ curl -X GET 'https://www.dolthub.com/api/v2/user' \
| Status | Description | Schema |
|--------|-------------|--------|
-| `200` | The authenticated user's profile. | [`User`](models#model-user) |
-| `401` | Authentication credentials were missing or invalid. | [`Problem`](models#model-problem) |
-| `405` | The HTTP method is not supported for this resource. | [`Problem`](models#model-problem) |
-| `500` | An unexpected server error occurred. | [`Problem`](models#model-problem) |
+| `200` | The authenticated user's profile. | [`User`](/products/dolthub/api/v2/models#model-user) |
+| `401` | Authentication credentials were missing or invalid. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `405` | The HTTP method is not supported for this resource. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
+| `500` | An unexpected server error occurred. | [`Problem`](/products/dolthub/api/v2/models#model-problem) |
**Example response `200`**
diff --git a/site/dolt/src/content/products/hosted/api/README.md b/site/dolt/src/content/products/hosted/api/README.md
new file mode 100644
index 0000000..989f9ad
--- /dev/null
+++ b/site/dolt/src/content/products/hosted/api/README.md
@@ -0,0 +1,22 @@
+---
+title: "Hosted Dolt API"
+description: Programmatic access to your Hosted Dolt deployments.
+---
+
+# Hosted Dolt API
+
+Hosted Dolt exposes an HTTP API for managing deployments programmatically — creating them, listing them, and reading their configuration and state from scripts, CI, or your own tooling.
+
+## REST API
+
+- **[v1 API](/products/hosted/api/v1)** — the current generation. An explicit, versioned, OpenAPI-defined contract with consistent HTTP semantics, a single [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) error model, and a uniform response envelope. Start here.
+
+The conventions are deliberately the same as the [DoltHub v2 API](/products/dolthub/api/v2): the same error body, the same success envelope, and the same cursor pagination. If you already integrate with one, the other should feel familiar.
+
+## Scope
+
+The v1 API covers the **control plane** — the deployments themselves. Querying the data *inside* a deployment is not part of it: every deployment exposes a SQL endpoint that you connect to directly with your database credentials, exactly as you would any MySQL or Postgres server. See [Getting Started](/products/hosted/getting-started) for how to connect.
+
+Database credentials are never returned by this API. Reading a deployment tells you its configuration and state, never its secrets.
+
+> **Note:** please send requests to `https://hosted.doltdb.com`.
diff --git a/site/dolt/src/content/products/hosted/api/v1/README.md b/site/dolt/src/content/products/hosted/api/v1/README.md
new file mode 100644
index 0000000..6102f9f
--- /dev/null
+++ b/site/dolt/src/content/products/hosted/api/v1/README.md
@@ -0,0 +1,101 @@
+---
+title: "Hosted API v1"
+description: The Hosted Dolt v1 API — an explicit, versioned, OpenAPI-defined contract for deployments.
+---
+
+# Hosted API v1
+
+_API version: v1_
+
+The v1 API is the public HTTP surface for the Hosted Dolt control plane. Every endpoint lives under `https://hosted.doltdb.com/api/v1/`.
+
+It is an OpenAPI-defined contract, and commits to:
+
+- Consistent HTTP semantics (correct status codes, idempotent GETs, `202` for work that continues after the response)
+- A single error model ([RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) problem details) — see [Problem](/products/hosted/api/v1/models#model-problem)
+- A uniform success [Envelope](/products/hosted/api/v1/models#model-envelope) wrapping every response
+- Cursor pagination on list endpoints
+
+**Scope.** v1 covers the control plane only. Querying the data inside a deployment is not part of this API — connect to the deployment's SQL endpoint directly with your database credentials.
+
+## Authentication
+
+Every endpoint requires a Hosted API token, sent as a bearer token:
+
+```sh
+curl 'https://hosted.doltdb.com/api/v1/user' \
+ -H 'Authorization: Bearer hsat.v1.YOUR_TOKEN_HERE'
+```
+
+See [Authentication](/products/hosted/api/v1/authentication) for how to create and manage tokens.
+
+## All endpoints
+
+### User
+
+| Method | Path | What it does |
+|--------|------|--------------|
+| **GET** | `/api/v1/user` | [Get the authenticated user](/products/hosted/api/v1/user#getCurrentUser) |
+
+### Deployment
+
+| Method | Path | What it does |
+|--------|------|--------------|
+| **GET** | `/api/v1/deployment-options` | [List the options a deployment can be created with](/products/hosted/api/v1/deployment#getDeploymentOptions) |
+| **POST** | `/api/v1/deployments` | [Create a deployment](/products/hosted/api/v1/deployment#createDeployment) |
+| **GET** | `/api/v1/deployments/{owner}` | [List an owner's deployments](/products/hosted/api/v1/deployment#listDeployments) |
+| **GET** | `/api/v1/deployments/{owner}/{deployment}` | [Get a deployment](/products/hosted/api/v1/deployment#getDeployment) |
+| **GET** | `/api/v1/deployments/{owner}/{deployment}/instances` | [List a deployment's instances](/products/hosted/api/v1/deployment#listDeploymentInstances) |
+
+## Response shape
+
+Every `2xx` response body is an [Envelope](/products/hosted/api/v1/models#model-envelope): the resource, or an array of resources, under `data`, with optional `meta`.
+
+```json
+{
+ "data": { "owner": "acme", "name": "analytics", "state": "started" }
+}
+```
+
+List endpoints put the pagination cursor in `meta`:
+
+```json
+{
+ "data": [ { "owner": "acme", "name": "analytics" } ],
+ "meta": { "next_page_token": "eyJvZmZzZXQiOjI1fQ" }
+}
+```
+
+When `meta.next_page_token` is present, pass it back as the `page_token` query parameter to fetch the next page. On the last page `meta` is omitted entirely, so checking whether the token is present is all a client needs — it is never returned present but empty.
+
+## Errors
+
+Every non-`2xx` response is a [Problem](/products/hosted/api/v1/models#model-problem) with content type `application/problem+json`:
+
+```json
+{
+ "type": "https://docs.dolthub.com/products/hosted/api/v1/models/#model-errorcode",
+ "title": "Not found",
+ "status": 404,
+ "detail": "Deployment 'analytics' does not exist for owner 'acme'",
+ "instance": "/api/v1/deployments/acme/analytics",
+ "code": "NOT_FOUND",
+ "request_id": "req_01HZX9P7Q5N2M8"
+}
+```
+
+Branch on `code` — a stable, machine-readable [ErrorCode](/products/hosted/api/v1/models#model-errorcode) — never on the human-readable `title` or `detail`, which may be reworded at any time.
+
+Every response, including successful ones, carries an `x-request-id` header, echoed in the body as `request_id` on errors. Include it when contacting support so a request can be traced end to end.
+
+## Long-running work
+
+Creating a deployment returns `202 Accepted` with the deployment in its `starting` state — provisioning continues after the response. Poll [Get a deployment](/products/hosted/api/v1/deployment#getDeployment) until `state` becomes `started`.
+
+Deployment names are unique within an owner, which makes creates idempotent by name: retrying after an ambiguous failure returns `409 Conflict` rather than provisioning a second deployment.
+
+> **Creating a deployment incurs cost.**
+
+## Stability
+
+v1 is additive. New endpoints, new optional request fields, new response fields, and new `ErrorCode` values may be introduced within v1. Renaming or removing a field, or changing an existing one's meaning, requires a new major version.
diff --git a/site/dolt/src/content/products/hosted/api/v1/authentication.md b/site/dolt/src/content/products/hosted/api/v1/authentication.md
new file mode 100644
index 0000000..f2650cd
--- /dev/null
+++ b/site/dolt/src/content/products/hosted/api/v1/authentication.md
@@ -0,0 +1,59 @@
+---
+title: "Authentication"
+description: How to authenticate requests to the Hosted Dolt v1 API.
+---
+
+# Authentication
+
+_API version: v1_
+
+Every v1 endpoint requires authentication. The only credential type is a **Hosted API token**, sent in the `Authorization` header as a bearer token.
+
+## Creating a token
+
+Create a token from the **Tokens** section of your account settings at [hosted.doltdb.com/settings/tokens](https://hosted.doltdb.com/settings/tokens). Give it a name that says where it will be used — `deploy pipeline`, `staging bootstrap` — since that name is how you will identify it later.
+
+Copy the token immediately. Only a hash of it is stored, so the secret is shown once and cannot be recovered afterwards. If you lose it, delete the token and create another.
+
+Tokens are prefixed `hsat.v1.`.
+
+## Using a token
+
+Send it as a bearer token on every request:
+
+```sh
+curl 'https://hosted.doltdb.com/api/v1/user' \
+ -H 'Authorization: Bearer hsat.v1.YOUR_TOKEN_HERE'
+```
+
+`GET /api/v1/user` is the cheapest way to check a credential: a `200` confirms the token is valid and shows whose access it carries.
+
+In a script, keep the token in an environment variable rather than in the source:
+
+```sh
+export HOSTED_API_TOKEN='hsat.v1.YOUR_TOKEN_HERE'
+
+curl 'https://hosted.doltdb.com/api/v1/deployments/acme' \
+ -H "Authorization: Bearer $HOSTED_API_TOKEN"
+```
+
+## Permissions
+
+A token carries the full permissions of the user who created it. There are no per-token scopes in v1 — anything you can do in the web UI, a token of yours can do through the API, including [creating deployments, which incurs cost](/products/hosted/api/v1/deployment#createDeployment).
+
+Access to a particular deployment still follows that deployment's own roles. A deployment you cannot see returns `404` rather than `403`, so the API never reveals that a deployment exists to someone without access to it.
+
+## Expiry and revocation
+
+Every token has an expiry date, chosen when you create it — 30, 60, or 90 days, or one year. There is deliberately no non-expiring option; rotate long-lived automation on a schedule that matches the expiry you pick.
+
+Delete a token from the same settings page to revoke it immediately. The tokens table also shows when each token was last used, and from where, which is the fastest way to find out whether a token is still in service before you delete it.
+
+## Failure responses
+
+| Status | Code | Meaning |
+|--------|------|---------|
+| `401` | `UNAUTHENTICATED` | The `Authorization` header was missing, malformed, or the token is invalid or expired. |
+| `403` | `PERMISSION_DENIED` | The token is valid, but its user is not permitted to perform this action. |
+
+Both are returned as [Problem](/products/hosted/api/v1/models#model-problem) documents. See the [v1 overview](/products/hosted/api/v1#errors) for the error model.
diff --git a/site/dolt/src/content/products/hosted/api/v1/deployment.md b/site/dolt/src/content/products/hosted/api/v1/deployment.md
new file mode 100644
index 0000000..b6b5a32
--- /dev/null
+++ b/site/dolt/src/content/products/hosted/api/v1/deployment.md
@@ -0,0 +1,362 @@
+---
+title: "Deployment"
+description: Creating, listing, and reading Hosted Dolt deployments and their instances.
+---
+
+# Deployment
+
+Hosted Dolt deployments and their lifecycle.
+
+## List the options a deployment can be created with {#getDeploymentOptions}
+GET /api/v1/deployment-options
+
+Returns the zones, instance types, and storage options available for a cloud, so a caller can construct a valid `POST /api/v1/deployments` request.
+
+The options narrow in steps, because each depends on the one before it. Supply `cloud` alone for its zones; add `zone` to also get that zone's instance types; add `instance_type_id` to also get the storage options compatible with that instance. Fields you haven't narrowed enough to determine are absent rather than empty.
+
+Each list is filtered to what you selected: supplying `zone` narrows `zones` to that zone, and supplying `instance_type_id` narrows `instance_types` to that instance type. A fully narrowed request therefore describes one combination rather than repeating the whole catalogue.
+
+A `zone` or `instance_type_id` that doesn't exist is a `422` rather than an empty result, so a typo can't be mistaken for a combination with nothing available. `instance_type_id` requires `zone`; supplying it alone is a `400`.
+
+The `id` of an instance type or storage option is what `POST /api/v1/deployments` accepts; `name` is for display.
+
+
+**Parameters**
+
+| Name | In | Type | Required | Description |
+|------|----|------|----------|-------------|
+| `cloud` | query | string | yes | The cloud to list options for. |
+| `zone` | query | string | no | A zone from this cloud's `zones`. Supply it to receive `instance_types`. |
+| `instance_type_id` | query | string | no | An instance type `id` from `instance_types`. Supply it, together with `zone`, to receive `storage_options`. |
+
+**Example request**
+
+```sh
+curl -X GET 'https://hosted.doltdb.com/api/v1/deployment-options?cloud=aws' \
+ -H 'Authorization: Bearer YOUR_TOKEN'
+```
+
+**Responses**
+
+| Status | Description | Schema |
+|--------|-------------|--------|
+| `200` | The available options, narrowed by the supplied parameters. | [`DeploymentOptions`](/products/hosted/api/v1/models#model-deploymentoptions) |
+| `400` | The request was malformed or failed input validation. | |
+| `401` | Authentication credentials were missing or invalid. | |
+| `405` | The HTTP method is not supported for this resource. | |
+| `422` | The request was well-formed but semantically invalid. | |
+| `500` | An unexpected server error occurred. | |
+| `503` | The service is temporarily unavailable. | |
+
+**Example response `200`**
+
+```json
+{
+ "data": {
+ "cloud": "aws",
+ "zones": [
+ "us-east-1"
+ ],
+ "instance_types": [
+ {
+ "id": "aws.t2.medium",
+ "name": "t2.medium",
+ "cpus": 2,
+ "memory_gb": 4,
+ "description": "Trial tier, the lowest spec that runs a Dolt SQL server.",
+ "hourly_cost_usd": 0.06849315
+ }
+ ],
+ "storage_options": [
+ {
+ "id": "aws.ebs.gp3_50",
+ "name": "Trial 50GB EBS",
+ "description": "Trial tier storage capped at 50GB",
+ "min_size_gb": 50,
+ "max_size_gb": 50,
+ "monthly_cost_usd_per_gb": 0
+ }
+ ]
+ }
+}
+```
+
+---
+
+## Create a deployment {#createDeployment}
+POST /api/v1/deployments
+
+Provisions a new deployment and returns `202` with the deployment in its `starting` state. Provisioning continues after the response: poll `GET /api/v1/deployments/{owner}/{deployment}` until `state` becomes `started`.
+
+Deployment names are unique within an owner, so a create is idempotent by name — a retry after an ambiguous failure returns `409` rather than provisioning a second deployment. Callers should still treat `409` as "it already exists", not as a different failure.
+
+`instance_type_id` and `volume_type_id` take the **ids** from the deployment options endpoint, not the display names a deployment reports back on a read.
+
+As with any create, a `5xx` or a dropped connection does not tell you whether the deployment was created — the call can succeed remotely and fail on the way back. Retry: it returns `409` if the deployment now exists, and `GET` confirms either way.
+
+**Creating a deployment incurs cost.**
+
+
+**Request body**
+
+| Field | Type | Required | Description |
+|-------|------|----------|-------------|
+| `owner` | string | yes | The user or organization that will own the deployment. The caller must have permission to create deployments for it. 3–32 characters of letters, digits, hyphens, and underscores. |
+| `name` | string | yes | The deployment name, unique within the owner. 3–32 characters of letters, digits, hyphens, and underscores. |
+| `cloud` | string | yes | The cloud the deployment runs in. |
+| `zone` | string | yes | The cloud region to provision in, as listed by the deployment options. |
+| `cluster_type` | string | no | The database engine the deployment runs. `mysql_with_dolt_replicas` is a MySQL primary with Dolt read replicas. |
+| `instance_type_id` | string | yes | The **id** of the instance type, from the deployment options endpoint. Note a deployment reports `instance_type_name` on a read — the id and the display name are different values. |
+| `volume_type_id` | string | yes | The **id** of the storage type, from the deployment options endpoint. As with `instance_type_id`, this is the id rather than the display name. |
+| `volume_size_gb` | integer | yes | The size of the storage volume, in gigabytes. Must fall within the selected storage type's supported range. |
+| `replicas` | integer | no | The number of read replicas. Defaults to `0` when omitted. |
+| `webpki_cert` | boolean | no | Serve a publicly-trusted (WebPKI) TLS certificate rather than a Hosted-issued one. Defaults to `false` when omitted. |
+| `expose_remotesapi_endpoint` | boolean | no | Expose a Dolt remotes API endpoint. Defaults to `false` when omitted. |
+| `expose_mcp` | boolean | no | Expose an MCP endpoint. Defaults to `false` when omitted. |
+| `expose_stats` | boolean | no | Expose a statistics endpoint. Defaults to `false` when omitted. |
+
+**Example request**
+
+```sh
+curl -X POST 'https://hosted.doltdb.com/api/v1/deployments' \
+ -H 'Authorization: Bearer YOUR_TOKEN' \
+ -H 'Content-Type: application/json' \
+ -d '{"owner":"acme","name":"analytics","cloud":"aws","zone":"us-east-1","instance_type_id":"aws.t2.medium","volume_type_id":"aws.ebs.gp3_50","volume_size_gb":50}'
+```
+
+**Responses**
+
+| Status | Description | Schema |
+|--------|-------------|--------|
+| `202` | The deployment has been accepted and is provisioning. `state` is `starting`. | [`Deployment`](/products/hosted/api/v1/models#model-deployment) |
+| `400` | The request was malformed or failed input validation. | |
+| `401` | Authentication credentials were missing or invalid. | |
+| `403` | Authenticated, but not permitted to perform this action. | |
+| `405` | The HTTP method is not supported for this resource. | |
+| `409` | The request conflicts with the current state of the resource (e.g. it already exists). | |
+| `422` | The request was well-formed but semantically invalid. | |
+| `500` | An unexpected server error occurred. | |
+| `503` | The service is temporarily unavailable. | |
+
+**Example response `202`**
+
+```json
+{
+ "data": {
+ "owner": "acme",
+ "name": "analytics",
+ "state": "starting",
+ "cloud": "aws",
+ "zone": "us-east-1",
+ "cluster_type": "dolt",
+ "instance_type_name": "t2.medium",
+ "volume_type_name": "Trial 50GB EBS",
+ "volume_size_gb": 50,
+ "replicas": 0,
+ "host": "",
+ "port": 3306,
+ "caller_role": "admin",
+ "created_by": "acme-ops",
+ "created_at": "2026-08-11T09:14:00Z"
+ }
+}
+```
+
+---
+
+## List an owner's deployments {#listDeployments}
+GET /api/v1/deployments/{owner}
+
+Returns the deployments belonging to `{owner}` that the caller can see, newest cursor page first. Requires a credential with access to the owner.
+
+Items are `DeploymentSummary`, not the full `Deployment` — the backing RPC returns a narrower shape for lists. Fetch `GET /api/v1/deployments/{owner}/{deployment}` for the complete resource.
+
+Pagination is cursor-based: when `meta.next_page_token` is present, pass it back as `page_token` to fetch the next page. On the last page `meta` is omitted entirely, so presence of the token is the only check a client needs.
+
+
+**Parameters**
+
+| Name | In | Type | Required | Description |
+|------|----|------|----------|-------------|
+| `owner` | path | string | yes | The user or organization whose deployments to list. 3–32 characters of letters, digits, hyphens, and underscores. |
+| `page_token` | query | string | no | The `meta.next_page_token` from a previous response. Omit for the first page. |
+| `state` | query | string | no | Return only deployments in this state. Omit for all states. |
+
+**Example request**
+
+```sh
+curl -X GET 'https://hosted.doltdb.com/api/v1/deployments/{owner}' \
+ -H 'Authorization: Bearer YOUR_TOKEN'
+```
+
+**Responses**
+
+| Status | Description | Schema |
+|--------|-------------|--------|
+| `200` | The owner's deployments. | [`DeploymentSummary[]`](/products/hosted/api/v1/models#model-deploymentsummary) |
+| `400` | The request was malformed or failed input validation. | |
+| `401` | Authentication credentials were missing or invalid. | |
+| `403` | Authenticated, but not permitted to perform this action. | |
+| `404` | The requested resource does not exist. | |
+| `405` | The HTTP method is not supported for this resource. | |
+| `500` | An unexpected server error occurred. | |
+
+**Example response `200`**
+
+```json
+{
+ "data": [
+ {
+ "owner": "acme",
+ "name": "analytics",
+ "state": "started",
+ "cloud": "aws",
+ "zone": "us-west-2",
+ "cluster_type": "dolt",
+ "instance_type_name": "m5.large",
+ "volume_type_name": "gp3",
+ "volume_size_gb": 100,
+ "replicas": 0,
+ "database_version": "1.58.4",
+ "hourly_cost_usd": 0.192,
+ "webpki_cert": true
+ }
+ ],
+ "meta": {
+ "next_page_token": "eyJvZmZzZXQiOjI1fQ"
+ }
+}
+```
+
+---
+
+## Get a deployment {#getDeployment}
+GET /api/v1/deployments/{owner}/{deployment}
+
+Returns the deployment `{owner}/{deployment}`. Requires a credential with at least read access; a deployment the caller cannot see returns `404` rather than `403`, so its existence isn't leaked.
+
+
+**Parameters**
+
+| Name | In | Type | Required | Description |
+|------|----|------|----------|-------------|
+| `owner` | path | string | yes | The user or organization that owns the deployment. 3–32 characters of letters, digits, hyphens, and underscores. |
+| `deployment` | path | string | yes | The deployment name, unique within the owner. 3–32 characters of letters, digits, hyphens, and underscores. |
+
+**Example request**
+
+```sh
+curl -X GET 'https://hosted.doltdb.com/api/v1/deployments/{owner}/{deployment}' \
+ -H 'Authorization: Bearer YOUR_TOKEN'
+```
+
+**Responses**
+
+| Status | Description | Schema |
+|--------|-------------|--------|
+| `200` | The deployment. | [`Deployment`](/products/hosted/api/v1/models#model-deployment) |
+| `400` | The request was malformed or failed input validation. | |
+| `401` | Authentication credentials were missing or invalid. | |
+| `404` | The requested resource does not exist. | |
+| `405` | The HTTP method is not supported for this resource. | |
+| `500` | An unexpected server error occurred. | |
+| `503` | The service is temporarily unavailable. | |
+
+**Example response `200`**
+
+```json
+{
+ "data": {
+ "owner": "acme",
+ "name": "analytics",
+ "state": "started",
+ "cloud": "aws",
+ "zone": "us-east-1",
+ "cluster_type": "dolt",
+ "instance_type_name": "t2.medium",
+ "volume_type_name": "Trial 50GB EBS",
+ "volume_size_gb": 50,
+ "replicas": 0,
+ "database_version": "1.58.4",
+ "host": "analytics.dbs.hosted.doltdb.com",
+ "port": 3306,
+ "hourly_cost_usd": 0.06849315,
+ "webpki_cert": true,
+ "expose_remotesapi_endpoint": false,
+ "expose_mcp": false,
+ "expose_stats": false,
+ "disable_automatic_dolt_updates": false,
+ "caller_role": "admin",
+ "created_by": "acme-ops",
+ "created_at": "2026-07-01T18:22:04Z"
+ }
+}
+```
+
+---
+
+## List a deployment's instances {#listDeploymentInstances}
+GET /api/v1/deployments/{owner}/{deployment}/instances
+
+Returns the instances backing `{owner}/{deployment}` — one for a single-instance deployment, or a primary plus its read replicas.
+
+Stopped instances are not listed; starting, started, and stopping ones all are. So an instance appearing here is part of the deployment but not necessarily serving traffic, and an empty array means it has none outside the stopped state — normal while a deployment is itself `starting`.
+
+The list is not paginated: a deployment has a primary and its replicas, a set small enough to return whole.
+
+
+**Parameters**
+
+| Name | In | Type | Required | Description |
+|------|----|------|----------|-------------|
+| `owner` | path | string | yes | The user or organization that owns the deployment. 3–32 characters of letters, digits, hyphens, and underscores. |
+| `deployment` | path | string | yes | The deployment name, unique within the owner. 3–32 characters of letters, digits, hyphens, and underscores. |
+
+**Example request**
+
+```sh
+curl -X GET 'https://hosted.doltdb.com/api/v1/deployments/{owner}/{deployment}/instances' \
+ -H 'Authorization: Bearer YOUR_TOKEN'
+```
+
+**Responses**
+
+| Status | Description | Schema |
+|--------|-------------|--------|
+| `200` | The deployment's non-stopped instances. | [`DeploymentInstance[]`](/products/hosted/api/v1/models#model-deploymentinstance) |
+| `400` | The request was malformed or failed input validation. | |
+| `401` | Authentication credentials were missing or invalid. | |
+| `404` | The requested resource does not exist. | |
+| `405` | The HTTP method is not supported for this resource. | |
+| `500` | An unexpected server error occurred. | |
+| `503` | The service is temporarily unavailable. | |
+
+**Example response `200`**
+
+```json
+{
+ "data": [
+ {
+ "id": "9b1f5c2e-4d3a-4f8b-9c0d-1e2f3a4b5c6d",
+ "index": 0,
+ "is_primary": true,
+ "host": "analytics-0.dbs.hosted.doltdb.com",
+ "instance_type_name": "t2.medium",
+ "volume_type_name": "Trial 50GB EBS",
+ "volume_size_gb": 50,
+ "hourly_cost_usd": 0.06849315
+ },
+ {
+ "id": "2c4e6a8b-1d3f-4a5c-8e9b-0f1a2b3c4d5e",
+ "index": 1,
+ "is_primary": false,
+ "host": "analytics-1.dbs.hosted.doltdb.com",
+ "instance_type_name": "t2.medium",
+ "volume_type_name": "Trial 50GB EBS",
+ "volume_size_gb": 50,
+ "hourly_cost_usd": 0.06849315
+ }
+ ]
+}
+```
+
diff --git a/site/dolt/src/content/products/hosted/api/v1/models.md b/site/dolt/src/content/products/hosted/api/v1/models.md
new file mode 100644
index 0000000..8a498e2
--- /dev/null
+++ b/site/dolt/src/content/products/hosted/api/v1/models.md
@@ -0,0 +1,279 @@
+---
+title: "Models"
+description: Request and response schemas for the Hosted v1 API.
+---
+
+# Models
+
+Shared request and response types used across the v1 API. See the [error model](#model-problem) for how failures are reported.
+
+## ErrorCode {#model-errorcode}
+A stable, machine-readable error code in SCREAMING_SNAKE_CASE. Clients branch on this value, never on the human-readable `title`/`detail` prose. The baseline codes below cover the standard HTTP failure categories; endpoint-specific codes (e.g. `DEPLOYMENT_NOT_FOUND`) are appended to this enum alongside the endpoints that emit them, which is an additive, non-breaking change under the v1 stability policy.
+
+**Enum values**
+
+| Value |
+|-------|
+| `VALIDATION_FAILED` |
+| `UNAUTHENTICATED` |
+| `PERMISSION_DENIED` |
+| `NOT_FOUND` |
+| `METHOD_NOT_ALLOWED` |
+| `CONFLICT` |
+| `UNPROCESSABLE` |
+| `RATE_LIMITED` |
+| `INTERNAL` |
+| `SERVICE_UNAVAILABLE` |
+| `OPERATION_FAILED` |
+
+---
+
+## Problem {#model-problem}
+A structured error body returned for every non-2xx response, following RFC 9457 (Problem Details for HTTP APIs). This is the single error model for the entire v1 API — there are no ad-hoc error shapes.
+
+| Field | Type | Required | Description |
+|-------|------|----------|-------------|
+| `type` | `string` | yes | A URI identifying the problem type; when dereferenced it points at human-readable documentation for the error. |
+| `title` | `string` | yes | A short, human-readable summary of the problem type. |
+| `status` | `integer` | yes | The HTTP status code, repeated in the body for convenience. |
+| `detail` | `string` | no | A human-readable explanation specific to this occurrence of the problem. |
+| `instance` | `string` | no | A URI reference identifying the specific occurrence (typically the request path). |
+| `code` | `string` | yes | A stable, machine-readable error code in SCREAMING_SNAKE_CASE. Clients branch on this value, never on the human-readable `title`/`detail` prose. The baseline codes below cover the standard HTTP failure categories; endpoint-specific codes (e.g. `DEPLOYMENT_NOT_FOUND`) are appended to this enum alongside the endpoints that emit them, which is an additive, non-breaking change under the v1 stability policy. |
+| `request_id` | `string` | yes | The request identifier, echoed on every response. Include it when contacting support so a request can be traced end-to-end. |
+
+---
+
+## Meta {#model-meta}
+Response metadata carried alongside the primary `data` payload. All fields are optional; list endpoints populate `next_page_token` for cursor pagination.
+
+| Field | Type | Required | Description |
+|-------|------|----------|-------------|
+| `next_page_token` | `string` | no | Opaque cursor for the next page of a list response. Absent when there are no further results — never present and empty — otherwise pass it back as the `page_token` query parameter to fetch the next page. |
+
+---
+
+## Envelope {#model-envelope}
+The success envelope wrapping every 2xx response body: the resource or list of resources under `data`, with optional `meta`. This is the single success shape for the API — there are no unenveloped success bodies. Endpoints narrow `data` to a concrete resource via `allOf`; the base leaves `data` unconstrained so that composition works.
+
+| Field | Type | Required | Description |
+|-------|------|----------|-------------|
+| `data` | `object,array` | yes | The primary response payload — a resource, or an array of resources for list endpoints. |
+| `meta` | `object` | no | Response metadata carried alongside the primary `data` payload. All fields are optional; list endpoints populate `next_page_token` for cursor pagination. |
+
+---
+
+## UserEmailAddress {#model-useremailaddress}
+An email address belonging to a user.
+
+| Field | Type | Required | Description |
+|-------|------|----------|-------------|
+| `address` | `string` | yes | The email address. |
+| `is_verified` | `boolean` | yes | Whether the address has completed email verification. |
+| `is_primary` | `boolean` | yes | Whether this is the user's primary address. Exactly one address is primary. |
+
+---
+
+## User {#model-user}
+A Hosted user. `GET /api/v1/user` returns the authenticated user's profile. v1 returns only public-facing profile fields — the identity provider the account signs in with, session state, and credential metadata are never included.
+
+| Field | Type | Required | Description |
+|-------|------|----------|-------------|
+| `username` | `string` | yes | The user's Hosted username (unique handle). |
+| `display_name` | `string` | no | The user's display name. May be empty. |
+| `company` | `string` | no | The user's stated company. May be empty. |
+| `email_addresses` | `array` | yes | The user's email addresses. Returned only for the authenticated user themselves; empty for any other caller. |
+
+---
+
+## InstanceType {#model-instancetype}
+A compute instance type a deployment can run on.
+
+| Field | Type | Required | Description |
+|-------|------|----------|-------------|
+| `id` | `string` | yes | The identifier `POST /api/v1/deployments` accepts as `instance_type_id`. |
+| `name` | `string` | yes | The display name. A deployment reports this as `instance_type_name`. |
+| `cpus` | `integer` | no | Virtual CPUs. |
+| `memory_gb` | `integer` | no | Memory, in gigabytes. |
+| `description` | `string` | no | A human-readable summary of what the instance suits. |
+| `hourly_cost_usd` | `number` | no | Cost per hour in US dollars. Absent when no hourly price is published for this instance type. |
+
+---
+
+## StorageOption {#model-storageoption}
+A storage type a deployment's volume can use.
+
+| Field | Type | Required | Description |
+|-------|------|----------|-------------|
+| `id` | `string` | yes | The identifier `POST /api/v1/deployments` accepts as `volume_type_id`. |
+| `name` | `string` | yes | The display name. A deployment reports this as `volume_type_name`. |
+| `description` | `string` | no | A human-readable summary of the storage type. |
+| `min_size_gb` | `integer` | no | Smallest volume size this type supports, in gigabytes. `volume_size_gb` on a create request must be at least this. |
+| `max_size_gb` | `integer` | no | Largest volume size this type supports, in gigabytes. |
+| `monthly_cost_usd_per_gb` | `number` | no | Cost per gigabyte per month, in US dollars. |
+
+---
+
+## DeploymentInstance {#model-deploymentinstance}
+One instance backing a deployment. A deployment has a primary and, when it has read replicas, one instance per replica.
+
+| Field | Type | Required | Description |
+|-------|------|----------|-------------|
+| `id` | `string` | yes | The instance's identifier, unique within the deployment. |
+| `index` | `integer` | yes | The instance's position in the deployment. `0` is the first instance; replicas take the following indices. |
+| `is_primary` | `boolean` | yes | Whether this instance is currently the primary. Exactly one instance of a started deployment is primary, and which one can change over the deployment's life. |
+| `host` | `string` | no | The hostname for this specific instance. Connect to the deployment's own `host` unless you mean to address one instance directly. |
+| `instance_type_name` | `string` | no | The display name of this instance's type. |
+| `volume_type_name` | `string` | no | The display name of this instance's storage type. |
+| `volume_size_gb` | `integer` | no | The size of this instance's storage volume, in gigabytes. |
+| `hourly_cost_usd` | `number` | no | This instance's cost per hour, in US dollars. A deployment's total is the sum across its instances. |
+
+---
+
+## DeploymentOptions {#model-deploymentoptions}
+The options available for creating a deployment, narrowed by the query parameters supplied. `instance_types` and `storage_options` are absent until enough of the chain has been supplied to determine them.
+
+| Field | Type | Required | Description |
+|-------|------|----------|-------------|
+| `cloud` | `string` | yes | The cloud the deployment runs in. |
+| `zones` | `array` | yes | The zones this cloud supports. |
+| `instance_types` | `array` | no | Instance types available in the requested `zone`. Absent when `zone` wasn't supplied. |
+| `storage_options` | `array` | no | Storage types compatible with the requested `instance_type_id`. Absent when `zone` and `instance_type_id` weren't both supplied. |
+
+---
+
+## CreateDeploymentRequest {#model-createdeploymentrequest}
+The provisioning parameters for a new deployment.
+
+v1.0 exposes the core parameters only. Restoring from a backup, cloning an existing deployment, workbench user settings, and private networking are all settable on the internal API but are not part of this request; each is its own feature with its own contract, and adding them is additive. The internal deployment test flag is deliberately not exposed at all.
+
+| Field | Type | Required | Description |
+|-------|------|----------|-------------|
+| `owner` | `string` | yes | The user or organization that will own the deployment. The caller must have permission to create deployments for it. 3–32 characters of letters, digits, hyphens, and underscores. |
+| `name` | `string` | yes | The deployment name, unique within the owner. 3–32 characters of letters, digits, hyphens, and underscores. |
+| `cloud` | `string` | yes | The cloud the deployment runs in. |
+| `zone` | `string` | yes | The cloud region to provision in, as listed by the deployment options. |
+| `cluster_type` | `string` | no | The database engine the deployment runs. `mysql_with_dolt_replicas` is a MySQL primary with Dolt read replicas. |
+| `instance_type_id` | `string` | yes | The **id** of the instance type, from the deployment options endpoint. Note a deployment reports `instance_type_name` on a read — the id and the display name are different values. |
+| `volume_type_id` | `string` | yes | The **id** of the storage type, from the deployment options endpoint. As with `instance_type_id`, this is the id rather than the display name. |
+| `volume_size_gb` | `integer` | yes | The size of the storage volume, in gigabytes. Must fall within the selected storage type's supported range. |
+| `replicas` | `integer` | no | The number of read replicas. Defaults to `0` when omitted. |
+| `webpki_cert` | `boolean` | no | Serve a publicly-trusted (WebPKI) TLS certificate rather than a Hosted-issued one. Defaults to `false` when omitted. |
+| `expose_remotesapi_endpoint` | `boolean` | no | Expose a Dolt remotes API endpoint. Defaults to `false` when omitted. |
+| `expose_mcp` | `boolean` | no | Expose an MCP endpoint. Defaults to `false` when omitted. |
+| `expose_stats` | `boolean` | no | Expose a statistics endpoint. Defaults to `false` when omitted. |
+
+---
+
+## DeploymentState {#model-deploymentstate}
+The deployment's lifecycle state. `starting` covers both initial provisioning and a restart; poll this field to observe a create or a resize reaching `started`.
+
+**Enum values**
+
+| Value |
+|-------|
+| `starting` |
+| `started` |
+| `stopping` |
+| `stopped` |
+
+---
+
+## CloudProvider {#model-cloudprovider}
+The cloud the deployment runs in.
+
+**Enum values**
+
+| Value |
+|-------|
+| `aws` |
+| `gcp` |
+| `azure` |
+
+---
+
+## ClusterType {#model-clustertype}
+The database engine the deployment runs. `mysql_with_dolt_replicas` is a MySQL primary with Dolt read replicas.
+
+**Enum values**
+
+| Value |
+|-------|
+| `dolt` |
+| `doltgres` |
+| `mysql_with_dolt_replicas` |
+
+---
+
+## DeploymentRole {#model-deploymentrole}
+The authenticated caller's role on this deployment. Always present on a read, since a caller without at least read access cannot retrieve the deployment at all.
+
+**Enum values**
+
+| Value |
+|-------|
+| `admin` |
+| `writer` |
+| `reader` |
+| `reader_and_pulls` |
+
+---
+
+## DeploymentSummary {#model-deploymentsummary}
+A deployment as it appears in a list.
+
+This is deliberately not the same shape as `Deployment`. The list RPC returns a narrower record — it omits connection details, the caller's role, and the creation audit fields, and it adds the last-backup figures shown in fleet views. Read the deployment itself for the full resource. As with `Deployment`, database credentials are never included.
+
+| Field | Type | Required | Description |
+|-------|------|----------|-------------|
+| `owner` | `string` | yes | The user or organization that owns the deployment. |
+| `name` | `string` | yes | The deployment name, unique within the owner. |
+| `state` | `string` | yes | The deployment's lifecycle state. `starting` covers both initial provisioning and a restart; poll this field to observe a create or a resize reaching `started`. |
+| `cloud` | `string` | yes | The cloud the deployment runs in. |
+| `zone` | `string` | yes | The cloud region the deployment runs in. |
+| `cluster_type` | `string` | yes | The database engine the deployment runs. `mysql_with_dolt_replicas` is a MySQL primary with Dolt read replicas. |
+| `instance_type_name` | `string` | no | The display name of the deployment's instance type. |
+| `volume_type_name` | `string` | no | The display name of the deployment's storage type. |
+| `volume_size_gb` | `integer` | no | The size of the deployment's storage volume, in gigabytes. |
+| `replicas` | `integer` | no | The number of read replicas. `0` for a single-instance deployment. |
+| `database_version` | `string` | no | The version of the database engine the deployment is running — a Dolt version for a `dolt` cluster, a Doltgres version for a `doltgres` one. |
+| `hourly_cost_usd` | `number` | no | The deployment's current cost per hour, in US dollars. |
+| `webpki_cert` | `boolean` | no | Whether the deployment serves a publicly-trusted (WebPKI) TLS certificate. |
+| `last_backup_size_bytes` | `integer` | no | Size of the most recent backup, in bytes. Absent when no backup has been taken or its size has not been computed yet. |
+| `last_backup_time` | `string` | no | When the most recent backup was taken. Absent when no backup has been taken. |
+
+---
+
+## Deployment {#model-deployment}
+A Hosted Dolt deployment.
+
+v1 returns configuration and lifecycle state only. The deployment's database credentials are deliberately **not** part of this resource — they are issued and rotated through the deployment credentials endpoints, so that reading a deployment is never a credential-disclosing operation.
+
+Provider-specific private-networking configuration (AWS PrivateLink, GCP Private Service Connect, Azure Private Link) is not included in v1.0. Each carries its own endpoint collection and provisioning state, and will land as its own sub-resource; adding it is additive under the stability policy.
+
+| Field | Type | Required | Description |
+|-------|------|----------|-------------|
+| `owner` | `string` | yes | The user or organization that owns the deployment. |
+| `name` | `string` | yes | The deployment name, unique within the owner. |
+| `state` | `string` | yes | The deployment's lifecycle state. `starting` covers both initial provisioning and a restart; poll this field to observe a create or a resize reaching `started`. |
+| `cloud` | `string` | yes | The cloud the deployment runs in. |
+| `zone` | `string` | yes | The cloud region the deployment runs in. |
+| `cluster_type` | `string` | yes | The database engine the deployment runs. `mysql_with_dolt_replicas` is a MySQL primary with Dolt read replicas. |
+| `instance_type_name` | `string` | no | The display name of the deployment's instance type. Note this is the *name*, not the id that `POST /api/v1/deployments` accepts; both are listed by the deployment options endpoint. |
+| `volume_type_name` | `string` | no | The display name of the deployment's storage type. As with `instance_type_name`, this is the name rather than the id used to create a deployment. |
+| `volume_size_gb` | `integer` | no | The size of the deployment's storage volume, in gigabytes. |
+| `replicas` | `integer` | no | The number of read replicas. `0` for a single-instance deployment. |
+| `database_version` | `string` | no | The version of the database engine the deployment is running — a Dolt version for a `dolt` cluster, a Doltgres version for a `doltgres` one. |
+| `host` | `string` | no | The hostname clients connect to. Empty until the deployment reaches `started`. |
+| `port` | `integer` | no | The port clients connect to. |
+| `hourly_cost_usd` | `number` | no | The deployment's current cost per hour, in US dollars. |
+| `webpki_cert` | `boolean` | no | Whether the deployment serves a publicly-trusted (WebPKI) TLS certificate rather than a Hosted-issued one. |
+| `expose_remotesapi_endpoint` | `boolean` | no | Whether the deployment exposes a Dolt remotes API endpoint. |
+| `expose_mcp` | `boolean` | no | Whether the deployment exposes an MCP endpoint. |
+| `expose_stats` | `boolean` | no | Whether the deployment exposes a statistics endpoint. |
+| `disable_automatic_dolt_updates` | `boolean` | no | Whether automatic Dolt version updates are disabled for this deployment. |
+| `caller_role` | `string` | yes | The authenticated caller's role on this deployment. Always present on a read, since a caller without at least read access cannot retrieve the deployment at all. |
+| `created_by` | `string` | no | The username of the user who created the deployment. |
+| `created_at` | `string` | yes | When the deployment was created. |
+| `destroy_at` | `string` | no | When the deployment is scheduled to be destroyed. Absent unless a destroy has been scheduled. |
+| `destroyed_by` | `string` | no | The username of the user who destroyed the deployment. Absent unless it has been destroyed. |
+
diff --git a/site/dolt/src/content/products/hosted/api/v1/user.md b/site/dolt/src/content/products/hosted/api/v1/user.md
new file mode 100644
index 0000000..916cfe5
--- /dev/null
+++ b/site/dolt/src/content/products/hosted/api/v1/user.md
@@ -0,0 +1,50 @@
+---
+title: "User"
+description: The authenticated user resource in the Hosted v1 API.
+---
+
+# User
+
+The authenticated user.
+
+## Get the authenticated user {#getCurrentUser}
+GET /api/v1/user
+
+Returns the profile of the user identified by the request's credentials. Useful as a credential check: a `200` confirms the token is valid and shows whose access it carries.
+
+
+**Example request**
+
+```sh
+curl -X GET 'https://hosted.doltdb.com/api/v1/user' \
+ -H 'Authorization: Bearer YOUR_TOKEN'
+```
+
+**Responses**
+
+| Status | Description | Schema |
+|--------|-------------|--------|
+| `200` | The authenticated user's profile. | [`User`](/products/hosted/api/v1/models#model-user) |
+| `401` | Authentication credentials were missing or invalid. | |
+| `405` | The HTTP method is not supported for this resource. | |
+| `500` | An unexpected server error occurred. | |
+
+**Example response `200`**
+
+```json
+{
+ "data": {
+ "username": "acme-ops",
+ "display_name": "Acme Operations",
+ "company": "Acme Corp",
+ "email_addresses": [
+ {
+ "address": "ops@acme.com",
+ "is_verified": true,
+ "is_primary": true
+ }
+ ]
+ }
+}
+```
+
diff --git a/site/dolt/src/nav.ts b/site/dolt/src/nav.ts
index ab77403..1b82e75 100644
--- a/site/dolt/src/nav.ts
+++ b/site/dolt/src/nav.ts
@@ -244,6 +244,20 @@ const nav: NavSection[] = [
{ title: "Infrastructure", href: "/products/hosted/infrastructure" },
{ title: "Private Networking", href: "/products/hosted/private-networking" },
{ title: "SSO", href: "/products/hosted/sso" },
+ {
+ // Only one API version exists, so the sections sit directly under
+ // API rather than behind a "v1" node. The paths keep /v1/ so a
+ // future v2 can be added without moving any of these URLs.
+ title: "API",
+ href: "/products/hosted/api",
+ children: [
+ { title: "Overview", href: "/products/hosted/api/v1" },
+ { title: "Authentication", href: "/products/hosted/api/v1/authentication" },
+ { title: "User", href: "/products/hosted/api/v1/user" },
+ { title: "Deployment", href: "/products/hosted/api/v1/deployment" },
+ { title: "Models", href: "/products/hosted/api/v1/models" },
+ ],
+ },
],
},
{
diff --git a/specs/hosted-v1.yaml b/specs/hosted-v1.yaml
new file mode 100644
index 0000000..56bb91c
--- /dev/null
+++ b/specs/hosted-v1.yaml
@@ -0,0 +1,1508 @@
+# Hosted Public API v1 — OpenAPI contract.
+#
+# This is the single source of truth for the v1 API. TypeScript DTO types,
+# runtime/contract-test JSON Schemas, and the public docs are all generated
+# from this file — never hand-edited downstream.
+#
+# The error model, envelope, and pagination conventions below are deliberately
+# identical to DoltHub's v2 spec (web/packages/dolthub/openapi/v2.yaml) apart
+# from the docs URL. Two public APIs from the same company that disagree about
+# error bodies is a worse outcome than either individual choice.
+openapi: 3.1.0
+
+info:
+ title: Hosted API
+ version: 1.0.0
+ summary: The public REST API for Hosted Dolt deployments.
+ description: |
+ The Hosted v1 API is an explicit, versioned, OpenAPI-defined contract for the Hosted
+ control plane: deployments and their instances, backups, credentials, configuration,
+ and access.
+
+ This document is the contract: it is the source of truth for the implementation, the
+ generated types, and the rendered reference docs.
+
+ **Scope.** v1 covers the control plane only. Querying the data inside a deployment is
+ not part of this API — every deployment exposes a SQL endpoint that callers connect to
+ directly with their own credentials.
+ contact:
+ name: DoltHub Support
+ url: https://hosted.doltdb.com/contact
+ email: dolt-interest@dolthub.com
+ license:
+ name: Hosted Dolt Terms of Service
+ url: https://hosted.doltdb.com/terms
+ termsOfService: https://hosted.doltdb.com/terms
+
+servers:
+ - url: https://hosted.doltdb.com
+ description: Production
+
+# Default: every operation requires an API token. Individual operations may override this
+# once paths are added. API tokens are the only credential in v1 — the scheme list is a
+# sequence so an `oauth2` scheme can be added later without a breaking change.
+security:
+ - apiToken: []
+
+# Operation tags are registered here so renderers group operations consistently.
+tags:
+ - name: User
+ description: The authenticated user.
+ - name: Deployment
+ description: Hosted Dolt deployments and their lifecycle.
+
+paths:
+ /api/v1/user:
+ get:
+ operationId: getCurrentUser
+ summary: Get the authenticated user.
+ description: >-
+ Returns the profile of the user identified by the request's credentials. Useful as a
+ credential check: a `200` confirms the token is valid and shows whose access it
+ carries.
+ tags:
+ - User
+ security:
+ - apiToken: []
+ responses:
+ "200":
+ description: The authenticated user's profile.
+ headers:
+ x-request-id:
+ $ref: "#/components/headers/RequestId"
+ content:
+ application/json:
+ schema:
+ allOf:
+ - $ref: "#/components/schemas/Envelope"
+ - type: object
+ required:
+ - data
+ properties:
+ data:
+ $ref: "#/components/schemas/User"
+ examples:
+ default:
+ summary: An authenticated user's profile.
+ value:
+ data:
+ username: acme-ops
+ display_name: Acme Operations
+ company: Acme Corp
+ email_addresses:
+ - address: ops@acme.com
+ is_verified: true
+ is_primary: true
+ "401":
+ $ref: "#/components/responses/Unauthorized"
+ "405":
+ $ref: "#/components/responses/MethodNotAllowed"
+ "500":
+ $ref: "#/components/responses/InternalServerError"
+
+ /api/v1/deployment-options:
+ get:
+ operationId: getDeploymentOptions
+ summary: List the options a deployment can be created with.
+ description: >-
+ Returns the zones, instance types, and storage options available for a cloud, so a
+ caller can construct a valid `POST /api/v1/deployments` request.
+
+
+ The options narrow in steps, because each depends on the one before it. Supply
+ `cloud` alone for its zones; add `zone` to also get that zone's instance types; add
+ `instance_type_id` to also get the storage options compatible with that instance.
+ Fields you haven't narrowed enough to determine are absent rather than empty.
+
+
+ Each list is filtered to what you selected: supplying `zone` narrows `zones` to that
+ zone, and supplying `instance_type_id` narrows `instance_types` to that instance
+ type. A fully narrowed request therefore describes one combination rather than
+ repeating the whole catalogue.
+
+
+ A `zone` or `instance_type_id` that doesn't exist is a `422` rather than an empty
+ result, so a typo can't be mistaken for a combination with nothing available.
+ `instance_type_id` requires `zone`; supplying it alone is a `400`.
+
+
+ The `id` of an instance type or storage option is what
+ `POST /api/v1/deployments` accepts; `name` is for display.
+ tags:
+ - Deployment
+ security:
+ - apiToken: []
+ parameters:
+ - name: cloud
+ in: query
+ required: true
+ description: The cloud to list options for.
+ schema:
+ $ref: "#/components/schemas/CloudProvider"
+ - name: zone
+ in: query
+ required: false
+ description: >-
+ A zone from this cloud's `zones`. Supply it to receive `instance_types`.
+ schema:
+ type: string
+ minLength: 1
+ example: us-east-1
+ - name: instance_type_id
+ in: query
+ required: false
+ description: >-
+ An instance type `id` from `instance_types`. Supply it, together with `zone`,
+ to receive `storage_options`.
+ schema:
+ type: string
+ minLength: 1
+ example: aws.t2.medium
+ responses:
+ "200":
+ description: The available options, narrowed by the supplied parameters.
+ headers:
+ x-request-id:
+ $ref: "#/components/headers/RequestId"
+ content:
+ application/json:
+ schema:
+ allOf:
+ - $ref: "#/components/schemas/Envelope"
+ - type: object
+ required:
+ - data
+ properties:
+ data:
+ $ref: "#/components/schemas/DeploymentOptions"
+ examples:
+ default:
+ summary: Fully narrowed options for one instance type.
+ value:
+ data:
+ cloud: aws
+ zones:
+ - us-east-1
+ instance_types:
+ - id: aws.t2.medium
+ name: t2.medium
+ cpus: 2
+ memory_gb: 4
+ description: Trial tier, the lowest spec that runs a Dolt SQL server.
+ hourly_cost_usd: 0.06849315
+ storage_options:
+ - id: aws.ebs.gp3_50
+ name: Trial 50GB EBS
+ description: Trial tier storage capped at 50GB
+ min_size_gb: 50
+ max_size_gb: 50
+ monthly_cost_usd_per_gb: 0
+ "400":
+ $ref: "#/components/responses/BadRequest"
+ "401":
+ $ref: "#/components/responses/Unauthorized"
+ "405":
+ $ref: "#/components/responses/MethodNotAllowed"
+ "422":
+ $ref: "#/components/responses/UnprocessableEntity"
+ "500":
+ $ref: "#/components/responses/InternalServerError"
+ "503":
+ $ref: "#/components/responses/ServiceUnavailable"
+
+ /api/v1/deployments:
+ post:
+ operationId: createDeployment
+ summary: Create a deployment.
+ description: >-
+ Provisions a new deployment and returns `202` with the deployment in its `starting`
+ state. Provisioning continues after the response: poll
+ `GET /api/v1/deployments/{owner}/{deployment}` until `state` becomes `started`.
+
+
+ Deployment names are unique within an owner, so a create is idempotent by name — a
+ retry after an ambiguous failure returns `409` rather than provisioning a second
+ deployment. Callers should still treat `409` as "it already exists", not as a
+ different failure.
+
+
+ `instance_type_id` and `volume_type_id` take the **ids** from the deployment options
+ endpoint, not the display names a deployment reports back on a read.
+
+
+ As with any create, a `5xx` or a dropped connection does not tell you whether the
+ deployment was created — the call can succeed remotely and fail on the way back.
+ Retry: it returns `409` if the deployment now exists, and `GET` confirms either way.
+
+
+ **Creating a deployment incurs cost.**
+ tags:
+ - Deployment
+ security:
+ - apiToken: []
+ requestBody:
+ required: true
+ description: The provisioning parameters for the new deployment.
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/CreateDeploymentRequest"
+ examples:
+ default:
+ summary: A single-instance Dolt deployment on AWS.
+ value:
+ owner: acme
+ name: analytics
+ cloud: aws
+ zone: us-east-1
+ instance_type_id: aws.t2.medium
+ volume_type_id: aws.ebs.gp3_50
+ volume_size_gb: 50
+ responses:
+ "202":
+ description: >-
+ The deployment has been accepted and is provisioning. `state` is `starting`.
+ headers:
+ x-request-id:
+ $ref: "#/components/headers/RequestId"
+ content:
+ application/json:
+ schema:
+ allOf:
+ - $ref: "#/components/schemas/Envelope"
+ - type: object
+ required:
+ - data
+ properties:
+ data:
+ $ref: "#/components/schemas/Deployment"
+ examples:
+ default:
+ summary: A deployment accepted and provisioning.
+ value:
+ data:
+ owner: acme
+ name: analytics
+ state: starting
+ cloud: aws
+ zone: us-east-1
+ cluster_type: dolt
+ instance_type_name: t2.medium
+ volume_type_name: Trial 50GB EBS
+ volume_size_gb: 50
+ replicas: 0
+ host: ""
+ port: 3306
+ caller_role: admin
+ created_by: acme-ops
+ created_at: "2026-08-11T09:14:00Z"
+ "400":
+ $ref: "#/components/responses/BadRequest"
+ "401":
+ $ref: "#/components/responses/Unauthorized"
+ "403":
+ $ref: "#/components/responses/Forbidden"
+ "405":
+ $ref: "#/components/responses/MethodNotAllowed"
+ "409":
+ $ref: "#/components/responses/Conflict"
+ "422":
+ $ref: "#/components/responses/UnprocessableEntity"
+ "500":
+ $ref: "#/components/responses/InternalServerError"
+ "503":
+ $ref: "#/components/responses/ServiceUnavailable"
+
+ /api/v1/deployments/{owner}:
+ get:
+ operationId: listDeployments
+ summary: List an owner's deployments.
+ description: >-
+ Returns the deployments belonging to `{owner}` that the caller can see, newest
+ cursor page first. Requires a credential with access to the owner.
+
+
+ Items are `DeploymentSummary`, not the full `Deployment` — the backing RPC returns a
+ narrower shape for lists. Fetch
+ `GET /api/v1/deployments/{owner}/{deployment}` for the complete resource.
+
+
+ Pagination is cursor-based: when `meta.next_page_token` is present, pass it back as
+ `page_token` to fetch the next page. On the last page `meta` is omitted entirely, so
+ presence of the token is the only check a client needs.
+ tags:
+ - Deployment
+ security:
+ - apiToken: []
+ parameters:
+ - name: owner
+ in: path
+ required: true
+ description: >-
+ The user or organization whose deployments to list. 3–32 characters of letters,
+ digits, hyphens, and underscores.
+ schema:
+ type: string
+ pattern: "^[-a-zA-Z0-9_]{3,32}$"
+ example: acme
+ - name: page_token
+ in: query
+ required: false
+ description: >-
+ The `meta.next_page_token` from a previous response. Omit for the first page.
+ schema:
+ type: string
+ example: eyJvZmZzZXQiOjI1fQ
+ - name: state
+ in: query
+ required: false
+ description: Return only deployments in this state. Omit for all states.
+ schema:
+ $ref: "#/components/schemas/DeploymentState"
+ responses:
+ "200":
+ description: The owner's deployments.
+ headers:
+ x-request-id:
+ $ref: "#/components/headers/RequestId"
+ content:
+ application/json:
+ schema:
+ allOf:
+ - $ref: "#/components/schemas/Envelope"
+ - type: object
+ required:
+ - data
+ properties:
+ data:
+ type: array
+ description: The page of deployments.
+ items:
+ $ref: "#/components/schemas/DeploymentSummary"
+ examples:
+ default:
+ summary: One page of deployments.
+ value:
+ data:
+ - owner: acme
+ name: analytics
+ state: started
+ cloud: aws
+ zone: us-west-2
+ cluster_type: dolt
+ instance_type_name: m5.large
+ volume_type_name: gp3
+ volume_size_gb: 100
+ replicas: 0
+ database_version: 1.58.4
+ hourly_cost_usd: 0.192
+ webpki_cert: true
+ meta:
+ next_page_token: eyJvZmZzZXQiOjI1fQ
+ "400":
+ $ref: "#/components/responses/BadRequest"
+ "401":
+ $ref: "#/components/responses/Unauthorized"
+ "403":
+ $ref: "#/components/responses/Forbidden"
+ "404":
+ $ref: "#/components/responses/NotFound"
+ "405":
+ $ref: "#/components/responses/MethodNotAllowed"
+ "500":
+ $ref: "#/components/responses/InternalServerError"
+
+ /api/v1/deployments/{owner}/{deployment}:
+ get:
+ operationId: getDeployment
+ summary: Get a deployment.
+ description: >-
+ Returns the deployment `{owner}/{deployment}`. Requires a credential with at least
+ read access; a deployment the caller cannot see returns `404` rather than `403`, so
+ its existence isn't leaked.
+ tags:
+ - Deployment
+ security:
+ - apiToken: []
+ parameters:
+ - name: owner
+ in: path
+ required: true
+ description: >-
+ The user or organization that owns the deployment. 3–32 characters of letters,
+ digits, hyphens, and underscores.
+ schema:
+ type: string
+ pattern: "^[-a-zA-Z0-9_]{3,32}$"
+ example: acme
+ - name: deployment
+ in: path
+ required: true
+ description: >-
+ The deployment name, unique within the owner. 3–32 characters of letters,
+ digits, hyphens, and underscores.
+ schema:
+ type: string
+ pattern: "^[-a-zA-Z0-9_]{3,32}$"
+ example: analytics
+ responses:
+ "200":
+ description: The deployment.
+ headers:
+ x-request-id:
+ $ref: "#/components/headers/RequestId"
+ content:
+ application/json:
+ schema:
+ allOf:
+ - $ref: "#/components/schemas/Envelope"
+ - type: object
+ required:
+ - data
+ properties:
+ data:
+ $ref: "#/components/schemas/Deployment"
+ examples:
+ default:
+ summary: A running deployment.
+ value:
+ data:
+ owner: acme
+ name: analytics
+ state: started
+ cloud: aws
+ zone: us-east-1
+ cluster_type: dolt
+ instance_type_name: t2.medium
+ volume_type_name: Trial 50GB EBS
+ volume_size_gb: 50
+ replicas: 0
+ database_version: 1.58.4
+ host: analytics.dbs.hosted.doltdb.com
+ port: 3306
+ hourly_cost_usd: 0.06849315
+ webpki_cert: true
+ expose_remotesapi_endpoint: false
+ expose_mcp: false
+ expose_stats: false
+ disable_automatic_dolt_updates: false
+ caller_role: admin
+ created_by: acme-ops
+ created_at: "2026-07-01T18:22:04Z"
+ "400":
+ $ref: "#/components/responses/BadRequest"
+ "401":
+ $ref: "#/components/responses/Unauthorized"
+ "404":
+ $ref: "#/components/responses/NotFound"
+ "405":
+ $ref: "#/components/responses/MethodNotAllowed"
+ "500":
+ $ref: "#/components/responses/InternalServerError"
+ "503":
+ $ref: "#/components/responses/ServiceUnavailable"
+
+ /api/v1/deployments/{owner}/{deployment}/instances:
+ get:
+ operationId: listDeploymentInstances
+ summary: List a deployment's instances.
+ description: >-
+ Returns the instances backing `{owner}/{deployment}` — one for a single-instance
+ deployment, or a primary plus its read replicas.
+
+
+ Stopped instances are not listed; starting, started, and stopping ones all are. So
+ an instance appearing here is part of the deployment but not necessarily serving
+ traffic, and an empty array means it has none outside the stopped state — normal
+ while a deployment is itself `starting`.
+
+
+ The list is not paginated: a deployment has a primary and its replicas, a set small
+ enough to return whole.
+ tags:
+ - Deployment
+ security:
+ - apiToken: []
+ parameters:
+ - name: owner
+ in: path
+ required: true
+ description: >-
+ The user or organization that owns the deployment. 3–32 characters of letters,
+ digits, hyphens, and underscores.
+ schema:
+ type: string
+ pattern: "^[-a-zA-Z0-9_]{3,32}$"
+ example: acme
+ - name: deployment
+ in: path
+ required: true
+ description: >-
+ The deployment name, unique within the owner. 3–32 characters of letters,
+ digits, hyphens, and underscores.
+ schema:
+ type: string
+ pattern: "^[-a-zA-Z0-9_]{3,32}$"
+ example: analytics
+ responses:
+ "200":
+ description: The deployment's non-stopped instances.
+ headers:
+ x-request-id:
+ $ref: "#/components/headers/RequestId"
+ content:
+ application/json:
+ schema:
+ allOf:
+ - $ref: "#/components/schemas/Envelope"
+ - type: object
+ required:
+ - data
+ properties:
+ data:
+ type: array
+ description: The deployment's non-stopped instances.
+ items:
+ $ref: "#/components/schemas/DeploymentInstance"
+ examples:
+ default:
+ summary: A primary with one read replica.
+ value:
+ data:
+ - id: 9b1f5c2e-4d3a-4f8b-9c0d-1e2f3a4b5c6d
+ index: 0
+ is_primary: true
+ host: analytics-0.dbs.hosted.doltdb.com
+ instance_type_name: t2.medium
+ volume_type_name: Trial 50GB EBS
+ volume_size_gb: 50
+ hourly_cost_usd: 0.06849315
+ - id: 2c4e6a8b-1d3f-4a5c-8e9b-0f1a2b3c4d5e
+ index: 1
+ is_primary: false
+ host: analytics-1.dbs.hosted.doltdb.com
+ instance_type_name: t2.medium
+ volume_type_name: Trial 50GB EBS
+ volume_size_gb: 50
+ hourly_cost_usd: 0.06849315
+ "400":
+ $ref: "#/components/responses/BadRequest"
+ "401":
+ $ref: "#/components/responses/Unauthorized"
+ "404":
+ $ref: "#/components/responses/NotFound"
+ "405":
+ $ref: "#/components/responses/MethodNotAllowed"
+ "500":
+ $ref: "#/components/responses/InternalServerError"
+ "503":
+ $ref: "#/components/responses/ServiceUnavailable"
+
+components:
+ headers:
+ RequestId:
+ description: >-
+ The request identifier — echoed on every response (including 2xx). Reuse
+ the inbound `x-request-id` from the caller / edge proxy when present;
+ otherwise the server mints a `req_` value.
+ schema:
+ type: string
+ examples:
+ - req_2f1c9e7a-3b6d-4c5e-8a9f-0d1e2f3a4b5c
+
+ securitySchemes:
+ apiToken:
+ type: http
+ scheme: bearer
+ description: >-
+ A Hosted API token, sent as `Authorization: Bearer `. Create one from the
+ Tokens section of your account settings. Tokens carry the full permissions of the
+ user who created them and expire on a date chosen at creation.
+
+ schemas:
+ # --- Error model ---------------------------------------------------------------------
+ # Every non-2xx response uses Problem (RFC 9457).
+ ErrorCode:
+ type: string
+ title: ErrorCode
+ description: >-
+ A stable, machine-readable error code in SCREAMING_SNAKE_CASE. Clients branch on
+ this value, never on the human-readable `title`/`detail` prose. The baseline codes
+ below cover the standard HTTP failure categories; endpoint-specific codes (e.g.
+ `DEPLOYMENT_NOT_FOUND`) are appended to this enum alongside the endpoints that emit
+ them, which is an additive, non-breaking change under the v1 stability policy.
+ enum:
+ - VALIDATION_FAILED # 400 — malformed request or failed input validation
+ - UNAUTHENTICATED # 401 — missing or invalid credentials
+ - PERMISSION_DENIED # 403 — authenticated but not permitted
+ - NOT_FOUND # 404 — resource does not exist
+ - METHOD_NOT_ALLOWED # 405 — HTTP method not supported for this resource
+ - CONFLICT # 409 — conflicts with current state (e.g. already exists)
+ - UNPROCESSABLE # 422 — well-formed but semantically invalid
+ - RATE_LIMITED # 429 — rate limit exceeded
+ - INTERNAL # 500 — unexpected server fault
+ - SERVICE_UNAVAILABLE # 503 — temporarily unavailable
+ - OPERATION_FAILED # operation reached terminal failure state
+ examples:
+ - NOT_FOUND
+
+ Problem:
+ type: object
+ title: Problem
+ description: >-
+ A structured error body returned for every non-2xx response, following RFC 9457
+ (Problem Details for HTTP APIs). This is the single error model for the entire v1
+ API — there are no ad-hoc error shapes.
+ required:
+ # `type` is required even though RFC 9457 permits omitting it: this API always emits
+ # it, and leaving it optional made the spec disagree with the generated DTO (which
+ # marks it non-optional because of the `default`).
+ - type
+ - title
+ - status
+ - code
+ - request_id
+ properties:
+ type:
+ type: string
+ format: uri
+ default: about:blank
+ description: >-
+ A URI identifying the problem type; when dereferenced it points at
+ human-readable documentation for the error.
+ examples:
+ - https://docs.dolthub.com/products/hosted/api/v1/models/#model-errorcode
+ title:
+ type: string
+ description: A short, human-readable summary of the problem type.
+ examples:
+ - Not found
+ status:
+ type: integer
+ format: int32
+ minimum: 400
+ maximum: 599
+ description: The HTTP status code, repeated in the body for convenience.
+ examples:
+ - 404
+ detail:
+ type: string
+ description: A human-readable explanation specific to this occurrence of the problem.
+ examples:
+ - "Deployment 'analytics' does not exist for owner 'acme'"
+ instance:
+ type: string
+ format: uri-reference
+ description: A URI reference identifying the specific occurrence (typically the request path).
+ examples:
+ - /api/v1/deployments/acme/analytics
+ code:
+ $ref: "#/components/schemas/ErrorCode"
+ request_id:
+ type: string
+ description: >-
+ The request identifier, echoed on every response. Include it when contacting
+ support so a request can be traced end-to-end.
+ examples:
+ - req_01HZX9P7Q5N2M8
+ additionalProperties: true
+
+ # --- Success envelope ----------------------------------------------------------------
+ Meta:
+ type: object
+ title: Meta
+ description: >-
+ Response metadata carried alongside the primary `data` payload. All fields are
+ optional; list endpoints populate `next_page_token` for cursor pagination.
+ properties:
+ next_page_token:
+ type: string
+ description: >-
+ Opaque cursor for the next page of a list response. Absent when there are no
+ further results — never present and empty — otherwise pass it back as the
+ `page_token` query parameter to fetch the next page.
+ examples:
+ - eyJvZmZzZXQiOjI1fQ
+ additionalProperties: true
+ examples:
+ - next_page_token: eyJvZmZzZXQiOjI1fQ
+
+ Envelope:
+ type: object
+ title: Envelope
+ description: >-
+ The success envelope wrapping every 2xx response body: the resource or list of
+ resources under `data`, with optional `meta`. This is the single success shape for
+ the API — there are no unenveloped success bodies. Endpoints narrow `data` to a
+ concrete resource via `allOf`; the base leaves `data` unconstrained so that
+ composition works.
+ required:
+ - data
+ properties:
+ data:
+ type: [object, array]
+ # Required for `data` to actually be unconstrained. Without it, openapi-typescript
+ # emits `Record` — an object permitting no properties — and the
+ # composed `Envelope & { data: Resource }` becomes unassignable, so nothing can use
+ # the generated response type.
+ additionalProperties: true
+ description: The primary response payload — a resource, or an array of resources for list endpoints.
+ meta:
+ $ref: "#/components/schemas/Meta"
+ examples:
+ - data:
+ username: acme-ops
+ meta:
+ next_page_token: eyJvZmZzZXQiOjI1fQ
+
+ # --- Resources ----------------------------------------------------------------------
+ # Resource schemas are the public DTO surface — what the v1 contract guarantees to
+ # integrators. Field names are snake_case. Fields are added additively under the v1
+ # stability policy; renames or removals require v2.
+ UserEmailAddress:
+ type: object
+ title: UserEmailAddress
+ description: An email address belonging to a user.
+ required:
+ - address
+ - is_verified
+ - is_primary
+ properties:
+ address:
+ type: string
+ description: The email address.
+ examples:
+ - ops@acme.com
+ is_verified:
+ type: boolean
+ description: Whether the address has completed email verification.
+ is_primary:
+ type: boolean
+ description: >-
+ Whether this is the user's primary address. Exactly one address is primary.
+ User:
+ type: object
+ title: User
+ description: >-
+ A Hosted user. `GET /api/v1/user` returns the authenticated user's profile. v1
+ returns only public-facing profile fields — the identity provider the account signs
+ in with, session state, and credential metadata are never included.
+ required:
+ - username
+ - email_addresses
+ properties:
+ username:
+ type: string
+ description: The user's Hosted username (unique handle).
+ examples:
+ - acme-ops
+ display_name:
+ type: string
+ description: The user's display name. May be empty.
+ examples:
+ - Acme Operations
+ company:
+ type: string
+ description: The user's stated company. May be empty.
+ examples:
+ - Acme Corp
+ email_addresses:
+ type: array
+ description: >-
+ The user's email addresses. Returned only for the authenticated user
+ themselves; empty for any other caller.
+ items:
+ $ref: "#/components/schemas/UserEmailAddress"
+
+ InstanceType:
+ type: object
+ title: InstanceType
+ description: A compute instance type a deployment can run on.
+ required:
+ - id
+ - name
+ properties:
+ id:
+ type: string
+ description: >-
+ The identifier `POST /api/v1/deployments` accepts as `instance_type_id`.
+ examples:
+ - aws.t2.medium
+ name:
+ type: string
+ description: The display name. A deployment reports this as `instance_type_name`.
+ examples:
+ - t2.medium
+ cpus:
+ type: integer
+ format: int32
+ description: Virtual CPUs.
+ examples:
+ - 2
+ memory_gb:
+ type: integer
+ format: int32
+ description: Memory, in gigabytes.
+ examples:
+ - 4
+ description:
+ type: string
+ description: A human-readable summary of what the instance suits.
+ examples:
+ - Trial tier, the lowest spec that runs a Dolt SQL server.
+ hourly_cost_usd:
+ type: number
+ format: float
+ description: >-
+ Cost per hour in US dollars. Absent when no hourly price is published for this
+ instance type.
+ examples:
+ - 0.06849315
+
+ StorageOption:
+ type: object
+ title: StorageOption
+ description: A storage type a deployment's volume can use.
+ required:
+ - id
+ - name
+ properties:
+ id:
+ type: string
+ description: >-
+ The identifier `POST /api/v1/deployments` accepts as `volume_type_id`.
+ examples:
+ - aws.ebs.gp3_50
+ name:
+ type: string
+ description: The display name. A deployment reports this as `volume_type_name`.
+ examples:
+ - Trial 50GB EBS
+ description:
+ type: string
+ description: A human-readable summary of the storage type.
+ examples:
+ - Trial tier storage capped at 50GB
+ min_size_gb:
+ type: integer
+ format: int32
+ description: >-
+ Smallest volume size this type supports, in gigabytes. `volume_size_gb` on a
+ create request must be at least this.
+ examples:
+ - 50
+ max_size_gb:
+ type: integer
+ format: int32
+ description: >-
+ Largest volume size this type supports, in gigabytes.
+ examples:
+ - 50
+ monthly_cost_usd_per_gb:
+ type: number
+ format: float
+ description: Cost per gigabyte per month, in US dollars.
+ examples:
+ - 0
+
+ DeploymentInstance:
+ type: object
+ title: DeploymentInstance
+ description: >-
+ One instance backing a deployment. A deployment has a primary and, when it has read
+ replicas, one instance per replica.
+ required:
+ - id
+ - index
+ - is_primary
+ properties:
+ id:
+ type: string
+ format: uuid
+ description: The instance's identifier, unique within the deployment.
+ examples:
+ - 9b1f5c2e-4d3a-4f8b-9c0d-1e2f3a4b5c6d
+ index:
+ type: integer
+ format: int32
+ description: >-
+ The instance's position in the deployment. `0` is the first instance; replicas
+ take the following indices.
+ examples:
+ - 0
+ is_primary:
+ type: boolean
+ description: >-
+ Whether this instance is currently the primary. Exactly one instance of a
+ started deployment is primary, and which one can change over the deployment's
+ life.
+ examples:
+ - true
+ host:
+ type: string
+ description: >-
+ The hostname for this specific instance. Connect to the deployment's own `host`
+ unless you mean to address one instance directly.
+ examples:
+ - analytics-0.dbs.hosted.doltdb.com
+ instance_type_name:
+ type: string
+ description: The display name of this instance's type.
+ examples:
+ - t2.medium
+ volume_type_name:
+ type: string
+ description: The display name of this instance's storage type.
+ examples:
+ - Trial 50GB EBS
+ volume_size_gb:
+ type: integer
+ format: int32
+ description: The size of this instance's storage volume, in gigabytes.
+ examples:
+ - 50
+ hourly_cost_usd:
+ type: number
+ format: float
+ description: >-
+ This instance's cost per hour, in US dollars. A deployment's total is the sum
+ across its instances.
+ examples:
+ - 0.06849315
+
+ DeploymentOptions:
+ type: object
+ title: DeploymentOptions
+ description: >-
+ The options available for creating a deployment, narrowed by the query parameters
+ supplied. `instance_types` and `storage_options` are absent until enough of the
+ chain has been supplied to determine them.
+ required:
+ - cloud
+ - zones
+ properties:
+ cloud:
+ $ref: "#/components/schemas/CloudProvider"
+ zones:
+ type: array
+ description: The zones this cloud supports.
+ items:
+ type: string
+ examples:
+ - ["us-east-1", "us-west-2", "eu-west-2"]
+ instance_types:
+ type: array
+ description: >-
+ Instance types available in the requested `zone`. Absent when `zone` wasn't
+ supplied.
+ items:
+ $ref: "#/components/schemas/InstanceType"
+ storage_options:
+ type: array
+ description: >-
+ Storage types compatible with the requested `instance_type_id`. Absent when
+ `zone` and `instance_type_id` weren't both supplied.
+ items:
+ $ref: "#/components/schemas/StorageOption"
+
+ CreateDeploymentRequest:
+ type: object
+ title: CreateDeploymentRequest
+ description: >-
+ The provisioning parameters for a new deployment.
+
+
+ v1.0 exposes the core parameters only. Restoring from a backup, cloning an existing
+ deployment, workbench user settings, and private networking are all settable on the
+ internal API but are not part of this request; each is its own feature with its own
+ contract, and adding them is additive. The internal deployment test flag is
+ deliberately not exposed at all.
+ required:
+ - owner
+ - name
+ - cloud
+ - zone
+ - instance_type_id
+ - volume_type_id
+ - volume_size_gb
+ properties:
+ owner:
+ type: string
+ description: >-
+ The user or organization that will own the deployment. The caller must have
+ permission to create deployments for it. 3–32 characters of letters, digits,
+ hyphens, and underscores.
+ pattern: "^[-a-zA-Z0-9_]{3,32}$"
+ examples:
+ - acme
+ name:
+ type: string
+ description: >-
+ The deployment name, unique within the owner. 3–32 characters of letters,
+ digits, hyphens, and underscores.
+ pattern: "^[-a-zA-Z0-9_]{3,32}$"
+ examples:
+ - analytics
+ cloud:
+ $ref: "#/components/schemas/CloudProvider"
+ zone:
+ type: string
+ description: The cloud region to provision in, as listed by the deployment options.
+ minLength: 1
+ examples:
+ - us-east-1
+ cluster_type:
+ $ref: "#/components/schemas/ClusterType"
+ instance_type_id:
+ type: string
+ description: >-
+ The **id** of the instance type, from the deployment options endpoint. Note a
+ deployment reports `instance_type_name` on a read — the id and the display name
+ are different values.
+ minLength: 1
+ examples:
+ - aws.t2.medium
+ volume_type_id:
+ type: string
+ description: >-
+ The **id** of the storage type, from the deployment options endpoint. As with
+ `instance_type_id`, this is the id rather than the display name.
+ minLength: 1
+ examples:
+ - aws.ebs.gp3_50
+ volume_size_gb:
+ type: integer
+ format: int32
+ description: >-
+ The size of the storage volume, in gigabytes. Must fall within the selected
+ storage type's supported range.
+ minimum: 1
+ examples:
+ - 50
+ replicas:
+ type: integer
+ format: int32
+ description: The number of read replicas. Defaults to `0` when omitted.
+ minimum: 0
+ examples:
+ - 2
+ webpki_cert:
+ type: boolean
+ description: >-
+ Serve a publicly-trusted (WebPKI) TLS certificate rather than a Hosted-issued
+ one. Defaults to `false` when omitted.
+ examples:
+ - true
+ expose_remotesapi_endpoint:
+ type: boolean
+ description: Expose a Dolt remotes API endpoint. Defaults to `false` when omitted.
+ examples:
+ - false
+ expose_mcp:
+ type: boolean
+ description: Expose an MCP endpoint. Defaults to `false` when omitted.
+ examples:
+ - false
+ expose_stats:
+ type: boolean
+ description: Expose a statistics endpoint. Defaults to `false` when omitted.
+ examples:
+ - false
+
+ DeploymentState:
+ type: string
+ title: DeploymentState
+ description: >-
+ The deployment's lifecycle state. `starting` covers both initial provisioning and
+ a restart; poll this field to observe a create or a resize reaching `started`.
+ enum:
+ - starting
+ - started
+ - stopping
+ - stopped
+ examples:
+ - started
+
+ CloudProvider:
+ type: string
+ title: CloudProvider
+ description: The cloud the deployment runs in.
+ enum:
+ - aws
+ - gcp
+ - azure
+ examples:
+ - aws
+
+ ClusterType:
+ type: string
+ title: ClusterType
+ description: >-
+ The database engine the deployment runs. `mysql_with_dolt_replicas` is a MySQL
+ primary with Dolt read replicas.
+ enum:
+ - dolt
+ - doltgres
+ - mysql_with_dolt_replicas
+ examples:
+ - dolt
+
+ DeploymentRole:
+ type: string
+ title: DeploymentRole
+ description: >-
+ The authenticated caller's role on this deployment. Always present on a read, since
+ a caller without at least read access cannot retrieve the deployment at all.
+ enum:
+ - admin
+ - writer
+ - reader
+ - reader_and_pulls
+ examples:
+ - admin
+
+ DeploymentSummary:
+ type: object
+ title: DeploymentSummary
+ description: >-
+ A deployment as it appears in a list.
+
+
+ This is deliberately not the same shape as `Deployment`. The list RPC returns a
+ narrower record — it omits connection details, the caller's role, and the creation
+ audit fields, and it adds the last-backup figures shown in fleet views. Read the
+ deployment itself for the full resource. As with `Deployment`, database credentials
+ are never included.
+ required:
+ - owner
+ - name
+ - state
+ - cloud
+ - zone
+ - cluster_type
+ properties:
+ owner:
+ type: string
+ description: The user or organization that owns the deployment.
+ examples:
+ - acme
+ name:
+ type: string
+ description: The deployment name, unique within the owner.
+ examples:
+ - analytics
+ state:
+ $ref: "#/components/schemas/DeploymentState"
+ cloud:
+ $ref: "#/components/schemas/CloudProvider"
+ zone:
+ type: string
+ description: The cloud region the deployment runs in.
+ examples:
+ - us-west-2
+ cluster_type:
+ $ref: "#/components/schemas/ClusterType"
+ instance_type_name:
+ type: string
+ description: The display name of the deployment's instance type.
+ examples:
+ - m5.large
+ volume_type_name:
+ type: string
+ description: The display name of the deployment's storage type.
+ examples:
+ - gp3
+ volume_size_gb:
+ type: integer
+ format: int32
+ description: The size of the deployment's storage volume, in gigabytes.
+ examples:
+ - 100
+ replicas:
+ type: integer
+ format: int32
+ description: The number of read replicas. `0` for a single-instance deployment.
+ examples:
+ - 0
+ database_version:
+ type: string
+ description: >-
+ The version of the database engine the deployment is running — a Dolt version
+ for a `dolt` cluster, a Doltgres version for a `doltgres` one.
+ examples:
+ - 1.58.4
+ hourly_cost_usd:
+ type: number
+ format: float
+ description: The deployment's current cost per hour, in US dollars.
+ examples:
+ - 0.192
+ webpki_cert:
+ type: boolean
+ description: >-
+ Whether the deployment serves a publicly-trusted (WebPKI) TLS certificate.
+ examples:
+ - true
+ last_backup_size_bytes:
+ type: integer
+ format: int64
+ description: >-
+ Size of the most recent backup, in bytes. Absent when no backup has been taken
+ or its size has not been computed yet.
+ examples:
+ - 1048576
+ last_backup_time:
+ type: string
+ format: date-time
+ description: >-
+ When the most recent backup was taken. Absent when no backup has been taken.
+ examples:
+ - "2026-08-10T02:00:00Z"
+
+ Deployment:
+ type: object
+ title: Deployment
+ description: >-
+ A Hosted Dolt deployment.
+
+
+ v1 returns configuration and lifecycle state only. The deployment's database
+ credentials are deliberately **not** part of this resource — they are issued and
+ rotated through the deployment credentials endpoints, so that reading a deployment
+ is never a credential-disclosing operation.
+
+
+ Provider-specific private-networking configuration (AWS PrivateLink, GCP Private
+ Service Connect, Azure Private Link) is not included in v1.0. Each carries its own
+ endpoint collection and provisioning state, and will land as its own sub-resource;
+ adding it is additive under the stability policy.
+ required:
+ - owner
+ - name
+ - state
+ - cloud
+ - zone
+ - cluster_type
+ - caller_role
+ - created_at
+ properties:
+ owner:
+ type: string
+ description: The user or organization that owns the deployment.
+ examples:
+ - acme
+ name:
+ type: string
+ description: The deployment name, unique within the owner.
+ examples:
+ - analytics
+ state:
+ $ref: "#/components/schemas/DeploymentState"
+ cloud:
+ $ref: "#/components/schemas/CloudProvider"
+ zone:
+ type: string
+ description: The cloud region the deployment runs in.
+ examples:
+ - us-east-1
+ cluster_type:
+ $ref: "#/components/schemas/ClusterType"
+ instance_type_name:
+ type: string
+ description: >-
+ The display name of the deployment's instance type. Note this is the *name*, not
+ the id that `POST /api/v1/deployments` accepts; both are listed by the deployment
+ options endpoint.
+ examples:
+ - t2.medium
+ volume_type_name:
+ type: string
+ description: >-
+ The display name of the deployment's storage type. As with `instance_type_name`,
+ this is the name rather than the id used to create a deployment.
+ examples:
+ - Trial 50GB EBS
+ volume_size_gb:
+ type: integer
+ format: int32
+ description: The size of the deployment's storage volume, in gigabytes.
+ examples:
+ - 50
+ replicas:
+ type: integer
+ format: int32
+ description: The number of read replicas. `0` for a single-instance deployment.
+ examples:
+ - 0
+ database_version:
+ type: string
+ description: >-
+ The version of the database engine the deployment is running — a Dolt version
+ for a `dolt` cluster, a Doltgres version for a `doltgres` one.
+ examples:
+ - 1.58.4
+ host:
+ type: string
+ description: >-
+ The hostname clients connect to. Empty until the deployment reaches `started`.
+ examples:
+ - analytics.dbs.hosted.doltdb.com
+ port:
+ type: integer
+ format: int32
+ description: The port clients connect to.
+ examples:
+ - 3306
+ hourly_cost_usd:
+ type: number
+ format: float
+ description: The deployment's current cost per hour, in US dollars.
+ examples:
+ - 0.06849315
+ webpki_cert:
+ type: boolean
+ description: >-
+ Whether the deployment serves a publicly-trusted (WebPKI) TLS certificate rather
+ than a Hosted-issued one.
+ expose_remotesapi_endpoint:
+ type: boolean
+ description: Whether the deployment exposes a Dolt remotes API endpoint.
+ expose_mcp:
+ type: boolean
+ description: Whether the deployment exposes an MCP endpoint.
+ expose_stats:
+ type: boolean
+ description: Whether the deployment exposes a statistics endpoint.
+ disable_automatic_dolt_updates:
+ type: boolean
+ description: >-
+ Whether automatic Dolt version updates are disabled for this deployment.
+ caller_role:
+ $ref: "#/components/schemas/DeploymentRole"
+ created_by:
+ type: string
+ description: The username of the user who created the deployment.
+ examples:
+ - acme-ops
+ created_at:
+ type: string
+ format: date-time
+ description: When the deployment was created.
+ examples:
+ - "2026-07-01T18:22:04Z"
+ destroy_at:
+ type: string
+ format: date-time
+ description: >-
+ When the deployment is scheduled to be destroyed. Absent unless a destroy has
+ been scheduled.
+ examples:
+ - "2026-09-01T00:00:00Z"
+ destroyed_by:
+ type: string
+ description: >-
+ The username of the user who destroyed the deployment. Absent unless it has been
+ destroyed.
+ examples:
+ - acme-ops
+
+ responses:
+ BadRequest:
+ description: The request was malformed or failed input validation.
+ headers:
+ x-request-id:
+ $ref: "#/components/headers/RequestId"
+ content:
+ application/problem+json:
+ schema:
+ $ref: "#/components/schemas/Problem"
+ Unauthorized:
+ description: Authentication credentials were missing or invalid.
+ headers:
+ x-request-id:
+ $ref: "#/components/headers/RequestId"
+ content:
+ application/problem+json:
+ schema:
+ $ref: "#/components/schemas/Problem"
+ Forbidden:
+ description: Authenticated, but not permitted to perform this action.
+ headers:
+ x-request-id:
+ $ref: "#/components/headers/RequestId"
+ content:
+ application/problem+json:
+ schema:
+ $ref: "#/components/schemas/Problem"
+ NotFound:
+ description: The requested resource does not exist.
+ headers:
+ x-request-id:
+ $ref: "#/components/headers/RequestId"
+ content:
+ application/problem+json:
+ schema:
+ $ref: "#/components/schemas/Problem"
+ MethodNotAllowed:
+ description: The HTTP method is not supported for this resource.
+ headers:
+ x-request-id:
+ $ref: "#/components/headers/RequestId"
+ Allow:
+ description: The HTTP methods supported by this resource.
+ schema:
+ type: string
+ content:
+ application/problem+json:
+ schema:
+ $ref: "#/components/schemas/Problem"
+ Conflict:
+ description: The request conflicts with the current state of the resource (e.g. it already exists).
+ headers:
+ x-request-id:
+ $ref: "#/components/headers/RequestId"
+ content:
+ application/problem+json:
+ schema:
+ $ref: "#/components/schemas/Problem"
+ UnprocessableEntity:
+ description: The request was well-formed but semantically invalid.
+ headers:
+ x-request-id:
+ $ref: "#/components/headers/RequestId"
+ content:
+ application/problem+json:
+ schema:
+ $ref: "#/components/schemas/Problem"
+ TooManyRequests:
+ description: The client has exceeded its rate limit.
+ headers:
+ x-request-id:
+ $ref: "#/components/headers/RequestId"
+ Retry-After:
+ description: The number of seconds to wait before retrying the request.
+ schema:
+ type: integer
+ format: int32
+ content:
+ application/problem+json:
+ schema:
+ $ref: "#/components/schemas/Problem"
+ InternalServerError:
+ description: An unexpected server error occurred.
+ headers:
+ x-request-id:
+ $ref: "#/components/headers/RequestId"
+ content:
+ application/problem+json:
+ schema:
+ $ref: "#/components/schemas/Problem"
+ ServiceUnavailable:
+ description: The service is temporarily unavailable.
+ headers:
+ x-request-id:
+ $ref: "#/components/headers/RequestId"
+ content:
+ application/problem+json:
+ schema:
+ $ref: "#/components/schemas/Problem"