{
  "openapi": "3.1.0",
  "info": {
    "title": "BorealHost API",
    "version": "1.0",
    "description": "Agent-native web hosting API by BorealHost.ai (Quebec, Canada).\nFull self-service: register \u2192 explore plans \u2192 checkout \u2192 provision \u2192 manage.\n\nAll prices are in CAD. All responses use a consistent envelope format:\n`{\"ok\": true, \"data\": {...}, \"meta\": {\"request_id\": \"uuid\", \"timestamp\": \"iso8601\"}}`\n\nFor errors: `{\"ok\": false, \"error\": {\"code\": \"...\", \"message\": \"...\", \"param\": \"...\"}, \"meta\": {...}}`\n\n**MCP server**: If you're an AI agent, consider using the BorealHost MCP server\ninstead of this REST API \u2014 it wraps all endpoints with rich tool descriptions.\n",
    "contact": {
      "name": "BorealHost.ai",
      "url": "https://borealhost.ai"
    },
    "license": {
      "name": "Proprietary"
    }
  },
  "servers": [
    {
      "url": "https://borealhost.ai/api/v1",
      "description": "Production"
    }
  ],
  "security": [],
  "components": {
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key in format `bh_<48 hex chars>`.\nObtain via POST /auth/register/ or through checkout completion.\nPass as: `Authorization: Bearer bh_...`\n"
      }
    },
    "schemas": {
      "Meta": {
        "type": "object",
        "properties": {
          "request_id": {
            "type": "string",
            "format": "uuid"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "const": false
          },
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "NOT_FOUND",
                  "FORBIDDEN",
                  "UNAUTHORIZED",
                  "VALIDATION_ERROR",
                  "RATE_LIMITED",
                  "INTERNAL_ERROR"
                ]
              },
              "message": {
                "type": "string"
              },
              "param": {
                "type": "string",
                "nullable": true
              }
            }
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        }
      },
      "Plan": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string",
            "example": "site_starter"
          },
          "name": {
            "type": "string",
            "example": "Starter"
          },
          "track": {
            "type": "string",
            "enum": [
              "single_site",
              "agency"
            ]
          },
          "hosting_type": {
            "type": "string",
            "enum": [
              "shared",
              "vps",
              "dedicated"
            ]
          },
          "price": {
            "type": "object",
            "properties": {
              "monthly": {
                "type": "number"
              },
              "annual": {
                "type": "number"
              },
              "currency": {
                "type": "string",
                "const": "CAD"
              }
            }
          },
          "features": {
            "type": "object",
            "properties": {
              "max_sites": {
                "type": "integer"
              },
              "ai_modules": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "free_domain_annual": {
                "type": "boolean"
              }
            }
          }
        }
      },
      "CheckoutSession": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "sku": {
            "type": "string",
            "example": "bh_site_starter_monthly"
          },
          "plan_slug": {
            "type": "string"
          },
          "billing_period": {
            "type": "string",
            "enum": [
              "monthly",
              "annual"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "not_ready",
              "ready",
              "awaiting_payment",
              "in_progress",
              "completed",
              "canceled",
              "failed"
            ]
          },
          "buyer_email": {
            "type": "string"
          },
          "requested_slug": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "checkout_secret": {
            "type": "string",
            "description": "Used to authenticate subsequent checkout operations"
          },
          "stripe_checkout_url": {
            "type": "string",
            "description": "Present only when payment_method is stripe_checkout"
          },
          "api_key": {
            "type": "string",
            "description": "Present once on completion, then cleared permanently"
          },
          "subscription_id": {
            "type": "string",
            "format": "uuid"
          }
        }
      },
      "Site": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "plan": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "domains": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "modules": {
            "type": "object"
          },
          "resources": {
            "type": "object",
            "properties": {
              "memory_mb": {
                "type": "integer"
              },
              "cpu_cores": {
                "type": "integer"
              },
              "disk_gb": {
                "type": "integer"
              }
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ApiKeyCreated": {
        "type": "object",
        "properties": {
          "api_key": {
            "type": "string",
            "example": "bh_a1b2c3...",
            "description": "Shown once, store immediately"
          },
          "key_id": {
            "type": "string",
            "format": "uuid"
          },
          "prefix": {
            "type": "string",
            "example": "bh_a1b2c3"
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "read",
                "write",
                "admin"
              ]
            }
          },
          "account_id": {
            "type": "string",
            "format": "uuid"
          }
        }
      }
    },
    "parameters": {
      "TenantSlug": {
        "name": "tenant_slug",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "Site identifier (slug chosen during checkout)"
      }
    }
  },
  "paths": {
    "/plans/": {
      "get": {
        "operationId": "listPlans",
        "summary": "List available hosting plans",
        "tags": [
          "Plans"
        ],
        "parameters": [
          {
            "name": "track",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "single_site",
                "agency"
              ]
            }
          },
          {
            "name": "include_deprecated",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Plan list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Plan"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/plans/{plan_slug}/": {
      "get": {
        "operationId": "getPlan",
        "summary": "Get a single plan's details",
        "tags": [
          "Plans"
        ],
        "parameters": [
          {
            "name": "plan_slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Plan details"
          },
          "404": {
            "description": "Plan not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/status/": {
      "get": {
        "operationId": "platformStatus",
        "summary": "Platform operational status",
        "tags": [
          "Discovery"
        ],
        "responses": {
          "200": {
            "description": "Platform status",
            "content": {
              "application/json": {
                "example": {
                  "ok": true,
                  "data": {
                    "status": "operational",
                    "region": "ca-qc",
                    "provider": "BorealHost.ai",
                    "api_version": "v1"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/auth/register/": {
      "post": {
        "operationId": "register",
        "summary": "Register an agent account and get an API key",
        "description": "No authentication needed. Creates a synthetic agent identity.\nThe returned API key is shown ONCE \u2014 store it immediately.\nRate limit: 5 per IP per hour.\n",
        "tags": [
          "Auth"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "default": "Agent Key"
                  }
                }
              },
              "example": {
                "name": "My Agent"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Account created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/ApiKeyCreated"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/auth/whoami/": {
      "get": {
        "operationId": "whoami",
        "summary": "Check API key account info",
        "tags": [
          "Auth"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Account info",
            "content": {
              "application/json": {
                "example": {
                  "ok": true,
                  "data": {
                    "user": {
                      "id": "uuid",
                      "email": "agent-xxx@api.borealhost.ai"
                    },
                    "api_key": {
                      "id": "uuid",
                      "scopes": [
                        "read",
                        "write"
                      ]
                    },
                    "account": {
                      "sites": 1,
                      "active_subscriptions": 1
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/acp/checkouts/": {
      "post": {
        "operationId": "createCheckout",
        "summary": "Create a checkout session",
        "description": "Start a purchase flow. SKU format: `bh_{plan_slug}_{monthly|annual}`.\nRate limit: 10 per IP per hour.\n",
        "tags": [
          "Checkout"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "sku"
                ],
                "properties": {
                  "sku": {
                    "type": "string",
                    "example": "bh_site_starter_monthly"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Checkout session created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/CheckoutSession"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Invalid SKU",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/acp/checkouts/{checkout_id}/": {
      "get": {
        "operationId": "getCheckout",
        "summary": "Poll checkout status",
        "description": "Poll for payment and provisioning updates.\nWhen status is \"completed\", the api_key field appears ONCE, then is cleared.\nRate limit: 60 per IP per minute.\n",
        "tags": [
          "Checkout"
        ],
        "parameters": [
          {
            "name": "checkout_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "checkout_secret",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Or pass via X-Checkout-Secret header"
          }
        ],
        "responses": {
          "200": {
            "description": "Checkout status",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/CheckoutSession"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/acp/checkouts/{checkout_id}/update/": {
      "post": {
        "operationId": "updateCheckout",
        "summary": "Set buyer email and site slug",
        "description": "Must be in \"not_ready\" status. Setting requested_slug transitions to \"ready\".\nSlug format: 3-50 chars, lowercase alphanumeric + hyphens.\n",
        "tags": [
          "Checkout"
        ],
        "parameters": [
          {
            "name": "checkout_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "buyer_email": {
                    "type": "string",
                    "format": "email"
                  },
                  "requested_slug": {
                    "type": "string",
                    "pattern": "^[a-z0-9][a-z0-9-]{1,48}[a-z0-9]$"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Checkout updated"
          },
          "422": {
            "description": "Invalid slug or slug taken"
          }
        }
      }
    },
    "/acp/checkouts/{checkout_id}/complete/": {
      "post": {
        "operationId": "completeCheckout",
        "summary": "Complete payment and start provisioning",
        "description": "Must be in \"ready\" status.\n- stripe_checkout: returns Stripe payment URL, poll for completion\n- stripe_payment_method: charges directly, returns API key immediately\n",
        "tags": [
          "Checkout"
        ],
        "parameters": [
          {
            "name": "checkout_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "payment_method": {
                    "type": "string",
                    "enum": [
                      "stripe_checkout",
                      "stripe_payment_method"
                    ],
                    "default": "stripe_checkout"
                  },
                  "payment_method_id": {
                    "type": "string",
                    "description": "Required for stripe_payment_method"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Stripe checkout URL returned (awaiting_payment)"
          },
          "201": {
            "description": "Payment processed, site provisioning started (completed)"
          }
        }
      }
    },
    "/sites/": {
      "get": {
        "operationId": "listSites",
        "summary": "List all sites",
        "tags": [
          "Sites"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Site list"
          }
        }
      }
    },
    "/sites/{tenant_slug}/": {
      "get": {
        "operationId": "getSite",
        "summary": "Get site details",
        "tags": [
          "Sites"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantSlug"
          }
        ],
        "responses": {
          "200": {
            "description": "Site details",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Site"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Site not found"
          }
        }
      }
    },
    "/sites/{tenant_slug}/dns/": {
      "post": {
        "operationId": "manageDns",
        "summary": "Create or delete DNS records",
        "tags": [
          "Sites"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantSlug"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "action",
                  "type"
                ],
                "properties": {
                  "action": {
                    "type": "string",
                    "enum": [
                      "create",
                      "delete"
                    ]
                  },
                  "type": {
                    "type": "string",
                    "enum": [
                      "A",
                      "AAAA",
                      "CNAME",
                      "MX",
                      "TXT",
                      "SRV"
                    ]
                  },
                  "subdomain": {
                    "type": "string",
                    "default": ""
                  },
                  "value": {
                    "type": "string"
                  },
                  "ttl": {
                    "type": "integer",
                    "default": 3600
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "DNS record managed"
          }
        }
      }
    },
    "/sites/{tenant_slug}/deploy/": {
      "post": {
        "operationId": "deploy",
        "summary": "Trigger deployment",
        "tags": [
          "Sites"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantSlug"
          }
        ],
        "responses": {
          "200": {
            "description": "Deployment triggered"
          }
        }
      }
    },
    "/sites/{tenant_slug}/snapshot/": {
      "post": {
        "operationId": "createSnapshot",
        "summary": "Create backup snapshot",
        "description": "Dedicated/VPS plans only.",
        "tags": [
          "Sites"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantSlug"
          }
        ],
        "responses": {
          "200": {
            "description": "Snapshot created"
          },
          "403": {
            "description": "Plan does not support snapshots"
          }
        }
      }
    },
    "/sites/{tenant_slug}/metrics/": {
      "get": {
        "operationId": "getMetrics",
        "summary": "Get traffic and performance metrics",
        "tags": [
          "Sites"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantSlug"
          },
          {
            "name": "days",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 7,
              "minimum": 1,
              "maximum": 90
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Metrics data"
          }
        }
      }
    },
    "/sites/{tenant_slug}/scale/": {
      "post": {
        "operationId": "scale",
        "summary": "Change hosting plan",
        "tags": [
          "Sites"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantSlug"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "new_plan"
                ],
                "properties": {
                  "new_plan": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Plan changed"
          }
        }
      }
    },
    "/sites/{tenant_slug}/delete/": {
      "delete": {
        "operationId": "decommission",
        "summary": "Delete site (7-day grace period)",
        "tags": [
          "Sites"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantSlug"
          }
        ],
        "responses": {
          "200": {
            "description": "Site scheduled for deletion"
          }
        }
      }
    },
    "/sites/{tenant_slug}/files/": {
      "get": {
        "operationId": "listFiles",
        "summary": "List files and directories",
        "tags": [
          "Files"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantSlug"
          },
          {
            "name": "path",
            "in": "query",
            "schema": {
              "type": "string",
              "default": ""
            }
          }
        ],
        "responses": {
          "200": {
            "description": "File listing"
          }
        }
      }
    },
    "/sites/{tenant_slug}/files/read/": {
      "get": {
        "operationId": "readFile",
        "summary": "Read file contents (max 512KB, text only)",
        "tags": [
          "Files"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantSlug"
          },
          {
            "name": "path",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "File content"
          }
        }
      }
    },
    "/sites/{tenant_slug}/files/write/": {
      "post": {
        "operationId": "writeFile",
        "summary": "Write or overwrite a text file",
        "tags": [
          "Files"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantSlug"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "path",
                  "content"
                ],
                "properties": {
                  "path": {
                    "type": "string"
                  },
                  "content": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "File written"
          }
        }
      }
    },
    "/sites/{tenant_slug}/files/upload/": {
      "post": {
        "operationId": "uploadFile",
        "summary": "Upload base64-encoded file (for binaries)",
        "tags": [
          "Files"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantSlug"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "path",
                  "content_b64"
                ],
                "properties": {
                  "path": {
                    "type": "string"
                  },
                  "content_b64": {
                    "type": "string",
                    "format": "byte"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "File uploaded"
          }
        }
      }
    },
    "/sites/{tenant_slug}/files/delete/": {
      "post": {
        "operationId": "deleteFile",
        "summary": "Delete file or directory",
        "tags": [
          "Files"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantSlug"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "path"
                ],
                "properties": {
                  "path": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "File deleted"
          }
        }
      }
    },
    "/sites/{tenant_slug}/logs/": {
      "get": {
        "operationId": "getLogs",
        "summary": "Retrieve container logs",
        "tags": [
          "Logs"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantSlug"
          },
          {
            "name": "type",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "error",
                "access",
                "php"
              ],
              "default": "error"
            }
          },
          {
            "name": "lines",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 100,
              "minimum": 1,
              "maximum": 500
            }
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Log lines"
          }
        }
      }
    },
    "/sites/{tenant_slug}/ssh/": {
      "get": {
        "operationId": "getSshInfo",
        "summary": "Get SSH connection info (VPS/dedicated only)",
        "tags": [
          "SSH"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantSlug"
          }
        ],
        "responses": {
          "200": {
            "description": "SSH connection info"
          },
          "403": {
            "description": "Plan does not support SSH"
          }
        }
      }
    },
    "/sites/{tenant_slug}/ssh/keys/": {
      "post": {
        "operationId": "addSshKey",
        "summary": "Inject SSH public key",
        "tags": [
          "SSH"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantSlug"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "public_key"
                ],
                "properties": {
                  "public_key": {
                    "type": "string",
                    "description": "ssh-ed25519, ssh-rsa, or ecdsa-sha2-*"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "SSH key added"
          }
        }
      }
    },
    "/sites/{tenant_slug}/modules/": {
      "get": {
        "operationId": "listModules",
        "summary": "List AI modules and their state",
        "tags": [
          "Modules"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantSlug"
          }
        ],
        "responses": {
          "200": {
            "description": "Module list"
          }
        }
      }
    },
    "/sites/{tenant_slug}/modules/{module_name}/toggle/": {
      "post": {
        "operationId": "toggleModule",
        "summary": "Enable or disable an AI module",
        "tags": [
          "Modules"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TenantSlug"
          },
          {
            "name": "module_name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "chatbot",
                "seo",
                "translation",
                "content"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Module toggled"
          }
        }
      }
    },
    "/domains/": {
      "get": {
        "operationId": "listDomains",
        "summary": "List owned domains",
        "tags": [
          "Domains"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Domain list"
          }
        }
      }
    },
    "/domains/search/": {
      "get": {
        "operationId": "searchDomain",
        "summary": "Check domain availability and pricing",
        "tags": [
          "Domains"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "domain",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "example.ca"
          }
        ],
        "responses": {
          "200": {
            "description": "Availability and pricing"
          }
        }
      }
    },
    "/domains/register/": {
      "post": {
        "operationId": "registerDomain",
        "summary": "Register a new domain",
        "description": "Requires complete WHOIS contact info. For .ca domains, ca_legal_type is required.\nPhone format: +1.5145551234 (E.164).\n",
        "tags": [
          "Domains"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "domain",
                  "period",
                  "contact"
                ],
                "properties": {
                  "domain": {
                    "type": "string",
                    "example": "example.ca"
                  },
                  "period": {
                    "type": "integer",
                    "default": 1,
                    "minimum": 1,
                    "maximum": 10
                  },
                  "ca_legal_type": {
                    "type": "string",
                    "enum": [
                      "CCO",
                      "RES",
                      "CCT",
                      "GOV",
                      "EDU",
                      "ASS",
                      "HOP",
                      "PRT",
                      "TDM",
                      "TRD",
                      "PLT",
                      "LAM",
                      "MAJ",
                      "INB",
                      "ABO",
                      "LGR"
                    ]
                  },
                  "contact": {
                    "type": "object",
                    "required": [
                      "first_name",
                      "last_name",
                      "email",
                      "phone",
                      "address1",
                      "city",
                      "state",
                      "postal_code",
                      "country"
                    ],
                    "properties": {
                      "first_name": {
                        "type": "string"
                      },
                      "last_name": {
                        "type": "string"
                      },
                      "email": {
                        "type": "string",
                        "format": "email"
                      },
                      "phone": {
                        "type": "string",
                        "example": "+1.5145551234"
                      },
                      "address1": {
                        "type": "string"
                      },
                      "city": {
                        "type": "string"
                      },
                      "state": {
                        "type": "string",
                        "example": "QC"
                      },
                      "postal_code": {
                        "type": "string",
                        "example": "H2X 1Y4"
                      },
                      "country": {
                        "type": "string",
                        "default": "CA"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Domain registered"
          },
          "422": {
            "description": "Validation error (missing fields, bad phone format, etc.)"
          }
        }
      }
    },
    "/domains/{domain_name}/": {
      "get": {
        "operationId": "getDomain",
        "summary": "Get domain details",
        "tags": [
          "Domains"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "domain_name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Domain details"
          }
        }
      }
    },
    "/domains/{domain_name}/dns/": {
      "get": {
        "operationId": "listDomainDns",
        "summary": "List domain DNS records",
        "tags": [
          "Domains"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "domain_name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "DNS record list"
          }
        }
      }
    },
    "/domains/{domain_name}/dns/add/": {
      "post": {
        "operationId": "addDomainDns",
        "summary": "Add DNS record to domain",
        "tags": [
          "Domains"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "domain_name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "DNS record added"
          }
        }
      }
    },
    "/domains/{domain_name}/dns/delete/": {
      "post": {
        "operationId": "deleteDomainDns",
        "summary": "Delete DNS record from domain",
        "tags": [
          "Domains"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "domain_name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "DNS record deleted"
          }
        }
      }
    },
    "/domains/{domain_name}/link/": {
      "post": {
        "operationId": "linkDomain",
        "summary": "Link domain to a site",
        "tags": [
          "Domains"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "domain_name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Domain linked"
          }
        }
      }
    },
    "/domains/{domain_name}/settings/": {
      "post": {
        "operationId": "domainSettings",
        "summary": "Update domain settings (auto-renew, etc.)",
        "tags": [
          "Domains"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "domain_name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Settings updated"
          }
        }
      }
    },
    "/account/update/": {
      "post": {
        "operationId": "updateAccount",
        "summary": "Update account profile",
        "tags": [
          "Account"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "language": {
                    "type": "string",
                    "enum": [
                      "en",
                      "fr"
                    ]
                  },
                  "first_name": {
                    "type": "string"
                  },
                  "last_name": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Account updated"
          }
        }
      }
    },
    "/account/delete/": {
      "delete": {
        "operationId": "deleteAccount",
        "summary": "Permanently anonymize account (irreversible)",
        "tags": [
          "Account"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "confirm"
                ],
                "properties": {
                  "confirm": {
                    "type": "string",
                    "const": "DELETE"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Account anonymized"
          }
        }
      }
    },
    "/account/subscriptions/": {
      "get": {
        "operationId": "listSubscriptions",
        "summary": "List subscriptions with plan details",
        "tags": [
          "Account"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Subscription list"
          }
        }
      }
    },
    "/account/billing-portal/": {
      "get": {
        "operationId": "billingPortal",
        "summary": "Get Stripe billing portal URL",
        "tags": [
          "Account"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "flow",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "",
                "payment_method_update"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Portal URL"
          }
        }
      }
    },
    "/keys/": {
      "get": {
        "operationId": "listKeys",
        "summary": "List API keys",
        "tags": [
          "Keys"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Key list (prefixes only, not full keys)"
          }
        }
      }
    },
    "/keys/create/": {
      "post": {
        "operationId": "createKey",
        "summary": "Create a new API key",
        "tags": [
          "Keys"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "scopes": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "read",
                        "write",
                        "admin"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Key created (shown once)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/ApiKeyCreated"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/keys/{key_id}/revoke/": {
      "post": {
        "operationId": "revokeKey",
        "summary": "Revoke an API key",
        "tags": [
          "Keys"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "key_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Key revoked"
          }
        }
      }
    },
    "/keys/{key_id}/rotate/": {
      "post": {
        "operationId": "rotateKey",
        "summary": "Atomically rotate an API key",
        "description": "Old key is immediately invalidated. New key returned once.",
        "tags": [
          "Keys"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "key_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Key rotated",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/ApiKeyCreated"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/keys/claim/request/": {
      "post": {
        "operationId": "requestKeyClaim",
        "summary": "Start challenge-response key provisioning",
        "description": "No auth required. Writes a claim token to the container via bh-agent.\nAgent reads the token from ~/.borealhost/.claim_token, then calls /keys/claim/.\nRate limited: 5 per IP per hour.\n",
        "tags": [
          "Keys"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "site_slug"
                ],
                "properties": {
                  "site_slug": {
                    "type": "string",
                    "example": "my-site"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Claim token written to container"
          },
          "422": {
            "description": "Unknown site, existing key, or rate limited"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/keys/claim/": {
      "post": {
        "operationId": "claimApiKey",
        "summary": "Claim API key using token from container",
        "description": "No auth required. The claim token proves container filesystem access.\nReturns a site-scoped API key (read+write). Token is single-use, expires in 1 hour.\n",
        "tags": [
          "Keys"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "claim_token"
                ],
                "properties": {
                  "claim_token": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "API key created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "api_key": {
                          "type": "string",
                          "description": "Shown once, store immediately"
                        },
                        "site_slug": {
                          "type": "string"
                        },
                        "site_scoped": {
                          "type": "boolean",
                          "const": true
                        },
                        "scopes": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Invalid, expired, or already-claimed token"
          }
        }
      }
    }
  },
  "tags": [
    {
      "name": "Discovery",
      "description": "Platform status and discovery"
    },
    {
      "name": "Plans",
      "description": "Hosting plan catalog"
    },
    {
      "name": "Auth",
      "description": "Agent registration and identity"
    },
    {
      "name": "Checkout",
      "description": "Agent Checkout Protocol (ACP) \u2014 purchase hosting"
    },
    {
      "name": "Sites",
      "description": "Site management (DNS, deploy, scale, metrics)"
    },
    {
      "name": "Files",
      "description": "File operations on site containers"
    },
    {
      "name": "Logs",
      "description": "Container log retrieval"
    },
    {
      "name": "SSH",
      "description": "SSH access (VPS/dedicated only)"
    },
    {
      "name": "Modules",
      "description": "AI module management"
    },
    {
      "name": "Domains",
      "description": "Domain registration and DNS"
    },
    {
      "name": "Account",
      "description": "Account profile and billing"
    },
    {
      "name": "Keys",
      "description": "API key management"
    }
  ]
}