{
  "openapi": "3.0.3",
  "info": {
    "title": "Brandlit Studio HTTP API",
    "version": "2026-10-05.3",
    "description": "Public HTTP API for Brandlit Studio: projects, Connect with Grok Bot (device code), Grok website edits, Brandlit-hosted publishing, and bring-your-own-domain attach via DNS CNAME.\n\n**Auth:** cookie session today. Guest identity uses the `bl_uid` cookie (or `X-Brandlit-Uid` header); signing in or completing Connect sets the HttpOnly `bl_session` cookie. Machine Bearer tokens are not available yet.\n\n**curl:** use a cookie jar (`-c jar.txt -b jar.txt`) on every call so identity sticks.\n\n**CLI:** `brandlit` v1.0.0 (zero-dependency Node 18+) wraps this API. See /docs/CLI-README.md.\n\n**Prices:** read the current catalog from `GET /api/billing/products`; do not hard-code amounts.",
    "contact": {
      "name": "BlackLabel Tech",
      "url": "https://blacklabelbots.com"
    }
  },
  "servers": [
    {
      "url": "https://brandlit.blacklabelbots.com",
      "description": "Production Brandlit Studio"
    }
  ],
  "tags": [
    {
      "name": "Discovery"
    },
    {
      "name": "Auth"
    },
    {
      "name": "Connect"
    },
    {
      "name": "DomOps"
    },
    {
      "name": "KeyVault"
    },
    {
      "name": "Projects"
    },
    {
      "name": "Domains"
    },
    {
      "name": "Billing"
    },
    {
      "name": "Usage"
    },
    {
      "name": "Templates"
    },
    {
      "name": "Hosting"
    }
  ],
  "paths": {
    "/health": {
      "get": {
        "tags": [
          "Discovery"
        ],
        "summary": "Capability map",
        "operationId": "getHealth",
        "security": [],
        "responses": {
          "200": {
            "description": "Live capability flags and service status",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/mode": {
      "get": {
        "tags": [
          "Discovery"
        ],
        "summary": "Brain mode without requiring a signed-in session",
        "operationId": "getMode",
        "security": [
          {
            "cookieGuest": []
          },
          {
            "cookieSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Brain / site mode",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModeResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/signup": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Create email+password account; sets bl_session",
        "operationId": "authSignup",
        "security": [
          {
            "cookieGuest": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "password"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "password": {
                    "type": "string",
                    "minLength": 8,
                    "maxLength": 200
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Account created; Set-Cookie bl_session",
            "headers": {
              "Set-Cookie": {
                "schema": {
                  "type": "string"
                },
                "description": "bl_session=\u2026; Path=/; HttpOnly; SameSite=Lax"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthSessionResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "description": "Account already exists",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/signin": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Sign in; sets bl_session",
        "operationId": "authSignin",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "password"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "password": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Signed in; Set-Cookie bl_session",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthSessionResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/auth/signout": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Clear bl_session",
        "operationId": "authSignout",
        "security": [
          {
            "cookieSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Signed out; clears bl_session cookie",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "signedOut": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/me": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "Session + usage meters",
        "operationId": "authMe",
        "security": [
          {
            "cookieGuest": []
          },
          {
            "cookieSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Guest or authed identity plus usage",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthMeResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/forgot": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Password reset request (may return a copyable reset link when email delivery is unavailable)",
        "operationId": "authForgot",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Always ok-shaped (anti-enumeration); issued may be false",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "issued": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "smtpSent": {
                      "type": "boolean"
                    },
                    "resetUrl": {
                      "type": "string",
                      "description": "Present when a reset link is returned directly instead of by email"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/reset": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Complete password reset with KV token",
        "operationId": "authReset",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "token",
                  "password"
                ],
                "properties": {
                  "token": {
                    "type": "string"
                  },
                  "password": {
                    "type": "string",
                    "minLength": 8
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Password updated; may mint bl_session",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkEnvelope"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/auth/grokbot/start": {
      "get": {
        "tags": [
          "Connect"
        ],
        "summary": "Start device-code Connect with Grok Bot",
        "operationId": "grokbotStart",
        "security": [
          {
            "cookieGuest": []
          },
          {
            "cookieSession": []
          }
        ],
        "parameters": [
          {
            "name": "mode",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "oauth"
              ]
            },
            "description": "If Cursor OAuth client configured, redirects; production typically returns device_code JSON"
          }
        ],
        "responses": {
          "200": {
            "description": "Device-code payload",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GrokBotStartResponse"
                }
              }
            }
          },
          "302": {
            "description": "OAuth authorize redirect when mode=oauth and CURSOR_OAUTH_CLIENT_ID set"
          }
        }
      }
    },
    "/api/auth/grokbot/poll": {
      "get": {
        "tags": [
          "Connect"
        ],
        "summary": "Poll device code until approved; mints bl_session",
        "operationId": "grokbotPoll",
        "security": [
          {
            "cookieGuest": []
          },
          {
            "cookieSession": []
          }
        ],
        "parameters": [
          {
            "name": "device_code",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "pending or approved (approved sets bl_session)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GrokBotPollResponse"
                }
              }
            }
          },
          "403": {
            "description": "Denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "404": {
            "description": "Expired or unknown device_code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/grokbot/approve": {
      "post": {
        "tags": [
          "Connect"
        ],
        "summary": "Same-browser user approve",
        "description": "Live Worker route. Body needs device_code or user_code.",
        "operationId": "grokbotApprove",
        "security": [
          {
            "cookieGuest": []
          },
          {
            "cookieSession": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "device_code": {
                    "type": "string"
                  },
                  "user_code": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Device marked approved \u2014 client should poll",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkEnvelope"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/auth/grokbot/callback": {
      "get": {
        "tags": [
          "Connect"
        ],
        "summary": "OAuth callback (not enabled; returns 501, use device code)",
        "operationId": "grokbotCallback",
        "security": [],
        "parameters": [
          {
            "name": "code",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "state",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect to app when code/state missing"
          },
          "501": {
            "description": "Cursor OAuth not configured / token exchange not implemented \u2014 use device-code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/grokbot/status": {
      "get": {
        "tags": [
          "Connect"
        ],
        "summary": "Link + platform brain flags",
        "operationId": "grokbotStatus",
        "security": [
          {
            "cookieGuest": []
          },
          {
            "cookieSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Status",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GrokBotStatusResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/grokbot/disconnect": {
      "post": {
        "tags": [
          "Connect"
        ],
        "summary": "Clear Grok Bot entitlement for current identity",
        "operationId": "grokbotDisconnect",
        "security": [
          {
            "cookieGuest": []
          },
          {
            "cookieSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Disconnected",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "disconnected": {
                      "type": "boolean"
                    },
                    "grokBotLinked": {
                      "type": "boolean"
                    },
                    "hasGrokBrain": {
                      "type": "boolean"
                    },
                    "brainMode": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/grok": {
      "post": {
        "tags": [
          "DomOps"
        ],
        "summary": "DomOps inference (utterance \u2192 ops JSON)",
        "description": "Requires Connect entitlement and/or key path depending on live gate.\nObserved error codes include `connect_grokbot`, `needs_key`, `free_exhausted`, `platform_brain_unconfigured`.\nTransport is platform xAI chat/completions when linked (not CLI subscription proxy).\n",
        "operationId": "grokRun",
        "security": [
          {
            "cookieGuest": []
          },
          {
            "cookieSession": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "utterance"
                ],
                "properties": {
                  "utterance": {
                    "type": "string",
                    "description": "Natural language edit request"
                  },
                  "text": {
                    "type": "string",
                    "description": "Alias for utterance"
                  },
                  "snapshot": {
                    "type": "object",
                    "description": "Current layout snapshot (opaque to API; forwarded to model)"
                  },
                  "model": {
                    "type": "string",
                    "description": "Optional model override (default grok-3-mini / Worker XAI_MODEL)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "DomOps batch",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GrokSuccessResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "402": {
            "description": "Free meter exhausted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          },
          "503": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/grok/test": {
      "get": {
        "tags": [
          "DomOps"
        ],
        "summary": "Ping platform/BYOK key",
        "operationId": "grokTestGet",
        "security": [
          {
            "cookieGuest": []
          },
          {
            "cookieSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Key/platform ping ok",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GrokTestResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "503": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "tags": [
          "DomOps"
        ],
        "summary": "Ping with optional key in body",
        "operationId": "grokTestPost",
        "security": [
          {
            "cookieGuest": []
          },
          {
            "cookieSession": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "key": {
                    "type": "string"
                  },
                  "apiKey": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Key/platform ping ok",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GrokTestResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/key": {
      "post": {
        "tags": [
          "KeyVault"
        ],
        "summary": "Save advanced BYOK xAI key (AES-GCM in KV)",
        "operationId": "keySave",
        "security": [
          {
            "cookieGuest": []
          },
          {
            "cookieSession": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "key": {
                    "type": "string"
                  },
                  "apiKey": {
                    "type": "string"
                  },
                  "xaiKey": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Stored (hint only returned)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "hasKey": {
                      "type": "boolean"
                    },
                    "hint": {
                      "type": "string"
                    },
                    "mode": {
                      "type": "string",
                      "example": "byok"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "delete": {
        "tags": [
          "KeyVault"
        ],
        "summary": "Clear vaulted BYOK key",
        "operationId": "keyClear",
        "security": [
          {
            "cookieGuest": []
          },
          {
            "cookieSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Cleared",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "hasKey": {
                      "type": "boolean"
                    },
                    "mode": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/key/status": {
      "get": {
        "tags": [
          "KeyVault"
        ],
        "summary": "BYOK vault status (no raw key)",
        "operationId": "keyStatus",
        "security": [
          {
            "cookieGuest": []
          },
          {
            "cookieSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Status",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "hasKey": {
                      "type": "boolean"
                    },
                    "hint": {
                      "type": "string",
                      "nullable": true
                    },
                    "uid": {
                      "type": "string"
                    },
                    "mode": {
                      "type": "string"
                    },
                    "designedFor": {
                      "type": "string"
                    },
                    "note": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/projects": {
      "get": {
        "tags": [
          "Projects"
        ],
        "summary": "List projects for current identity",
        "operationId": "projectsList",
        "security": [
          {
            "cookieGuest": []
          },
          {
            "cookieSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Project list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProjectListResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Projects"
        ],
        "summary": "Create project",
        "description": "Cookie identity owns the project. Live accepts `name`, `mode`, and (when catalog matches) `templateId`.\nUnknown `templateId` returns `code: unknown_template`. Blank create without templateId is the reliable path.\n",
        "operationId": "projectsCreate",
        "security": [
          {
            "cookieGuest": []
          },
          {
            "cookieSession": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 80
                  },
                  "mode": {
                    "type": "string",
                    "enum": [
                      "blank",
                      "salesswipe"
                    ],
                    "default": "blank"
                  },
                  "templateId": {
                    "type": "string",
                    "description": "Optional; must match live template catalog ids"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProjectCreateResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "402": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/projects/{projectId}": {
      "get": {
        "tags": [
          "Projects"
        ],
        "summary": "Get project meta + HTML + ops + sidecar + assets",
        "operationId": "projectsGet",
        "security": [
          {
            "cookieGuest": []
          },
          {
            "cookieSession": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/projectId"
          }
        ],
        "responses": {
          "200": {
            "description": "Project, html, ops, sidecar, and asset list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProjectGetResponse"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "put": {
        "tags": [
          "Projects"
        ],
        "summary": "Save snapshot (alias of POST \u2026/save)",
        "operationId": "projectsPut",
        "security": [
          {
            "cookieGuest": []
          },
          {
            "cookieSession": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/projectId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProjectSaveBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProjectCreateResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/projects/{projectId}/save": {
      "post": {
        "tags": [
          "Projects"
        ],
        "summary": "Save HTML/ops snapshot to KV (+ R2 mirror on save path when configured)",
        "operationId": "projectsSave",
        "security": [
          {
            "cookieGuest": []
          },
          {
            "cookieSession": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/projectId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProjectSaveBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProjectCreateResponse"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/projects/{projectId}/publish": {
      "post": {
        "tags": [
          "Projects",
          "Hosting"
        ],
        "summary": "Mark published; returns pathUrl + siteUrl + BYO CNAME target",
        "operationId": "projectsPublish",
        "security": [
          {
            "cookieGuest": []
          },
          {
            "cookieSession": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/projectId"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "html": {
                    "type": "string",
                    "description": "Optional HTML to save before publish"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Published URLs",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProjectPublishResponse"
                }
              }
            }
          }
        }
      }
    },
    "/p/{projectId}": {
      "get": {
        "tags": [
          "Hosting"
        ],
        "summary": "Public published HTML with absolute project-asset URLs",
        "operationId": "publicPath",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/projectId"
          }
        ],
        "responses": {
          "200": {
            "description": "text/html. Header `x-brandlit-asset-rewrite` = count of rewritten refs. Header `x-brandlit-ext: project-ext/1` when served by brandlit-project-ext.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "Not found"
          }
        },
        "description": "Returns the project's saved HTML for a published project (editor chrome stripped; edge may inject `.webmcp/bridge.js`). Serve-time only: matching relative asset refs (`src`, `href`, `srcset`, CSS `url()`) that correspond to uploaded `/api/projects/{id}/assets` paths are rewritten to absolute `https://brandlit.blacklabelbots.com/project-assets/{id}/{path}`. Absolute http(s), data:, and root-absolute `/\u2026` URLs are left unchanged. Draft HTML from `GET /api/projects/{id}` stays relative (byte-equal to save). Unpublished \u2192 404 for anonymous."
      }
    },
    "/api/domain/instructions": {
      "get": {
        "tags": [
          "Domains"
        ],
        "summary": "BYO CNAME + preview/site URL templates",
        "operationId": "domainInstructions",
        "security": [],
        "parameters": [
          {
            "name": "projectId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Substituted into CNAME/preview examples when valid"
          }
        ],
        "responses": {
          "200": {
            "description": "Instructions",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DomainInstructionsResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/domain/search": {
      "get": {
        "tags": [
          "Domains"
        ],
        "summary": "Search registrable names (CF Registrar when token works; else DNS suggestions)",
        "operationId": "domainSearch",
        "security": [],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 8
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Search rows",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DomainSearchResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/domain/check": {
      "post": {
        "tags": [
          "Domains"
        ],
        "summary": "Check domain(s) registrability / pricing",
        "operationId": "domainCheck",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "domains": {
                    "oneOf": [
                      {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      },
                      {
                        "type": "string"
                      }
                    ]
                  },
                  "domain": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Check result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/domain/buy": {
      "post": {
        "tags": [
          "Domains"
        ],
        "summary": "Attempt register (often blocked \u2192 BYO guidance)",
        "description": "Partial. When registrar write is missing or billing/contact blocks purchase,\nresponse still returns `byo` attach guidance (HTTP 200 with ok:false or guided payload).\nReliable path for integrators: attach + verify CNAME.\n",
        "operationId": "domainBuy",
        "security": [
          {
            "cookieGuest": []
          },
          {
            "cookieSession": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "domain": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  },
                  "projectId": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Registered, guided, or BYO-required payload",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkEnvelope"
                }
              }
            }
          },
          "409": {
            "description": "Not registrable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      }
    },
    "/api/domain/attach": {
      "post": {
        "tags": [
          "Domains"
        ],
        "summary": "Bind custom hostname to owned project",
        "operationId": "domainAttach",
        "security": [
          {
            "cookieGuest": []
          },
          {
            "cookieSession": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "projectId"
                ],
                "properties": {
                  "domain": {
                    "type": "string"
                  },
                  "hostname": {
                    "type": "string"
                  },
                  "projectId": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Attached (verified false until DNS)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkEnvelope"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/domain/verify": {
      "post": {
        "tags": [
          "Domains"
        ],
        "summary": "DoH CNAME / Brandlit header verify",
        "operationId": "domainVerify",
        "security": [
          {
            "cookieGuest": []
          },
          {
            "cookieSession": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "domain": {
                    "type": "string"
                  },
                  "hostname": {
                    "type": "string"
                  },
                  "projectId": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "verified true/false with dns details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/billing/products": {
      "get": {
        "tags": [
          "Billing"
        ],
        "summary": "Product catalog JSON",
        "description": "Current product catalog returned by the live service. Use this as the source for prices; do not hard-code amounts.",
        "operationId": "billingProducts",
        "security": [],
        "responses": {
          "200": {
            "description": "Products",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingProductsResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/billing/checkout": {
      "post": {
        "tags": [
          "Billing"
        ],
        "summary": "Start Stripe Checkout",
        "description": "Requires a signed-in `bl_session`. Amounts come from the live product catalog.",
        "operationId": "billingCheckout",
        "security": [
          {
            "cookieSession": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "product": {
                    "type": "string",
                    "description": "Product id from GET /api/billing/products"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Checkout URL, or an already-owned result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkEnvelope"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/billing/confirm": {
      "get": {
        "tags": [
          "Billing"
        ],
        "summary": "Confirm payment / session (auth required)",
        "operationId": "billingConfirmGet",
        "security": [
          {
            "cookieSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Confirmed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkEnvelope"
                }
              }
            }
          },
          "401": {
            "description": "Sign in required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorBody"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Billing"
        ],
        "summary": "Confirm payment / session (auth required)",
        "operationId": "billingConfirmPost",
        "security": [
          {
            "cookieSession": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "sessionId": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Confirmed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkEnvelope"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/usage": {
      "get": {
        "tags": [
          "Usage"
        ],
        "summary": "Usage meters for current identity",
        "operationId": "usageGet",
        "security": [
          {
            "cookieGuest": []
          },
          {
            "cookieSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Usage",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "usage": {
                      "$ref": "#/components/schemas/UsagePublic"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/usage/heartbeat": {
      "post": {
        "tags": [
          "Usage"
        ],
        "summary": "Advance editor time meter",
        "operationId": "usageHeartbeat",
        "security": [
          {
            "cookieGuest": []
          },
          {
            "cookieSession": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "focused": {
                    "type": "boolean",
                    "default": true
                  },
                  "deltaSec": {
                    "type": "number",
                    "description": "Clamped (Worker HEARTBEAT_MAX_DELTA)"
                  },
                  "seconds": {
                    "type": "number",
                    "description": "Alias for deltaSec"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated usage; may include code free_exhausted when gated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/templates": {
      "get": {
        "tags": [
          "Templates"
        ],
        "summary": "Template catalog (+ previews under /template-previews/)",
        "operationId": "templatesList",
        "security": [],
        "responses": {
          "200": {
            "description": "Catalog",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TemplatesResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/profile": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "Onboarding profile",
        "operationId": "profileGet",
        "security": [
          {
            "cookieGuest": []
          },
          {
            "cookieSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Profile + brain flags",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkEnvelope"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Update profile fields",
        "operationId": "profilePost",
        "security": [
          {
            "cookieGuest": []
          },
          {
            "cookieSession": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string"
                  },
                  "onboarding": {
                    "type": "object"
                  },
                  "domain": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/projects/{projectId}/assets": {
      "get": {
        "tags": [
          "Projects"
        ],
        "summary": "List project assets",
        "operationId": "projectAssetsList",
        "security": [
          {
            "cookieGuest": []
          },
          {
            "cookieSession": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/projectId"
          }
        ],
        "responses": {
          "200": {
            "description": "Asset list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AssetListResponse"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "tags": [
          "Projects"
        ],
        "summary": "Upload one or more assets (multipart)",
        "operationId": "projectAssetsUpload",
        "security": [
          {
            "cookieGuest": []
          },
          {
            "cookieSession": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/projectId"
          }
        ],
        "description": "multipart/form-data. Every file part is stored at its filename (may include folders, e.g. logos/brand.png). Optional text field `prefix` puts all files under that folder. Same path overwrites. Limits: 10 MB per file, 20 files per request, 25 MB per request, 200 files and 50 MB per project. Allowed: png jpg jpeg gif webp avif svg ico woff woff2 ttf otf css js mjs json txt mp4 webm mp3 wav pdf. HTML is rejected (415). Type is taken from the file extension.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "prefix": {
                    "type": "string"
                  },
                  "file": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "binary"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Uploaded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AssetUploadResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "413": {
            "$ref": "#/components/responses/Error"
          },
          "415": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api/projects/{projectId}/assets/{assetPath}": {
      "get": {
        "tags": [
          "Projects"
        ],
        "summary": "Download an asset (owner)",
        "operationId": "projectAssetGet",
        "security": [
          {
            "cookieGuest": []
          },
          {
            "cookieSession": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/projectId"
          },
          {
            "name": "assetPath",
            "in": "path",
            "required": true,
            "description": "Relative path, up to 5 segments of [A-Za-z0-9._-], e.g. logos/brand.png",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "File bytes"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "put": {
        "tags": [
          "Projects"
        ],
        "summary": "Upload or replace one asset (raw body)",
        "operationId": "projectAssetPut",
        "security": [
          {
            "cookieGuest": []
          },
          {
            "cookieSession": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/projectId"
          },
          {
            "name": "assetPath",
            "in": "path",
            "required": true,
            "description": "Relative path, up to 5 segments of [A-Za-z0-9._-], e.g. logos/brand.png",
            "schema": {
              "type": "string"
            }
          }
        ],
        "description": "Allowed: png jpg jpeg gif webp avif svg ico woff woff2 ttf otf css js mjs json txt mp4 webm mp3 wav pdf. HTML is rejected (415). Type is taken from the file extension.",
        "requestBody": {
          "required": true,
          "content": {
            "application/octet-stream": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Uploaded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AssetUploadResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "413": {
            "$ref": "#/components/responses/Error"
          },
          "415": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "delete": {
        "tags": [
          "Projects"
        ],
        "summary": "Delete an asset",
        "operationId": "projectAssetDelete",
        "security": [
          {
            "cookieGuest": []
          },
          {
            "cookieSession": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/projectId"
          },
          {
            "name": "assetPath",
            "in": "path",
            "required": true,
            "description": "Relative path, up to 5 segments of [A-Za-z0-9._-], e.g. logos/brand.png",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkEnvelope"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/project-assets/{projectId}/{assetPath}": {
      "get": {
        "tags": [
          "Projects"
        ],
        "summary": "Public asset URL (use in published HTML)",
        "operationId": "projectAssetPublic",
        "security": [
          {},
          {
            "cookieGuest": []
          },
          {
            "cookieSession": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/projectId"
          },
          {
            "name": "assetPath",
            "in": "path",
            "required": true,
            "description": "Relative path, up to 5 segments of [A-Za-z0-9._-], e.g. logos/brand.png",
            "schema": {
              "type": "string"
            }
          }
        ],
        "description": "Public once the project is published (cache 5 min); before that, only the owner (cookie) can read it, and everyone else gets 404. Served with nosniff and a sandboxed CSP.",
        "responses": {
          "200": {
            "description": "File bytes"
          },
          "304": {
            "description": "Not modified"
          },
          "404": {
            "description": "Not found or not published"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "cookieGuest": {
        "type": "apiKey",
        "in": "cookie",
        "name": "bl_uid",
        "description": "Guest identity cookie (also accept header X-Brandlit-Uid)"
      },
      "cookieSession": {
        "type": "apiKey",
        "in": "cookie",
        "name": "bl_session",
        "description": "Signed-in / Connect session cookie. No Authorization Bearer yet."
      },
      "brandlitUidHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Brandlit-Uid",
        "description": "Optional guest uid when cookies unavailable (CORS allows this header)"
      }
    },
    "parameters": {
      "projectId": {
        "name": "projectId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "pattern": "^[a-z0-9_-]{1,48}$"
        }
      }
    },
    "responses": {
      "Error": {
        "description": "Error envelope",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorBody"
            }
          }
        }
      }
    },
    "schemas": {
      "OkEnvelope": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          }
        },
        "additionalProperties": true
      },
      "ErrorBody": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "example": false
          },
          "error": {
            "type": "string"
          },
          "code": {
            "type": "string",
            "description": "Machine-readable code (connect_grokbot, needs_key, free_exhausted, auth_required, unknown_template, oauth_unconfigured, \u2026)"
          },
          "detail": {
            "type": "string"
          }
        },
        "additionalProperties": true
      },
      "HealthResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "service": {
            "type": "string",
            "example": "brandlit-studio"
          },
          "protocol": {
            "type": "string",
            "example": "brandlit-canvas-room/1"
          },
          "designedFor": {
            "type": "string",
            "example": "Grok"
          },
          "vault": {
            "type": "boolean"
          },
          "platformBrain": {
            "type": "boolean"
          },
          "inference": {
            "type": "string"
          },
          "billing": {
            "type": "string",
            "description": "e.g. platform_api"
          },
          "stripe": {
            "type": "boolean"
          },
          "stripeWebhook": {
            "type": "boolean"
          },
          "payg": {
            "type": "object",
            "properties": {
              "freeSeconds": {
                "type": "number",
                "nullable": true
              },
              "freeGrokOps": {
                "type": "number"
              },
              "centsPerMinute": {
                "type": "number"
              }
            }
          },
          "money": {
            "type": "object",
            "description": "Pricing pointers. For the current catalog use GET /api/billing/products.",
            "additionalProperties": true
          },
          "hosting": {
            "type": "object",
            "additionalProperties": true
          },
          "site": {
            "type": "object",
            "properties": {
              "mode": {
                "type": "string",
                "example": "proxy"
              },
              "origin": {
                "type": "string"
              },
              "path": {
                "type": "string"
              }
            }
          },
          "oneButtonGrokBot": {
            "type": "boolean"
          },
          "browserApprove": {
            "type": "boolean"
          }
        },
        "additionalProperties": true
      },
      "ModeResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "grok": {
            "type": "string"
          },
          "hasKey": {
            "type": "boolean"
          },
          "grokBotLinked": {
            "type": "boolean"
          },
          "hasGrokBrain": {
            "type": "boolean"
          },
          "brainMode": {
            "type": "string",
            "example": "needs_grokbot"
          },
          "designedFor": {
            "type": "string"
          },
          "site": {
            "type": "string"
          },
          "siteOrigin": {
            "type": "string"
          },
          "product": {
            "type": "string"
          },
          "oneButtonGrokBot": {
            "type": "boolean"
          }
        }
      },
      "AuthSessionResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "uid": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "method": {
            "type": "string"
          },
          "usage": {
            "$ref": "#/components/schemas/UsagePublic"
          },
          "message": {
            "type": "string"
          }
        }
      },
      "AuthMeResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "authed": {
            "type": "boolean"
          },
          "guest": {
            "type": "boolean"
          },
          "email": {
            "type": "string",
            "nullable": true
          },
          "uid": {
            "type": "string"
          },
          "usage": {
            "$ref": "#/components/schemas/UsagePublic"
          },
          "hasKey": {
            "type": "boolean"
          },
          "grokBotLinked": {
            "type": "boolean"
          },
          "hasGrokBrain": {
            "type": "boolean"
          },
          "brainMode": {
            "type": "string"
          },
          "authMethod": {
            "type": "string"
          }
        },
        "additionalProperties": true
      },
      "UsagePublic": {
        "type": "object",
        "additionalProperties": true,
        "properties": {
          "secondsUsed": {
            "type": "number"
          },
          "grokOpsUsed": {
            "type": "number"
          },
          "freeGrokOps": {
            "type": "number"
          },
          "freeLeftOps": {
            "type": "number"
          },
          "gated": {
            "type": "boolean"
          },
          "tier": {
            "type": "string"
          },
          "centsPerMinute": {
            "type": "number"
          },
          "priceLabel": {
            "type": "string"
          }
        }
      },
      "GrokBotStartResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "flow": {
            "type": "string",
            "example": "device_code"
          },
          "device_code": {
            "type": "string"
          },
          "user_code": {
            "type": "string"
          },
          "verification_uri": {
            "type": "string"
          },
          "verification_uri_complete": {
            "type": "string"
          },
          "grokbot_deep_link": {
            "type": "string"
          },
          "interval": {
            "type": "integer",
            "example": 2
          },
          "expires_in": {
            "type": "integer",
            "example": 600
          },
          "message": {
            "type": "string"
          },
          "oauthReady": {
            "type": "boolean"
          }
        }
      },
      "GrokBotPollResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "approved",
              "denied",
              "expired"
            ]
          },
          "user_code": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "uid": {
            "type": "string"
          },
          "grokBotLinked": {
            "type": "boolean"
          },
          "hasGrokBrain": {
            "type": "boolean"
          },
          "brainMode": {
            "type": "string"
          },
          "plan": {
            "type": "string"
          }
        }
      },
      "GrokBotStatusResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "uid": {
            "type": "string"
          },
          "grokBotLinked": {
            "type": "boolean"
          },
          "hasGrokBrain": {
            "type": "boolean"
          },
          "platformBrainConfigured": {
            "type": "boolean"
          },
          "brainMode": {
            "type": "string"
          },
          "link": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true
          }
        }
      },
      "GrokSuccessResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "ops": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "speak": {
            "type": "string",
            "nullable": true
          },
          "model": {
            "type": "string"
          },
          "mode": {
            "type": "string"
          },
          "grokBotLinked": {
            "type": "boolean"
          },
          "hasGrokBrain": {
            "type": "boolean"
          },
          "billing": {
            "type": "string",
            "description": "Present on some live builds"
          }
        }
      },
      "GrokTestResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "tested": {
            "type": "boolean"
          },
          "model": {
            "type": "string"
          },
          "hint": {
            "type": "string"
          },
          "mode": {
            "type": "string"
          },
          "grokBotLinked": {
            "type": "boolean"
          },
          "hasGrokBrain": {
            "type": "boolean"
          }
        }
      },
      "Project": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "mode": {
            "type": "string"
          },
          "templateId": {
            "type": "string",
            "nullable": true
          },
          "owner": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "published": {
            "type": "boolean"
          },
          "previewUrl": {
            "type": "string"
          },
          "siteUrl": {
            "type": "string"
          },
          "siteHost": {
            "type": "string"
          },
          "brandKit": {
            "type": "object",
            "additionalProperties": true
          },
          "domain": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "ProjectListResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "projects": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Project"
            }
          },
          "total": {
            "type": "integer"
          },
          "nextOffset": {
            "type": "integer",
            "nullable": true
          }
        }
      },
      "ProjectCreateResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "project": {
            "$ref": "#/components/schemas/Project"
          }
        }
      },
      "ProjectGetResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "project": {
            "$ref": "#/components/schemas/Project"
          },
          "html": {
            "type": "string",
            "nullable": true
          },
          "ops": {
            "type": "array",
            "nullable": true,
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Last ops batch saved via save/PUT (null if never saved)."
          },
          "sidecar": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true,
            "description": "Free-form client metadata saved via save/PUT `sidecar` (\u226464 KB JSON). null if none."
          },
          "assets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ProjectAsset"
            }
          },
          "assetsTruncated": {
            "type": "boolean"
          },
          "assetsTotalBytes": {
            "type": "integer"
          },
          "schema": {
            "type": "string",
            "example": "brandlit-web/1+ext1"
          }
        }
      },
      "ProjectSaveBody": {
        "type": "object",
        "properties": {
          "html": {
            "type": "string"
          },
          "ops": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "name": {
            "type": "string"
          },
          "brandKit": {
            "type": "object"
          },
          "published": {
            "type": "boolean"
          },
          "mode": {
            "type": "string"
          },
          "sidecar": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true,
            "description": "Optional client metadata (city, phone, logoPath, \u2026). Object replaces the stored sidecar; null deletes it; omit to leave unchanged. Max 64 KB JSON."
          }
        }
      },
      "ProjectPublishResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "project": {
            "$ref": "#/components/schemas/Project"
          },
          "publicUrl": {
            "type": "string"
          },
          "pathUrl": {
            "type": "string"
          },
          "siteUrl": {
            "type": "string"
          },
          "customUrl": {
            "type": "string",
            "nullable": true
          },
          "byoCnameTarget": {
            "type": "string"
          }
        }
      },
      "DomainInstructionsResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "buy": {
            "type": "string"
          },
          "registrar": {
            "type": "boolean"
          },
          "previewUrl": {
            "type": "string"
          },
          "siteUrl": {
            "type": "string"
          },
          "byo": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "DomainSearchResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "query": {
            "type": "string"
          },
          "domains": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        }
      },
      "BillingProductsResponse": {
        "type": "object",
        "description": "Live product catalog",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "currency": {
            "type": "string"
          },
          "products": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "unit_amount": {
                  "type": "integer",
                  "description": "Cents"
                },
                "mode": {
                  "type": "string"
                },
                "interval": {
                  "type": "string"
                },
                "description": {
                  "type": "string"
                }
              }
            }
          },
          "freeGrokSeconds": {
            "type": "number"
          },
          "editorUnlimited": {
            "type": "boolean"
          },
          "freeSeconds": {
            "type": "number",
            "nullable": true
          },
          "perApp": {
            "type": "boolean"
          }
        }
      },
      "TemplatesResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "templates": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "category": {
                  "type": "string"
                },
                "line": {
                  "type": "string"
                },
                "palette": {
                  "type": "string"
                },
                "pages": {
                  "type": "integer"
                },
                "preview": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "ProjectAsset": {
        "type": "object",
        "properties": {
          "path": {
            "type": "string",
            "example": "logos/brand.png"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Stable URL https://brandlit.blacklabelbots.com/project-assets/{projectId}/{path}. Public once the project is published; owner-only (cookie) before."
          },
          "size": {
            "type": "integer"
          },
          "contentType": {
            "type": "string"
          },
          "uploadedAt": {
            "type": "string",
            "format": "date-time"
          },
          "etag": {
            "type": "string"
          }
        }
      },
      "AssetListResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "projectId": {
            "type": "string"
          },
          "assets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ProjectAsset"
            }
          },
          "truncated": {
            "type": "boolean"
          },
          "totalBytes": {
            "type": "integer"
          },
          "count": {
            "type": "integer"
          },
          "limits": {
            "type": "object",
            "properties": {
              "maxFileBytes": {
                "type": "integer",
                "example": 10485760
              },
              "maxFilesPerRequest": {
                "type": "integer",
                "example": 20
              },
              "maxObjects": {
                "type": "integer",
                "example": 200
              },
              "maxProjectBytes": {
                "type": "integer",
                "example": 52428800
              }
            }
          }
        }
      },
      "AssetUploadResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "projectId": {
            "type": "string"
          },
          "uploaded": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ProjectAsset"
            }
          }
        }
      }
    }
  }
}
