{
  "openapi": "3.1.0",
  "info": {
    "title": "turbopress Hosting API",
    "version": "1.0.0",
    "description": "Contract only: the public endpoint is disabled until authentication, authorization, target binding and operations are implemented. API tokens use tpapi_ and are distinct from MCP tokens. No arbitrary shell, WordPress database, uploads or wp-config.php deployment."
  },
  "servers": [
    {
      "url": "https://panel.turbopress.de/api/v1"
    }
  ],
  "security": [
    {
      "apiToken": []
    }
  ],
  "paths": {
    "/sites": {
      "get": {
        "operationId": "listSites",
        "summary": "List authorized sites",
        "x-permission": "sites:read",
        "security": [
          {
            "apiToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Visible sites and next cursor",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SiteListResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid syntax, JSON, cursor or idempotency key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Permission denied for a known owned target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "404": {
            "description": "Target or operation not found or not accessible",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "409": {
            "description": "Idempotency conflict or concurrent operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "422": {
            "description": "Operation rejected for this target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (error code rate_limited: per account, or per client IP before authentication, i.e. after 20 failed authentications or after 600 requests per minute from one IP). Retry-After gives the seconds to wait.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "502": {
            "description": "Hosting backend failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "503": {
            "description": "API or hosting backend unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "405": {
            "description": "Method not allowed for this route",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Opaque cursor from the preceding response"
          }
        ]
      }
    },
    "/sites/{site_id}": {
      "get": {
        "operationId": "getSite",
        "summary": "Get a site",
        "x-permission": "sites:read",
        "security": [
          {
            "apiToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Site status, capabilities and details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SiteResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid syntax, JSON, cursor or idempotency key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Permission denied for a known owned target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "404": {
            "description": "Target or operation not found or not accessible",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "409": {
            "description": "Idempotency conflict or concurrent operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "422": {
            "description": "Operation rejected for this target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (error code rate_limited: per account, or per client IP before authentication, i.e. after 20 failed authentications or after 600 requests per minute from one IP). Retry-After gives the seconds to wait.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "502": {
            "description": "Hosting backend failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "503": {
            "description": "API or hosting backend unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "405": {
            "description": "Method not allowed for this route",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "site_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Opaque public site identifier; never a domain name"
          }
        ]
      }
    },
    "/sites/{site_id}/backups": {
      "get": {
        "operationId": "listBackups",
        "summary": "List backups for this WordPress installation, newest first",
        "description": "Sorted newest first by created_at; backups without a known date come last. created_at (UTC) and size_bytes are null if WP Toolkit does not report them.",
        "x-permission": "backups:read",
        "security": [
          {
            "apiToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Backups and next cursor",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BackupListResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid syntax, JSON, cursor or idempotency key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Permission denied for a known owned target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "404": {
            "description": "Target or operation not found or not accessible",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "409": {
            "description": "Idempotency conflict or concurrent operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "422": {
            "description": "Operation rejected for this target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (error code rate_limited: per account, or per client IP before authentication, i.e. after 20 failed authentications or after 600 requests per minute from one IP). Retry-After gives the seconds to wait.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "502": {
            "description": "Hosting backend failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "503": {
            "description": "API or hosting backend unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "405": {
            "description": "Method not allowed for this route",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "site_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Opaque public site identifier; never a domain name"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Opaque cursor from the preceding response"
          }
        ]
      },
      "post": {
        "operationId": "createBackup",
        "summary": "Queue a WordPress backup",
        "x-permission": "backups:create",
        "security": [
          {
            "apiToken": []
          }
        ],
        "responses": {
          "202": {
            "description": "Backup operation queued",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OperationResponse"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "Operation URL",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Minimum polling interval in seconds",
                "schema": {
                  "type": "integer",
                  "minimum": 5
                }
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid syntax, JSON, cursor or idempotency key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Permission denied for a known owned target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "404": {
            "description": "Target or operation not found or not accessible",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "409": {
            "description": "Idempotency conflict or concurrent operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "413": {
            "description": "Request body, file or release exceeds the documented size limits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "415": {
            "description": "Request body present but Content-Type is not application/json",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "422": {
            "description": "Operation rejected for this target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (error code rate_limited: per account, or per client IP before authentication, i.e. after 20 failed authentications or after 600 requests per minute from one IP), or the account already has four open jobs (error code queue_full; nothing was created, retry later). Retry-After gives the seconds to wait.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "502": {
            "description": "Hosting backend failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "503": {
            "description": "API or hosting backend unavailable; also error code api_draining during a maintenance window (new writes are not accepted, Retry-After 120, no job or idempotency entry is created)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying (api_draining only)"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "405": {
            "description": "Method not allowed for this route",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "site_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Opaque public site identifier; never a domain name"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 16,
              "maxLength": 128,
              "pattern": "^[\\x20-\\x7E]+$"
            },
            "description": "Retained for 24 hours per account, token, method and route. Reuse after expiry may create a new operation."
          }
        ]
      }
    },
    "/sites/{site_id}/updates": {
      "get": {
        "operationId": "listUpdates",
        "summary": "List the open updates of this WordPress installation",
        "description": "Live read on every call (no cache): wp-cli on the installation reports plugin and theme updates and the offered WordPress core version. plugins and themes list only updates that are open right now, sorted by slug, at most 200 entries each; entries whose slug the update endpoint could not address are left out. core.current is read live from the installation (wp core version); null if that read fails or prints no valid version (never a stale inventory value); core.available is null if no core update is offered. If the state cannot be read the answer is 502 updates_unavailable, never an empty list. Only for WordPress sites (422 capability_unavailable otherwise).",
        "x-permission": "updates:read",
        "security": [
          {
            "apiToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Open updates",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UpdatesResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid syntax, JSON, cursor or idempotency key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Permission denied for a known owned target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "404": {
            "description": "Target or operation not found or not accessible",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "409": {
            "description": "Idempotency conflict or concurrent operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "422": {
            "description": "Not a WordPress site (capability_unavailable)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (error code rate_limited: per account, or per client IP before authentication, i.e. after 20 failed authentications or after 600 requests per minute from one IP). Retry-After gives the seconds to wait.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "502": {
            "description": "Update state could not be read (updates_unavailable) or hosting backend failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "503": {
            "description": "API or hosting backend unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "405": {
            "description": "Method not allowed for this route",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "site_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Opaque public site identifier; never a domain name"
          }
        ]
      },
      "post": {
        "operationId": "runUpdates",
        "summary": "Update plugins and themes (queued job, safety backup first)",
        "x-permission": "updates:run",
        "security": [
          {
            "apiToken": []
          }
        ],
        "responses": {
          "202": {
            "description": "Update job accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OperationResponse"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "Operation URL",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Minimum polling interval in seconds",
                "schema": {
                  "type": "integer",
                  "minimum": 5
                }
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid syntax, JSON, cursor or idempotency key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Permission denied for a known owned target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "404": {
            "description": "Target or operation not found or not accessible",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "409": {
            "description": "Idempotency conflict or concurrent operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "413": {
            "description": "Request body, file or release exceeds the documented size limits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "415": {
            "description": "Request body present but Content-Type is not application/json",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "422": {
            "description": "core_update_not_supported, too_many_items, item_not_installed, backup_limit_reached or capability_unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (error code rate_limited: per account, or per client IP before authentication, i.e. after 20 failed authentications or after 600 requests per minute from one IP), or the account already has four open jobs (error code queue_full; nothing was created, retry later). Retry-After gives the seconds to wait.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "502": {
            "description": "Hosting backend failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "503": {
            "description": "API or hosting backend unavailable; also error code api_draining during a maintenance window (new writes are not accepted, Retry-After 120, no job or idempotency entry is created)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying (api_draining only)"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "405": {
            "description": "Method not allowed for this route",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "site_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Opaque public site identifier; never a domain name"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 16,
              "maxLength": 128,
              "pattern": "^[\\x20-\\x7E]+$"
            },
            "description": "Retained for 24 hours per account, token, method and route. Reuse after expiry may create a new operation."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdatesRunRequest"
              }
            }
          }
        },
        "description": "Queues one job (202 + Operation kind updates:run). Body: 1 to 5 items {type: plugin|theme, slug}, no duplicates; WordPress core is not supported (a request with a core key or an item of type core is rejected with 422 core_update_not_supported, more than 5 items with 422 too_many_items). Rejected up front without a job: 422 item_not_installed (an item is not installed), 422 backup_limit_reached (the installation has reached its backup limit; delete a backup first), 502 updates_unavailable. The job takes exactly one safety backup, then updates the items one by one and reads each version back. The operation result is {safety_backup: file name or null, items: [{type, slug, from, to, status}]} with status updated, unchanged, failed, skipped or unconfirmed; it is also present on failed and unknown operations. Job budget 360 s from the start of the handler (the safety-backup wait is part of it); an item is only started with at least 180 s left (120 s update call + 60 s read-back), otherwise it is skipped and the operation ends failed with time_budget_exhausted. Failed codes: safety_backup_pending / safety_backup_failed (no update was started), backup_limit_reached, daily_limit, item_not_installed, update_failed, time_budget_exhausted. An unconfirmed result ends unknown. Daily limit 30 runs per account, shared with the AI access."
      }
    },
    "/sites/{site_id}/backups/{backup_id}": {
      "delete": {
        "operationId": "deleteBackup",
        "summary": "Queue the permanent deletion of one backup",
        "x-permission": "backups:delete",
        "security": [
          {
            "apiToken": []
          }
        ],
        "responses": {
          "202": {
            "description": "Deletion operation queued",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OperationResponse"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "Operation URL",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Minimum polling interval in seconds",
                "schema": {
                  "type": "integer",
                  "minimum": 5
                }
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid syntax, JSON, cursor or idempotency key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Permission denied for a known owned target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "404": {
            "description": "Target, backup (error code backup_not_found) or operation not found or not accessible",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "409": {
            "description": "Idempotency conflict or concurrent operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "422": {
            "description": "Operation rejected for this target: backup_protected (newest backup of the site), backup_in_use (a backup is being created or its outcome is unclear), or capability_unavailable (not a WordPress site)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (error code rate_limited: per account, or per client IP before authentication, i.e. after 20 failed authentications or after 600 requests per minute from one IP), or the account already has four open jobs (error code queue_full; nothing was created, retry later). Retry-After gives the seconds to wait.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "502": {
            "description": "Hosting backend failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "503": {
            "description": "API or hosting backend unavailable; also error code api_draining during a maintenance window (new writes are not accepted, Retry-After 120, no job or idempotency entry is created)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying (api_draining only)"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "405": {
            "description": "Method not allowed for this route",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "site_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Opaque public site identifier; never a domain name"
          },
          {
            "name": "backup_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Backup id from GET /sites/{site_id}/backups (the file name)"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 16,
              "maxLength": 128,
              "pattern": "^[\\x20-\\x7E]+$"
            },
            "description": "Retained for 24 hours per account, token, method and route. Reuse after expiry may create a new operation."
          }
        ],
        "description": "Irreversible. The backup is removed from the WordPress installation as an asynchronous operation (kind backups:delete). backup_id is the id returned by GET /sites/{site_id}/backups (path-encoding of + and : is optional). Two rules protect the site: the newest backup is never deleted (422 backup_protected), and no backup is deleted while a backup is being created or its outcome is unclear (422 backup_in_use). Both rules are checked when the request arrives and again when the operation runs; in the second case the operation ends as failed with the same error_code. An unknown id is 404 backup_not_found. A repeated request with the same Idempotency-Key returns the same operation and never deletes twice. The result of a succeeded operation is {filename, remaining_backups, deletion_verified: true}; if the deletion could not be confirmed, the operation ends as unknown."
      }
    },
    "/sites/{site_id}/cache/purge": {
      "post": {
        "operationId": "purgeCache",
        "summary": "Queue a cache purge",
        "x-permission": "cache:purge",
        "security": [
          {
            "apiToken": []
          }
        ],
        "responses": {
          "202": {
            "description": "Purge operation queued",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OperationResponse"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "Operation URL",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Minimum polling interval in seconds",
                "schema": {
                  "type": "integer",
                  "minimum": 5
                }
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid syntax, JSON, cursor or idempotency key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Permission denied for a known owned target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "404": {
            "description": "Target or operation not found or not accessible",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "409": {
            "description": "Idempotency conflict or concurrent operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "413": {
            "description": "Request body, file or release exceeds the documented size limits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "415": {
            "description": "Request body present but Content-Type is not application/json",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "422": {
            "description": "Operation rejected for this target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (error code rate_limited: per account, or per client IP before authentication, i.e. after 20 failed authentications or after 600 requests per minute from one IP), or the account already has four open jobs (error code queue_full; nothing was created, retry later). Retry-After gives the seconds to wait.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "502": {
            "description": "Hosting backend failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "503": {
            "description": "API or hosting backend unavailable; also error code api_draining during a maintenance window (new writes are not accepted, Retry-After 120, no job or idempotency entry is created)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying (api_draining only)"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "405": {
            "description": "Method not allowed for this route",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "site_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Opaque public site identifier; never a domain name"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 16,
              "maxLength": 128,
              "pattern": "^[\\x20-\\x7E]+$"
            },
            "description": "Retained for 24 hours per account, token, method and route. Reuse after expiry may create a new operation."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CachePurgeRequest"
              }
            }
          }
        }
      }
    },
    "/operations": {
      "get": {
        "operationId": "listOperations",
        "summary": "List the operations created with this token, newest first",
        "description": "Returns only operations that this token created, for sites that are still among its targets and whose original permission the token (and its issuing user) still holds. Other tokens, other accounts and other sites never appear, and the page boundary depends on visible rows only. No hosting backend is contacted. Does not count as a poll of the individual operations.",
        "x-permission": "original operation permission",
        "security": [
          {
            "apiToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Operations and next cursor",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OperationListResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid syntax, JSON, cursor or idempotency key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Permission denied for a known owned target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "404": {
            "description": "Target or operation not found or not accessible",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "409": {
            "description": "Idempotency conflict or concurrent operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "422": {
            "description": "Operation rejected for this target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (error code rate_limited: per account, or per client IP before authentication, i.e. after 20 failed authentications or after 600 requests per minute from one IP). Retry-After gives the seconds to wait.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "502": {
            "description": "Hosting backend failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "503": {
            "description": "API or hosting backend unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "405": {
            "description": "Method not allowed for this route",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "site_id",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Only operations of this site; must be a target of the token (otherwise 404 site_not_found)"
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "queued",
                "running",
                "succeeded",
                "failed",
                "unknown"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Opaque cursor from the preceding response; valid only for the same token and the same site_id and status filters"
          }
        ]
      }
    },
    "/operations/{id}": {
      "get": {
        "operationId": "getOperation",
        "summary": "Get operation state; original permission and current target access are rechecked",
        "x-permission": "original operation permission",
        "security": [
          {
            "apiToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Operation state",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OperationResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 5
                }
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid syntax, JSON, cursor or idempotency key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Permission denied for a known owned target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "404": {
            "description": "Target or operation not found or not accessible",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "409": {
            "description": "Idempotency conflict or concurrent operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "422": {
            "description": "Operation rejected for this target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (error code rate_limited: per account, or per client IP before authentication, i.e. after 20 failed authentications or after 600 requests per minute from one IP). Retry-After gives the seconds to wait.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "502": {
            "description": "Hosting backend failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "503": {
            "description": "API or hosting backend unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "405": {
            "description": "Method not allowed for this route",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/token": {
      "get": {
        "operationId": "getToken",
        "summary": "Describe the calling token (metadata only, never the secret or its hash)",
        "x-permission": "none (any valid token)",
        "security": [
          {
            "apiToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Token metadata",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenInfoResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid syntax, JSON, cursor or idempotency key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Permission denied for a known owned target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "404": {
            "description": "Target or operation not found or not accessible",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "409": {
            "description": "Idempotency conflict or concurrent operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "422": {
            "description": "Operation rejected for this target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (error code rate_limited: per account, or per client IP before authentication, i.e. after 20 failed authentications or after 600 requests per minute from one IP). Retry-After gives the seconds to wait.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "502": {
            "description": "Hosting backend failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "503": {
            "description": "API or hosting backend unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "405": {
            "description": "Method not allowed for this route",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/sites/{site_id}/deployments": {
      "post": {
        "operationId": "createDeployment",
        "summary": "Open an AI Launch deployment",
        "x-permission": "static:deploy",
        "security": [
          {
            "apiToken": []
          }
        ],
        "responses": {
          "201": {
            "description": "Deployment opened",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeploymentResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid syntax, JSON, cursor or idempotency key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Permission denied for a known owned target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "404": {
            "description": "Target or operation not found or not accessible",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "409": {
            "description": "Idempotency conflict or concurrent operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "413": {
            "description": "Request body, file or release exceeds the documented size limits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "415": {
            "description": "Request body present but Content-Type is not application/json",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "422": {
            "description": "Operation rejected for this target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (error code rate_limited: per account, or per client IP before authentication, i.e. after 20 failed authentications or after 600 requests per minute from one IP). Retry-After gives the seconds to wait.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "500": {
            "description": "Server-side hosting context is incomplete (invalid_context); contact support with the request ID",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "502": {
            "description": "Hosting backend failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "503": {
            "description": "API or hosting backend unavailable; also error code api_draining during a maintenance window (new writes are not accepted, Retry-After 120, no job or idempotency entry is created)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying (api_draining only)"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "405": {
            "description": "Method not allowed for this route",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "site_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Opaque public site identifier; never a domain name"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 16,
              "maxLength": 128,
              "pattern": "^[\\x20-\\x7E]+$"
            },
            "description": "Retained for 24 hours per account, token, method and route. Reuse after expiry may create a new operation."
          }
        ]
      },
      "get": {
        "operationId": "listDeployments",
        "summary": "List AI Launch deployments",
        "x-permission": "static:deploy",
        "security": [
          {
            "apiToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Deployments and next cursor",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeploymentListResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid syntax, JSON, cursor or idempotency key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Permission denied for a known owned target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "404": {
            "description": "Target or operation not found or not accessible",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "409": {
            "description": "Idempotency conflict or concurrent operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "422": {
            "description": "Operation rejected for this target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (error code rate_limited: per account, or per client IP before authentication, i.e. after 20 failed authentications or after 600 requests per minute from one IP). Retry-After gives the seconds to wait.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "500": {
            "description": "Server-side hosting context is incomplete (invalid_context); contact support with the request ID",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "502": {
            "description": "Hosting backend failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "503": {
            "description": "API or hosting backend unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "405": {
            "description": "Method not allowed for this route",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "site_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Opaque public site identifier; never a domain name"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Opaque cursor from the preceding response"
          }
        ]
      }
    },
    "/sites/{site_id}/deployments/{id}/files": {
      "put": {
        "operationId": "putDeploymentFile",
        "summary": "Add or replace a deployment file",
        "x-permission": "static:deploy",
        "security": [
          {
            "apiToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "File recorded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeploymentFileResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid syntax, JSON, cursor or idempotency key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Permission denied for a known owned target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "404": {
            "description": "Target or operation not found or not accessible",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "409": {
            "description": "Idempotency conflict or concurrent operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "413": {
            "description": "Request body, file or release exceeds the documented size limits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "415": {
            "description": "Request body present but Content-Type is not application/json",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "422": {
            "description": "Operation rejected for this target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (error code rate_limited: per account, or per client IP before authentication, i.e. after 20 failed authentications or after 600 requests per minute from one IP). Retry-After gives the seconds to wait.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "500": {
            "description": "Server-side hosting context is incomplete (invalid_context); contact support with the request ID",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "502": {
            "description": "Hosting backend failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "503": {
            "description": "API or hosting backend unavailable; also error code api_draining during a maintenance window (new writes are not accepted, Retry-After 120, no job or idempotency entry is created)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying (api_draining only)"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "405": {
            "description": "Method not allowed for this route",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "site_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Opaque public site identifier; never a domain name"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 16,
              "maxLength": 128,
              "pattern": "^[\\x20-\\x7E]+$"
            },
            "description": "Retained for 24 hours per account, token, method and route. Reuse after expiry may create a new operation."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeploymentFileRequest"
              }
            }
          }
        }
      }
    },
    "/sites/{site_id}/deployments/{id}/preview": {
      "post": {
        "operationId": "previewDeployment",
        "summary": "Validate deployment and return preview",
        "x-permission": "static:deploy",
        "security": [
          {
            "apiToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Validation report and preview",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeploymentPreviewResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid syntax, JSON, cursor or idempotency key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Permission denied for a known owned target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "404": {
            "description": "Target or operation not found or not accessible",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "409": {
            "description": "Idempotency conflict or concurrent operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "413": {
            "description": "Request body, file or release exceeds the documented size limits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "415": {
            "description": "Request body present but Content-Type is not application/json",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "422": {
            "description": "Operation rejected for this target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (error code rate_limited: per account, or per client IP before authentication, i.e. after 20 failed authentications or after 600 requests per minute from one IP). Retry-After gives the seconds to wait.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "500": {
            "description": "Server-side hosting context is incomplete (invalid_context); contact support with the request ID",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "502": {
            "description": "Hosting backend failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "503": {
            "description": "API or hosting backend unavailable; also error code api_draining during a maintenance window (new writes are not accepted, Retry-After 120, no job or idempotency entry is created)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying (api_draining only)"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "405": {
            "description": "Method not allowed for this route",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "site_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Opaque public site identifier; never a domain name"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 16,
              "maxLength": 128,
              "pattern": "^[\\x20-\\x7E]+$"
            },
            "description": "Retained for 24 hours per account, token, method and route. Reuse after expiry may create a new operation."
          }
        ]
      }
    },
    "/sites/{site_id}/deployments/{id}/publish": {
      "post": {
        "operationId": "publishDeployment",
        "summary": "Queue deployment publication",
        "x-permission": "static:deploy",
        "security": [
          {
            "apiToken": []
          }
        ],
        "responses": {
          "202": {
            "description": "Publish operation queued",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OperationResponse"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "Operation URL",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Minimum polling interval in seconds",
                "schema": {
                  "type": "integer",
                  "minimum": 5
                }
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid syntax, JSON, cursor or idempotency key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Permission denied for a known owned target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "404": {
            "description": "Target or operation not found or not accessible",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "409": {
            "description": "Idempotency conflict or concurrent operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "413": {
            "description": "Request body, file or release exceeds the documented size limits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "415": {
            "description": "Request body present but Content-Type is not application/json",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "422": {
            "description": "Operation rejected for this target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (error code rate_limited: per account, or per client IP before authentication, i.e. after 20 failed authentications or after 600 requests per minute from one IP), or the account already has four open jobs (error code queue_full; nothing was created, retry later). Retry-After gives the seconds to wait.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "500": {
            "description": "Server-side hosting context is incomplete (invalid_context); contact support with the request ID",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "502": {
            "description": "Hosting backend failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "503": {
            "description": "API or hosting backend unavailable; also error code api_draining during a maintenance window (new writes are not accepted, Retry-After 120, no job or idempotency entry is created)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying (api_draining only)"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "405": {
            "description": "Method not allowed for this route",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "site_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Opaque public site identifier; never a domain name"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 16,
              "maxLength": 128,
              "pattern": "^[\\x20-\\x7E]+$"
            },
            "description": "Retained for 24 hours per account, token, method and route. Reuse after expiry may create a new operation."
          }
        ]
      }
    },
    "/sites/{site_id}/deployments/{id}/rollback": {
      "post": {
        "operationId": "rollbackDeployment",
        "summary": "Queue rollback to a previous static version",
        "x-permission": "static:deploy",
        "security": [
          {
            "apiToken": []
          }
        ],
        "responses": {
          "202": {
            "description": "Rollback operation queued",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OperationResponse"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "Operation URL",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Minimum polling interval in seconds",
                "schema": {
                  "type": "integer",
                  "minimum": 5
                }
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid syntax, JSON, cursor or idempotency key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Permission denied for a known owned target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "404": {
            "description": "Target or operation not found or not accessible",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "409": {
            "description": "Idempotency conflict or concurrent operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "413": {
            "description": "Request body, file or release exceeds the documented size limits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "415": {
            "description": "Request body present but Content-Type is not application/json",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "422": {
            "description": "Operation rejected for this target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (error code rate_limited: per account, or per client IP before authentication, i.e. after 20 failed authentications or after 600 requests per minute from one IP), or the account already has four open jobs (error code queue_full; nothing was created, retry later). Retry-After gives the seconds to wait.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "500": {
            "description": "Server-side hosting context is incomplete (invalid_context); contact support with the request ID",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "502": {
            "description": "Hosting backend failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "503": {
            "description": "API or hosting backend unavailable; also error code api_draining during a maintenance window (new writes are not accepted, Retry-After 120, no job or idempotency entry is created)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying (api_draining only)"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "405": {
            "description": "Method not allowed for this route",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "site_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Opaque public site identifier; never a domain name"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 16,
              "maxLength": 128,
              "pattern": "^[\\x20-\\x7E]+$"
            },
            "description": "Retained for 24 hours per account, token, method and route. Reuse after expiry may create a new operation."
          }
        ]
      }
    },
    "/status": {
      "get": {
        "operationId": "getStatus",
        "summary": "Anonymous API status (no token needed)",
        "description": "Health and intake state for monitors and CI. No authentication, no account data, no audit entry; the per-IP request limit applies. While the API is switched off this route answers 503 api_unavailable like every other route.",
        "x-permission": "none (anonymous)",
        "security": [],
        "responses": {
          "200": {
            "description": "API is reachable; status is draining while the API accepts no new changes (reads and polling continue)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StatusResponse"
                }
              }
            }
          },
          "405": {
            "description": "Method not allowed for this route",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Per client IP limit (rate_limited): this route needs no token but counts toward the IP request limit. Retry-After gives the seconds to wait.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying"
              }
            }
          },
          "503": {
            "description": "API switched off (api_unavailable) or hosting unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/sites/{site_id}/staging": {
      "delete": {
        "operationId": "deleteStaging",
        "summary": "Delete the staging copy of this live site (queued job, irreversible)",
        "x-permission": "staging:delete",
        "security": [
          {
            "apiToken": []
          }
        ],
        "responses": {
          "202": {
            "description": "Staging deletion job accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OperationResponse"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "Operation URL",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Minimum polling interval in seconds",
                "schema": {
                  "type": "integer",
                  "minimum": 5
                }
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid syntax, JSON, cursor or idempotency key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Permission denied for a known owned target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "404": {
            "description": "Target or operation not found or not accessible; staging_not_found if the site has no staging copy",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "409": {
            "description": "Idempotency conflict or concurrent operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "422": {
            "description": "confirmation_mismatch, staging_in_use or capability_unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (error code rate_limited: per account, or per client IP before authentication, i.e. after 20 failed authentications or after 600 requests per minute from one IP), or the account already has four open jobs (error code queue_full; nothing was created, retry later). Retry-After gives the seconds to wait.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "502": {
            "description": "Hosting backend failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "503": {
            "description": "API or hosting backend unavailable; also error code api_draining during a maintenance window (new writes are not accepted, Retry-After 120, no job or idempotency entry is created)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying (api_draining only)"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "405": {
            "description": "Method not allowed for this route",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "site_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Opaque public site identifier; never a domain name"
          },
          {
            "name": "confirm",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Host of the staging site, e.g. staging.example.com"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 16,
              "maxLength": 128,
              "pattern": "^[\\x20-\\x7E]+$"
            },
            "description": "Retained for 24 hours per account, token, method and route. Reuse after expiry may create a new operation."
          }
        ],
        "description": "Addressed through the LIVE site, which must be a target of the token (the staging site need not be). confirm must equal the host of the staging site exactly (ASCII; IDN hosts in punycode). The staging copy is found only by the staging rule (host staging.<main domain>, same package); the live site can never be deleted. Rejected up front: 404 staging_not_found, 422 confirmation_mismatch, 422 staging_in_use (a backup or update is open). Result of a succeeded operation: {staging_host, deleted: true, subdomain_removed}. An unconfirmed result ends unknown. Daily limit 5 per account, shared with the AI access."
      },
      "post": {
        "operationId": "createStaging",
        "summary": "Create the staging copy of this live site (queued job)",
        "x-permission": "staging:create",
        "security": [
          {
            "apiToken": []
          }
        ],
        "responses": {
          "202": {
            "description": "Staging creation job accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OperationResponse"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "Operation URL",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Minimum polling interval in seconds",
                "schema": {
                  "type": "integer",
                  "minimum": 5
                }
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid syntax, JSON, scope, folder, cursor or idempotency key (invalid_scope, invalid_folder, invalid_arguments)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Permission denied for a known owned target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "404": {
            "description": "Target or operation not found or not accessible",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "409": {
            "description": "Idempotency conflict, staging_exists, or site_busy",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "413": {
            "description": "Request body, file or release exceeds the documented size limits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "415": {
            "description": "Request body present but Content-Type is not application/json",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "422": {
            "description": "capability_unavailable (a staging site), no_live_instance or storage_insufficient",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded or daily_limit or daily_limit (3 full and 3 partial restores per day and account) (error code rate_limited: per account, or per client IP before authentication, i.e. after 20 failed authentications or after 600 requests per minute from one IP), or the account already has four open jobs (error code queue_full; nothing was created, retry later). Retry-After gives the seconds to wait.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "502": {
            "description": "Hosting backend failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "503": {
            "description": "API or hosting backend unavailable, or delegation_unavailable (long operations temporarily switched off); also error code api_draining during a maintenance window (new writes are not accepted, Retry-After 120, no job or idempotency entry is created)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying (api_draining only)"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "405": {
            "description": "Method not allowed for this route",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "site_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Opaque public site identifier; never a domain name"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 16,
              "maxLength": 128,
              "pattern": "^[\\x20-\\x7E]+$"
            },
            "description": "Retained for 24 hours per account, token, method and route. Reuse after expiry may create a new operation."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmptyRequest"
              }
            }
          }
        },
        "description": "Queues one job (202 + Operation kind staging:create) that creates the one staging copy `staging.<main domain>` of the LIVE site (a staging site cannot be the source; the site must be a target of the token). Body: {} only; the name is fixed and cannot be chosen. Runs in the WP-Cockpit worker (see the delegation notes) under the shared site lock with a reservation: subdomain, clone (WP Toolkit), read-back of the new installation, best-effort SSL. Rejected up front without a job: 422 capability_unavailable (a staging site), 422 no_live_instance, 409 staging_exists (a copy exists, or the subdomain staging.<main domain> already exists without a copy, for example left by a refused clone: remove it in the panel or ask Support, DELETE /sites/{site_id}/staging cannot because there is no installation; this check costs no daily limit), 422 storage_insufficient (the webspace measurably has too little room; an unmeasurable quota is not a refusal), 502 preparation_failed (the subdomain could not be checked; nothing was changed), 409 site_busy, 429 daily_limit (the API enforces 3 a day and account; creations through chat, MCP and Cockpit count on the same counter, and API creations count against their limit of 5), 503 delegation_unavailable. Result on success {staging_host, ssl: issued|failed|unconfirmed, staging_site_id: site id or null}. staging_site_id is the id to select when you issue a token for the new site (null when it could not be determined; it then appears in the token form after the sites are refreshed). The new site is not a target of existing tokens. failed clone_failed: WP Toolkit refused the clone, the empty subdomain stays (result {staging_host, subdomain_left: true}) and has to be removed in the panel or by Support; until then every new request is refused up front as staging_exists without using the daily limit. unknown clone_unconfirmed: the clone was started but the new installation was not seen; the site stays locked until Support settles it. Other unknown codes: staging_outcome_unknown (the answer of Plesk to the subdomain creation was a connection error or not clearly readable; the subdomain may exist and the site stays locked until Support has settled it), effect_uncertain, worker_lost, backend_timeout, unconfirmed_result. Failed before any change (the site is not locked afterwards): staging_exists, storage_insufficient, preparation_failed (an error before the first step), subdomain_creation_failed (only for a clear error message of Plesk), daily_limit, site_busy, service_unavailable, access_removed, token_inactive, api_unavailable, delegation_not_started, job_expired. There is no safety backup (nothing of the live site is changed)."
      }
    },
    "/sites/{site_id}/backups/{backup_id}/restore": {
      "post": {
        "operationId": "restoreBackup",
        "summary": "Restore a backup over the site (queued job, overwrites the site, safety backup first)",
        "x-permission": "backups:restore",
        "security": [
          {
            "apiToken": []
          }
        ],
        "responses": {
          "202": {
            "description": "Restore job accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OperationResponse"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "Operation URL",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Minimum polling interval in seconds",
                "schema": {
                  "type": "integer",
                  "minimum": 5
                }
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid syntax, JSON, scope, folder, cursor or idempotency key (invalid_scope, invalid_folder, invalid_arguments)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Permission denied for a known owned target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "404": {
            "description": "Target, backup (error code backup_not_found) or operation not found or not accessible",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "409": {
            "description": "Idempotency conflict, or site_busy (another operation, automatic update, support lock or reservation on the subscription)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "413": {
            "description": "Request body, file or release exceeds the documented size limits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "415": {
            "description": "Request body present but Content-Type is not application/json",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "422": {
            "description": "confirmation_mismatch, woo_confirmation_missing, backup_limit_reached, backup_in_use, service_unavailable or capability_unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded or daily_limit (3 full and 3 partial restores per day and account) (error code rate_limited: per account, or per client IP before authentication, i.e. after 20 failed authentications or after 600 requests per minute from one IP), or the account already has four open jobs (error code queue_full; nothing was created, retry later). Retry-After gives the seconds to wait.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "502": {
            "description": "Hosting backend failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "503": {
            "description": "API or hosting backend unavailable, or delegation_unavailable (long operations temporarily switched off); also error code api_draining during a maintenance window (new writes are not accepted, Retry-After 120, no job or idempotency entry is created)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying (api_draining only)"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "405": {
            "description": "Method not allowed for this route",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "site_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Opaque public site identifier; never a domain name"
          },
          {
            "name": "backup_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Backup id from GET /sites/{site_id}/backups (the file name)"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 16,
              "maxLength": 128,
              "pattern": "^[\\x20-\\x7E]+$"
            },
            "description": "Retained for 24 hours per account, token, method and route. Reuse after expiry may create a new operation."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BackupRestoreRequest"
              }
            }
          }
        },
        "description": "Queues one job (202 + Operation kind backups:restore) that overwrites the site with a backup. OVERWRITES the website: everything written after the backup is lost (for scope full or database that includes WooCommerce orders and customers). The job runs in the WP-Cockpit worker, takes exactly one safety backup first and restores only when that backup is confirmed. Body: scope (required): full = the whole backup as a WP Toolkit restore task, database = only the database, files = only the files (newer files stay, wp-config.php is never replaced), folder = one wp-content folder, mirrored to the state of the backup (files not in the backup are deleted from that folder); folder (required with scope folder only): wp-content/uploads, wp-content/plugins/<slug> or wp-content/themes/<slug>; confirm_host (required): the exact host of this site (restores overwrite); confirm_data_loss (boolean, default false): must be true for scope full or database when WooCommerce is active on the site (an unreadable plugin list counts as active). backup_id must be a backup of this very installation (a staging copy's backups are only restorable through the staging site). Rejected up front without a job: 400 invalid_scope / invalid_folder / invalid_arguments, 403 permission_denied, 404 backup_not_found, 422 confirmation_mismatch, woo_confirmation_missing, backup_limit_reached (delete a backup first), backup_in_use, service_unavailable, 409 site_busy (another operation, automatic update, support lock or reservation on the subscription), 429 daily_limit (3 full and 3 partial restores per day and account, shared with the AI access), 503 delegation_unavailable. Result {safety_backup: file name or null, scope, restore_task: succeeded|pending|unknown|failed (full only), health_check: ok|issue_found|not_run (partial only)}; present on succeeded and, where it applies, on failed and unknown operations. succeeded: full needs the restore task seen succeeded; partial needs the finished import and a health check answer (issue_found is still succeeded: the site was restored, a check found a problem; the safety backup is the way back). A full restore whose WP Toolkit task is still running when the job ends stays running while the API polls the task (at most 30 minutes), then ends succeeded, failed restore_failed or unknown restore_pending (the site unlocks itself when the task ends). failed restore_failed: the import tool reported errors, the site may be partly restored (restore the safety backup). unknown (restore_outcome_unknown, restore_pending, effect_uncertain, worker_lost, backend_timeout, unconfirmed_result): the outcome is unclear, check the site; the site stays locked until the outcome is settled (partial restores: until Support releases it). Failed before any change: backup_not_found, confirmation_mismatch, woo_confirmation_missing, backup_limit_reached, safety_backup_pending, safety_backup_failed, daily_limit, site_busy, service_unavailable, backup_unsafe, backup_unreadable, no_database_in_backup, no_files_in_backup, folder_not_in_backup, siteurl_mismatch, siteurl_unreadable, time_budget_exhausted, delegation_not_started, job_expired. There is no automatic rollback."
      }
    },
    "/sites/{site_id}/core-update": {
      "post": {
        "operationId": "updateCore",
        "summary": "Update WordPress core (queued job, safety backup first)",
        "x-permission": "updates:core",
        "security": [
          {
            "apiToken": []
          }
        ],
        "responses": {
          "202": {
            "description": "Core update job accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OperationResponse"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "Operation URL",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Minimum polling interval in seconds",
                "schema": {
                  "type": "integer",
                  "minimum": 5
                }
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid syntax, JSON, scope, folder, cursor or idempotency key (invalid_scope, invalid_folder, invalid_arguments)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Permission denied for a known owned target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "404": {
            "description": "Target or operation not found or not accessible",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "409": {
            "description": "Idempotency conflict, version_changed, or site_busy",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "413": {
            "description": "Request body, file or release exceeds the documented size limits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "415": {
            "description": "Request body present but Content-Type is not application/json",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "422": {
            "description": "no_core_update, backup_limit_reached, backup_in_use, service_unavailable or capability_unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded or daily_limit or daily_limit (3 full and 3 partial restores per day and account) (error code rate_limited: per account, or per client IP before authentication, i.e. after 20 failed authentications or after 600 requests per minute from one IP), or the account already has four open jobs (error code queue_full; nothing was created, retry later). Retry-After gives the seconds to wait.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "502": {
            "description": "Hosting backend failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "503": {
            "description": "API or hosting backend unavailable, or delegation_unavailable (long operations temporarily switched off); also error code api_draining during a maintenance window (new writes are not accepted, Retry-After 120, no job or idempotency entry is created)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying (api_draining only)"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "405": {
            "description": "Method not allowed for this route",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "site_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Opaque public site identifier; never a domain name"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 16,
              "maxLength": 128,
              "pattern": "^[\\x20-\\x7E]+$"
            },
            "description": "Retained for 24 hours per account, token, method and route. Reuse after expiry may create a new operation."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CoreUpdateRequest"
              }
            }
          }
        },
        "description": "Queues one job (202 + Operation kind updates:core) that updates WordPress itself. Runs in the WP-Cockpit worker (see the delegation notes), takes exactly one safety backup first and updates only when that backup is confirmed. Body: {} or {\"expected_version\": \"6.8.3\"} (refuse when another version is offered, 409 version_changed). Rejected up front without a job: 422 no_core_update (core is current), 409 version_changed, 422 backup_limit_reached, backup_in_use, service_unavailable, 409 site_busy, 429 daily_limit (10 a day and account, API only), 502 updates_unavailable, 503 delegation_unavailable. Result {safety_backup: file name or null, from: version or null, to: version or null}; present on failed and unknown operations where it applies. succeeded only when the version read back (up to three tries) is NEWER than the version before; both come from `wp core version` on the installation. core_version_unreadable (failed): the version before could not be read, nothing was done. failed core_not_updated: the call returned but the version is unchanged. failed core_update_failed: the tool reported an error and the version is unchanged. unknown core_update_partial: the tool reported an error but the version changed. unknown (core_version_unconfirmed, core_update_partial, effect_uncertain, worker_lost, backend_timeout, unconfirmed_result): the outcome is unclear; check the site. It stays locked until Support settles it only after effect_uncertain and worker_lost. Failed before any change: no_core_update, version_changed, backup_limit_reached, safety_backup_pending, safety_backup_failed, daily_limit, site_busy, service_unavailable, access_removed, token_inactive, delegation_not_started, job_expired. No automatic rollback. The core update has a 1800 s limit."
      }
    },
    "/sites/{site_id}/plugins/{slug}/state": {
      "post": {
        "operationId": "setPluginState",
        "summary": "Activate or deactivate one installed plugin (queued job)",
        "x-permission": "plugins:manage",
        "security": [
          {
            "apiToken": []
          }
        ],
        "responses": {
          "202": {
            "description": "Plugin switch job accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OperationResponse"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "Operation URL",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Minimum polling interval in seconds",
                "schema": {
                  "type": "integer",
                  "minimum": 5
                }
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid syntax, JSON, scope, folder, cursor or idempotency key (invalid_scope, invalid_folder, invalid_arguments)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Permission denied for a known owned target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "404": {
            "description": "Target, plugin (error code plugin_not_installed) or operation not found or not accessible",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "409": {
            "description": "Idempotency conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "413": {
            "description": "Request body, file or release exceeds the documented size limits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "415": {
            "description": "Request body present but Content-Type is not application/json",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "422": {
            "description": "network_activated or capability_unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded or daily_limit or daily_limit (3 full and 3 partial restores per day and account) (error code rate_limited: per account, or per client IP before authentication, i.e. after 20 failed authentications or after 600 requests per minute from one IP), or the account already has four open jobs (error code queue_full; nothing was created, retry later). Retry-After gives the seconds to wait.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "502": {
            "description": "Hosting backend failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "503": {
            "description": "API or hosting backend unavailable, or delegation_unavailable (long operations temporarily switched off); also error code api_draining during a maintenance window (new writes are not accepted, Retry-After 120, no job or idempotency entry is created)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying (api_draining only)"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "405": {
            "description": "Method not allowed for this route",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "site_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Opaque public site identifier; never a domain name"
          },
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9][a-z0-9_.-]{0,61}$"
            },
            "description": "Plugin slug (directory name), see GET /sites/{site_id}/updates"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 16,
              "maxLength": 128,
              "pattern": "^[\\x20-\\x7E]+$"
            },
            "description": "Retained for 24 hours per account, token, method and route. Reuse after expiry may create a new operation."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PluginStateRequest"
              }
            }
          }
        },
        "description": "Queues one job (202 + Operation kind plugins:manage) in the API worker under the shared site lock. Body: {\"enabled\": true|false}. Rejected up front without a job: 400 invalid_arguments (slug or enabled), 404 plugin_not_installed, 422 network_activated (a network-activated plugin cannot be deactivated here), 429 daily_limit (20 a day and account, API only), 502 plugins_unavailable. Result {slug, enabled, changed}: succeeded only when the state read back shows the wanted state; a plugin already in that state succeeds with changed=false. A switch that cannot be confirmed ends unknown plugin_state_unconfirmed; a clean tool error ends failed plugin_state_failed. No safety backup is taken. Reading and switching run with --skip-plugins --skip-themes, so a plugin that breaks the site on load can still be deactivated. The API does not stop you from deactivating security or cache plugins or WooCommerce."
      }
    },
    "/sites/{site_id}/staging/push": {
      "post": {
        "operationId": "pushStaging",
        "summary": "Overwrite the live site with its staging copy (queued job, safety backup first; dry_run answers at once)",
        "x-permission": "staging:push",
        "security": [
          {
            "apiToken": []
          }
        ],
        "responses": {
          "202": {
            "description": "Staging push job accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OperationResponse"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "Operation URL",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Minimum polling interval in seconds",
                "schema": {
                  "type": "integer",
                  "minimum": 5
                }
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid syntax, JSON, scope, tables, delete_missing_files, confirm_host or idempotency key (invalid_scope, invalid_arguments)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Permission denied for a known owned target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "404": {
            "description": "Target, staging copy (staging_not_found) or operation not found or not accessible",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "409": {
            "description": "Idempotency conflict, staging_ambiguous, or site_busy",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "413": {
            "description": "Request body, file or release exceeds the documented size limits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "415": {
            "description": "Request body present but Content-Type is not application/json",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "422": {
            "description": "no_live_instance (also a staging site), confirmation_mismatch, woo_confirmation_missing, unknown_table, backup_limit_reached, backup_in_use, service_unavailable or capability_unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded or daily_limit or daily_limit (3 full and 3 partial restores per day and account) (error code rate_limited: per account, or per client IP before authentication, i.e. after 20 failed authentications or after 600 requests per minute from one IP), or the account already has four open jobs (error code queue_full; nothing was created, retry later). Retry-After gives the seconds to wait.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "502": {
            "description": "Hosting backend failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "503": {
            "description": "API or hosting backend unavailable, or delegation_unavailable (long operations temporarily switched off); also error code api_draining during a maintenance window (new writes are not accepted, Retry-After 120, no job or idempotency entry is created)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Seconds to wait before retrying (api_draining only)"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          },
          "405": {
            "description": "Method not allowed for this route",
            "headers": {
              "Allow": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "200": {
            "description": "Dry run result (no effect)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StagingPushDryRunResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "site_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Opaque public site identifier; never a domain name"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 16,
              "maxLength": 128,
              "pattern": "^[\\x20-\\x7E]+$"
            },
            "description": "Required unless dry_run is true. Retained for 24 hours per account, token, method and route."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StagingPushRequest"
              }
            }
          }
        },
        "description": "OVERWRITES THE LIVE SITE with its staging copy (files, database, or selected tables), irreversibly except by restoring the safety backup. The site must be the LIVE site of the pair and must be a target of the token; the staging copy is found by the server (host staging.<main domain>), never named in the request. Body: scope (required) all|files|db|selected; tables (required with selected only, 1 to 1000 distinct names [A-Za-z0-9_]{1,64} that exist in the staging database); delete_missing_files (required, boolean; true only with scope all or files: files on live without a counterpart in staging are deleted); confirm_host (required): the exact host of the live site; confirm_data_loss (boolean, default false): must be true for scope all or db when WooCommerce is active on live (an unreadable plugin list counts as active); dry_run (boolean, default false). Nothing else is accepted. dry_run=true answers 200 and does nothing to the site: no job, no Idempotency-Key needed, no idempotency entry, no daily counter, no backup, no lock. Data: {dry_run, scope, delete_missing_files, pair:{staging_host, live_host}, woocommerce_active: true|false|null, tables: staging tables (at most 1000) or null, missing_tables (selected tables not in staging), backup_quota:{used, limit}|null, storage_ok: true|false|null, busy: null|operation_running|cockpit_busy, daily_limit_reached, staging_newer_than_live: null (not determined)}. A dry run reads synchronously on the server (instance list, table list, plugin list for WooCommerce, storage check), is limited only by the general request limit, and like every POST answers 503 api_draining while the API is drained for maintenance. In a dry run confirm_host, delete_missing_files and confirm_data_loss are optional and only informative. Otherwise queues one job (202 + Operation kind staging:push). It runs in the WP-Cockpit worker (see the delegation notes) under the shared site lock with a reservation, takes exactly one safety backup of the LIVE site first and copies only when that backup is confirmed with its exact file name, then clears the cache and runs a health check of the live site. Rejected up front without a job: 400 invalid_scope / invalid_arguments, 403 permission_denied, 404 staging_not_found, 409 staging_ambiguous, 422 no_live_instance (also: a staging site), confirmation_mismatch, woo_confirmation_missing, unknown_table, backup_limit_reached, backup_in_use, service_unavailable, 409 site_busy, 429 daily_limit (5 a day and account, shared with the panel), 502 tables_unreadable, 503 delegation_unavailable. Result {safety_backup:{filename, created_at}, health_check: ok|issue_found|not_run, scope, delete_missing_files}; present on failed and unknown operations where it applies (health_check only on success). succeeded needs the named safety backup and a health check answer; issue_found is still succeeded (the copy happened, the check found a problem; the safety backup is the way back). failed copy_failed: WP Toolkit reported the copy failed after the live site may have been partly changed; restore the safety backup. unknown (copy_outcome_unknown, effect_uncertain, backup_outcome_unknown, worker_lost, backend_timeout, backend_job_missing, unconfirmed_result): the outcome is unclear, check the live site; the site stays locked until Support settles it. unknown site_binding_changed: the copy was proven and a fresh read shows that the live installation identity changed, so the public site_id no longer matches it (only then); the site is NOT locked; check the site and request a new token if needed. unknown binding_unconfirmed: the copy was proven but the binding could not be read right afterwards; the site is NOT locked; check the site. A token revoked, rights changed or the API switched off while the copy ran leave the proven result succeeded. The staging instance is bound when the request is accepted: if the copy is deleted and recreated before the job runs, the operation fails with pair_changed before the safety backup and nothing is copied (operations accepted before this binding existed run without it). Failed before any change to live: confirmation_mismatch, woo_confirmation_missing, pair_changed, unknown_table, tables_unreadable, backup_limit_reached, safety_backup_failed, time_budget_exhausted, daily_limit, site_busy, service_unavailable, access_removed, token_inactive, api_unavailable, delegation_not_started, job_expired. Two codes report failed but leave the site LOCKED (nothing was copied to live): safety_backup_pending (the safety backup still runs; the site stays reserved until that task is settled) and backup_filename_unavailable (the backup was made but its exact file name could not be determined; the reservation stays unknown until Support releases it). There is no automatic rollback."
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiToken": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "tpapi_ token"
      }
    },
    "schemas": {
      "Meta": {
        "type": "object",
        "properties": {
          "request_id": {
            "type": "string"
          }
        },
        "required": [
          "request_id"
        ],
        "additionalProperties": false
      },
      "PageMeta": {
        "type": "object",
        "properties": {
          "request_id": {
            "type": "string"
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "request_id",
          "next_cursor"
        ],
        "additionalProperties": false
      },
      "Error": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string"
          },
          "message": {
            "type": "string"
          }
        },
        "required": [
          "code",
          "message"
        ],
        "additionalProperties": false
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "error": {
            "$ref": "#/components/schemas/Error"
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        },
        "required": [
          "error",
          "meta"
        ],
        "additionalProperties": false
      },
      "Site": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "domain": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "wordpress",
              "ai_launch"
            ]
          },
          "status": {
            "type": "string"
          },
          "capabilities": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "data_as_of": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "role": {
            "type": "string",
            "enum": [
              "live",
              "staging"
            ],
            "description": "'staging' if the site is the staging copy of a live site of the same hosting package. The only rule: the host is exactly staging.<main domain>, same package, with exactly one live site (root installation of the main domain) and its own folder. Everything not recognized (and every AI Launch site) is 'live'."
          },
          "staging_of": {
            "type": [
              "string",
              "null"
            ],
            "description": "Only for role 'staging': the id of its live site, if that site belongs to the token's targets; otherwise null. Always null for role 'live'."
          },
          "details": {
            "$ref": "#/components/schemas/SiteDetails",
            "description": "Only in GET /sites/{site_id}, never in the list GET /sites"
          }
        },
        "required": [
          "id",
          "domain",
          "type",
          "status",
          "capabilities",
          "data_as_of",
          "role",
          "staging_of"
        ],
        "additionalProperties": false
      },
      "Backup": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "filename": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "size_bytes": {
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "filename"
        ],
        "additionalProperties": false
      },
      "Operation": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "site_id": {
            "type": "string"
          },
          "kind": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "running",
              "succeeded",
              "failed",
              "unknown"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "result": {
            "type": [
              "object",
              "null"
            ],
            "description": "Result of an operation, present on succeeded and, where documented, also on failed and unknown operations. backups:delete: {filename, remaining_backups, deletion_verified}. updates:run: {safety_backup, items:[{type, slug, from, to, status}]}. staging:delete: {staging_host, deleted, subdomain_removed}. backups:restore: {safety_backup, scope, restore_task (full) | health_check (partial)}. updates:core: {safety_backup, from, to}. plugins:manage: {slug, enabled, changed}. staging:create: {staging_host, ssl, staging_site_id}. staging:push: {safety_backup:{filename, created_at}, health_check, scope, delete_missing_files}."
          },
          "error_code": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "site_id",
          "kind",
          "status",
          "created_at",
          "updated_at"
        ],
        "additionalProperties": false
      },
      "Deployment": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "site_id": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "published_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "site_id",
          "status",
          "created_at"
        ],
        "additionalProperties": false
      },
      "SiteResponse": {
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Site"
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "additionalProperties": false
      },
      "SiteListResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Site"
            }
          },
          "meta": {
            "$ref": "#/components/schemas/PageMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "additionalProperties": false
      },
      "BackupListResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Backup"
            }
          },
          "meta": {
            "$ref": "#/components/schemas/PageMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "additionalProperties": false
      },
      "OperationResponse": {
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Operation"
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "additionalProperties": false
      },
      "DeploymentResponse": {
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Deployment"
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "additionalProperties": false
      },
      "DeploymentListResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Deployment"
            }
          },
          "meta": {
            "$ref": "#/components/schemas/PageMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "additionalProperties": false
      },
      "CachePurgeRequest": {
        "type": "object",
        "properties": {
          "scope": {
            "type": "string",
            "enum": [
              "page",
              "object",
              "all"
            ]
          }
        },
        "required": [
          "scope"
        ],
        "additionalProperties": false
      },
      "DeploymentFileRequest": {
        "type": "object",
        "properties": {
          "path": {
            "type": "string"
          },
          "content": {
            "type": "string"
          },
          "encoding": {
            "type": "string",
            "enum": [
              "utf8",
              "base64"
            ],
            "default": "utf8"
          }
        },
        "required": [
          "path",
          "content"
        ],
        "additionalProperties": false
      },
      "DeploymentFileResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "path": {
                "type": "string"
              },
              "size_bytes": {
                "type": "integer",
                "minimum": 0
              }
            },
            "required": [
              "path",
              "size_bytes"
            ],
            "additionalProperties": false
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "additionalProperties": false
      },
      "DeploymentPreviewResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "valid": {
                "type": "boolean"
              },
              "issues": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "preview_url": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "uri"
              }
            },
            "required": [
              "valid",
              "issues"
            ],
            "additionalProperties": false
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "additionalProperties": false
      },
      "OperationListResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Operation"
            }
          },
          "meta": {
            "$ref": "#/components/schemas/PageMeta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "additionalProperties": false
      },
      "TokenInfo": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "permissions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "targets": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Site IDs"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "null = unlimited"
          },
          "last_used_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "name",
          "permissions",
          "targets",
          "created_at",
          "expires_at",
          "last_used_at"
        ],
        "additionalProperties": false
      },
      "TokenInfoResponse": {
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/TokenInfo"
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "additionalProperties": false
      },
      "Status": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "ok",
              "draining"
            ]
          },
          "api": {
            "type": "string",
            "enum": [
              "v1"
            ]
          }
        },
        "required": [
          "status",
          "api"
        ],
        "additionalProperties": false
      },
      "StatusResponse": {
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Status"
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "additionalProperties": false
      },
      "SiteDetails": {
        "type": "object",
        "description": "Read-only extras taken from the hosting inventory that is already read for the request. Only values available without extra backend calls are offered.",
        "properties": {
          "wordpress_version": {
            "type": [
              "string",
              "null"
            ],
            "description": "Installed WordPress version; null if unknown and always null for AI Launch sites"
          }
        },
        "required": [
          "wordpress_version"
        ],
        "additionalProperties": false
      },
      "UpdateItem": {
        "type": "object",
        "description": "A plugin or theme with an open update. name and versions come from third-party code and are sanitized.",
        "properties": {
          "slug": {
            "type": "string",
            "description": "Slug as used for the update request"
          },
          "name": {
            "type": "string"
          },
          "current": {
            "type": "string"
          },
          "available": {
            "type": "string"
          }
        },
        "required": [
          "slug",
          "name",
          "current",
          "available"
        ],
        "additionalProperties": false
      },
      "Updates": {
        "type": "object",
        "properties": {
          "core": {
            "type": "object",
            "properties": {
              "current": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "available": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "current",
              "available"
            ],
            "additionalProperties": false
          },
          "plugins": {
            "type": "array",
            "maxItems": 200,
            "items": {
              "$ref": "#/components/schemas/UpdateItem"
            }
          },
          "themes": {
            "type": "array",
            "maxItems": 200,
            "items": {
              "$ref": "#/components/schemas/UpdateItem"
            }
          },
          "checked_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the state was read (UTC)"
          }
        },
        "required": [
          "core",
          "plugins",
          "themes",
          "checked_at"
        ],
        "additionalProperties": false
      },
      "UpdatesResponse": {
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Updates"
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "additionalProperties": false
      },
      "UpdatesRunRequest": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "minItems": 1,
            "maxItems": 5,
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string",
                  "enum": [
                    "plugin",
                    "theme"
                  ]
                },
                "slug": {
                  "type": "string",
                  "pattern": "^[a-z0-9][a-z0-9-]{0,61}$"
                }
              },
              "required": [
                "type",
                "slug"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "items"
        ],
        "additionalProperties": false
      },
      "BackupRestoreRequest": {
        "type": "object",
        "properties": {
          "scope": {
            "type": "string",
            "enum": [
              "full",
              "database",
              "files",
              "folder"
            ]
          },
          "folder": {
            "type": "string",
            "pattern": "^wp-content/(uploads|(plugins|themes)/[a-z0-9-]{1,100})$",
            "description": "Only with scope folder"
          },
          "confirm_host": {
            "type": "string",
            "description": "The exact host of the site that is restored (case-insensitive)"
          },
          "confirm_data_loss": {
            "type": "boolean",
            "default": false,
            "description": "Must be true for scope full or database when WooCommerce is active on the site"
          }
        },
        "required": [
          "scope",
          "confirm_host"
        ],
        "additionalProperties": false
      },
      "CoreUpdateRequest": {
        "type": "object",
        "properties": {
          "expected_version": {
            "type": "string",
            "pattern": "^\\d+(\\.\\d+){1,3}(-[A-Za-z0-9.]{1,20})?$",
            "description": "Refuse (409 version_changed) when another core version is offered"
          }
        },
        "additionalProperties": false
      },
      "PluginStateRequest": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean"
          }
        },
        "required": [
          "enabled"
        ],
        "additionalProperties": false
      },
      "EmptyRequest": {
        "type": "object",
        "additionalProperties": false
      },
      "StagingPushRequest": {
        "type": "object",
        "properties": {
          "scope": {
            "type": "string",
            "enum": [
              "all",
              "files",
              "db",
              "selected"
            ]
          },
          "tables": {
            "type": "array",
            "minItems": 1,
            "maxItems": 1000,
            "uniqueItems": true,
            "items": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_]{1,64}$"
            },
            "description": "Only with scope selected"
          },
          "delete_missing_files": {
            "type": "boolean",
            "description": "Required. True only with scope all or files"
          },
          "confirm_host": {
            "type": "string",
            "description": "Required. The exact host of the live site (case-insensitive)"
          },
          "confirm_data_loss": {
            "type": "boolean",
            "default": false,
            "description": "Must be true for scope all or db when WooCommerce is active on the live site"
          },
          "dry_run": {
            "type": "boolean",
            "default": false
          }
        },
        "required": [
          "scope"
        ],
        "additionalProperties": false
      },
      "StagingPushDryRun": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "dry_run",
          "scope",
          "delete_missing_files",
          "pair",
          "woocommerce_active",
          "tables",
          "missing_tables",
          "backup_quota",
          "storage_ok",
          "busy",
          "daily_limit_reached",
          "staging_newer_than_live"
        ],
        "properties": {
          "dry_run": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "scope": {
            "type": "string",
            "enum": [
              "all",
              "files",
              "db",
              "selected"
            ]
          },
          "delete_missing_files": {
            "type": "boolean"
          },
          "pair": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "staging_host",
              "live_host"
            ],
            "properties": {
              "staging_host": {
                "type": "string"
              },
              "live_host": {
                "type": "string"
              }
            }
          },
          "woocommerce_active": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "tables": {
            "type": [
              "array",
              "null"
            ],
            "maxItems": 1000,
            "items": {
              "type": "string"
            }
          },
          "missing_tables": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "backup_quota": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": false,
            "properties": {
              "used": {
                "type": "integer"
              },
              "limit": {
                "type": "integer"
              }
            }
          },
          "storage_ok": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "busy": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "operation_running",
              "cockpit_busy",
              null
            ]
          },
          "daily_limit_reached": {
            "type": "boolean"
          },
          "staging_newer_than_live": {
            "type": "null",
            "description": "Not determined; always null."
          }
        }
      },
      "StagingPushDryRunResponse": {
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/StagingPushDryRun"
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        },
        "required": [
          "data",
          "meta"
        ],
        "additionalProperties": false
      }
    },
    "headers": {
      "RateLimitLimit": {
        "description": "Requests allowed per minute for the account (currently 60). Sent on every answer after authentication.",
        "schema": {
          "type": "integer",
          "example": 60
        }
      },
      "RateLimitRemaining": {
        "description": "Requests left in the current one-minute window of the account; 0 once the limit is reached.",
        "schema": {
          "type": "integer",
          "minimum": 0,
          "maximum": 60
        }
      },
      "RateLimitReset": {
        "description": "Unix time (seconds) at which the current one-minute window ends and the count starts again.",
        "schema": {
          "type": "integer"
        }
      }
    }
  }
}
