{
  "openapi": "3.1.0",
  "info": {
    "title": "boomurl Publishing API",
    "version": "1.0.0",
    "description": "Publish static websites and get an instant public URL. Auth is a bearer API key (boom_sk_...). Mint one via /api/v1/keys after email verification, then publish with a single idempotent PUT."
  },
  "servers": [{ "url": "https://boomurl.com" }],
  "security": [{ "bearerAuth": [] }],
  "paths": {
    "/api/v1/keys/request": {
      "post": {
        "operationId": "requestKeyCode",
        "summary": "Email a 6-digit code to begin minting an API key",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["email"],
                "properties": { "email": { "type": "string", "format": "email" } }
              }
            }
          }
        },
        "responses": { "200": { "description": "Code sent" } }
      }
    },
    "/api/v1/keys": {
      "post": {
        "operationId": "mintKey",
        "summary": "Confirm the code and mint an API key (secret shown once)",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["email", "code"],
                "properties": {
                  "email": { "type": "string", "format": "email" },
                  "code": { "type": "string", "pattern": "^[0-9]{6}$" },
                  "label": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Key minted",
            "content": {
              "application/json": {
                "schema": { "type": "object", "properties": { "key": { "type": "string" } } }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "listKeys",
        "summary": "List your API keys (metadata only)",
        "responses": { "200": { "description": "Keys" }, "401": { "description": "Unauthorized" } }
      }
    },
    "/api/v1/keys/{id}": {
      "delete": {
        "operationId": "revokeKey",
        "summary": "Revoke an API key",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": { "200": { "description": "Revoked" }, "401": { "description": "Unauthorized" }, "404": { "description": "Not found" } }
      }
    },
    "/api/v1/sites": {
      "get": {
        "operationId": "listSites",
        "summary": "List the sites owned by your key",
        "responses": { "200": { "description": "Sites" }, "401": { "description": "Unauthorized" } }
      }
    },
    "/api/v1/sites/{name}": {
      "parameters": [{ "name": "name", "in": "path", "required": true, "schema": { "type": "string" } }],
      "put": {
        "operationId": "publishSite",
        "summary": "Create or update (idempotent) a site you own",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["files"],
                "properties": {
                  "files": {
                    "type": "object",
                    "additionalProperties": { "type": "string" },
                    "description": "Map of relative path -> file contents (UTF-8, or base64 when base64=true). Must include index.html at the top level."
                  },
                  "base64": { "type": "boolean", "description": "Treat file values as base64 (for binary)." }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Updated" },
          "201": { "description": "Created" },
          "401": { "description": "Unauthorized" },
          "409": { "description": "Name owned by another account" },
          "413": { "description": "Too large" }
        }
      },
      "get": {
        "operationId": "getSite",
        "summary": "Get site status (exists / owned / url)",
        "responses": { "200": { "description": "Status" }, "401": { "description": "Unauthorized" } }
      },
      "delete": {
        "operationId": "deleteSite",
        "summary": "Delete a site you own",
        "responses": { "200": { "description": "Deleted" }, "401": { "description": "Unauthorized" }, "404": { "description": "Not found" } }
      }
    },
    "/api/v1/sites/{name}/domains": {
      "parameters": [{ "name": "name", "in": "path", "required": true, "schema": { "type": "string" } }],
      "post": {
        "operationId": "attachDomain",
        "summary": "Attach a custom domain (apex or subdomain) to a site you own. Returns the nameservers to set at the registrar; HTTPS is automatic.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["domain"],
                "properties": { "domain": { "type": "string", "description": "example.com or blog.example.com" } }
              }
            }
          }
        },
        "responses": {
          "201": { "description": "Attached (pending nameserver change)" },
          "401": { "description": "Unauthorized" },
          "404": { "description": "Site not found / not yours" },
          "409": { "description": "Domain already connected to another site" }
        }
      },
      "get": {
        "operationId": "listSiteDomains",
        "summary": "List the site's custom domains with live status (nsDelegated, tlsReady, live)",
        "responses": { "200": { "description": "Domains" }, "401": { "description": "Unauthorized" }, "404": { "description": "Not found" } }
      }
    },
    "/api/v1/sites/{name}/domains/{domain}": {
      "parameters": [
        { "name": "name", "in": "path", "required": true, "schema": { "type": "string" } },
        { "name": "domain", "in": "path", "required": true, "schema": { "type": "string" } }
      ],
      "get": {
        "operationId": "getDomainStatus",
        "summary": "Status of one custom domain (nameservers, nsDelegated, tlsReady, live)",
        "responses": { "200": { "description": "Status" }, "401": { "description": "Unauthorized" }, "404": { "description": "Not found" } }
      },
      "delete": {
        "operationId": "detachDomain",
        "summary": "Disconnect a custom domain from your site",
        "responses": { "200": { "description": "Detached" }, "401": { "description": "Unauthorized" }, "404": { "description": "Not found" } }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": { "type": "http", "scheme": "bearer", "description": "API key: boom_sk_..." }
    }
  }
}
