{
  "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. Chat agents can instead use the hosted MCP server connector at https://boomurl.com/api/mcp (discovery: https://boomurl.com/.well-known/mcp.json)."
  },
  "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}": {
      "put": {
        "operationId": "publishSite",
        "summary": "Create or update (idempotent) a site you own",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [],
                "properties": {
                  "files": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "string"
                    },
                    "description": "Map of relative path -> file contents (UTF-8, or base64 when base64=true). Equivalent alternative: files_list (use that from ChatGPT Actions). No index.html required \u2014 a lone .md/.txt/.pdf becomes a page."
                  },
                  "base64": {
                    "type": "boolean",
                    "description": "Treat file values as base64 (for binary)."
                  },
                  "key": {
                    "type": "string",
                    "description": "Your API key (boom_sk_...), as an alternative to the Authorization header \u2014 for clients that cannot set headers, e.g. ChatGPT Custom-GPT Actions with auth set to None. Mint a per-user key via /api/v1/keys/request + /api/v1/keys."
                  },
                  "files_list": {
                    "type": "array",
                    "description": "The site's files as an array \u2014 USE THIS from ChatGPT Actions (the 'files' map field is not representable in Action schemas). Each item is one file.",
                    "items": {
                      "type": "object",
                      "required": [
                        "path",
                        "content"
                      ],
                      "properties": {
                        "path": {
                          "type": "string",
                          "description": "Relative file path, e.g. index.html or css/style.css"
                        },
                        "content": {
                          "type": "string",
                          "description": "The file's full contents (UTF-8 text, or base64 when base64=true)"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated"
          },
          "201": {
            "description": "Created"
          },
          "401": {
            "description": "Unauthorized"
          },
          "409": {
            "description": "Name owned by another account"
          },
          "413": {
            "description": "Too large"
          }
        },
        "description": " Auth: Bearer header, or a 'key' field in the body (for header-less clients like GPT Actions).",
        "security": [],
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      },
      "get": {
        "operationId": "getSite",
        "summary": "Get site status (exists / owned / url)",
        "responses": {
          "200": {
            "description": "Status"
          },
          "401": {
            "description": "Unauthorized"
          }
        },
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      },
      "delete": {
        "operationId": "deleteSite",
        "summary": "Delete a site you own",
        "responses": {
          "200": {
            "description": "Deleted"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not found"
          }
        },
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/api/v1/sites/{name}/domains": {
      "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"
          }
        },
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      },
      "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"
          }
        },
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/api/v1/sites/{name}/domains/{domain}": {
      "get": {
        "operationId": "getDomainStatus",
        "summary": "Status of one custom domain (nameservers, nsDelegated, tlsReady, live)",
        "responses": {
          "200": {
            "description": "Status"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not found"
          }
        },
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "domain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      },
      "delete": {
        "operationId": "detachDomain",
        "summary": "Disconnect a custom domain from your site",
        "responses": {
          "200": {
            "description": "Detached"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not found"
          }
        },
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "domain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key: boom_sk_..."
      }
    },
    "schemas": {}
  }
}