{
  "openapi": "3.1.0",
  "info": {
    "title": "BudgetHost Deployment API",
    "version": "1.0.0",
    "description": "Customer service and slice APIs. Use a service token for application configuration and deployment, or a slice token for provisioning. Tokens expire after 90 days by default. Rollback restores an image only."
  },
  "servers": [
    {
      "url": "https://api.budgethost.io"
    }
  ],
  "security": [
    {
      "serviceToken": []
    }
  ],
  "paths": {
    "/v1/deploy/services/{serviceId}": {
      "parameters": [
        {
          "name": "serviceId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "deploymentCapabilities",
        "description": "",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "api_version": {
                      "type": "string"
                    },
                    "request_id": {
                      "type": "string"
                    },
                    "correlation_id": {
                      "type": "string"
                    },
                    "data": {
                      "$ref": "#/components/schemas/Capabilities"
                    },
                    "error": {
                      "anyOf": [
                        {
                          "$ref": "#/components/schemas/Error"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": {
            "description": "Structured error; 400 invalid input, 401 invalid token, 403 forbidden, 404 not found/disabled, 409 conflict, 413 too large, 415 media type, 507 quota",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "api_version": {
                      "type": "string"
                    },
                    "request_id": {
                      "type": "string"
                    },
                    "correlation_id": {
                      "type": "string"
                    },
                    "data": {
                      "type": "null"
                    },
                    "error": {
                      "anyOf": [
                        {
                          "$ref": "#/components/schemas/Error"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "serviceToken": []
          }
        ],
        "tags": [
          "Deployments"
        ]
      }
    },
    "/v1/deploy/services/{serviceId}/deployments": {
      "parameters": [
        {
          "name": "serviceId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "listDeployments",
        "description": "",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "api_version": {
                      "type": "string"
                    },
                    "request_id": {
                      "type": "string"
                    },
                    "correlation_id": {
                      "type": "string"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Deployment"
                      }
                    },
                    "error": {
                      "anyOf": [
                        {
                          "$ref": "#/components/schemas/Error"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": {
            "description": "Structured error; 400 invalid input, 401 invalid token, 403 forbidden, 404 not found/disabled, 409 conflict, 413 too large, 415 media type, 507 quota",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "api_version": {
                      "type": "string"
                    },
                    "request_id": {
                      "type": "string"
                    },
                    "correlation_id": {
                      "type": "string"
                    },
                    "data": {
                      "type": "null"
                    },
                    "error": {
                      "anyOf": [
                        {
                          "$ref": "#/components/schemas/Error"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "serviceToken": []
          }
        ],
        "tags": [
          "Deployments"
        ]
      },
      "post": {
        "operationId": "createDeployment",
        "description": "Retry with the same token, key and input to recover the same ID.",
        "parameters": [
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "api_version": {
                      "type": "string"
                    },
                    "request_id": {
                      "type": "string"
                    },
                    "correlation_id": {
                      "type": "string"
                    },
                    "data": {
                      "$ref": "#/components/schemas/Deployment"
                    },
                    "error": {
                      "anyOf": [
                        {
                          "$ref": "#/components/schemas/Error"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": {
            "description": "Structured error; 400 invalid input, 401 invalid token, 403 forbidden, 404 not found/disabled, 409 conflict, 413 too large, 415 media type, 507 quota",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "api_version": {
                      "type": "string"
                    },
                    "request_id": {
                      "type": "string"
                    },
                    "correlation_id": {
                      "type": "string"
                    },
                    "data": {
                      "type": "null"
                    },
                    "error": {
                      "anyOf": [
                        {
                          "$ref": "#/components/schemas/Error"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Input"
              }
            }
          }
        },
        "security": [
          {
            "serviceToken": []
          }
        ],
        "tags": [
          "Deployments"
        ]
      }
    },
    "/v1/deploy/services/{serviceId}/deployments/{id}": {
      "parameters": [
        {
          "name": "serviceId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^dd-[a-f0-9]{64}$"
          }
        }
      ],
      "get": {
        "operationId": "getDeployment",
        "description": "",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "api_version": {
                      "type": "string"
                    },
                    "request_id": {
                      "type": "string"
                    },
                    "correlation_id": {
                      "type": "string"
                    },
                    "data": {
                      "$ref": "#/components/schemas/Deployment"
                    },
                    "error": {
                      "anyOf": [
                        {
                          "$ref": "#/components/schemas/Error"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": {
            "description": "Structured error; 400 invalid input, 401 invalid token, 403 forbidden, 404 not found/disabled, 409 conflict, 413 too large, 415 media type, 507 quota",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "api_version": {
                      "type": "string"
                    },
                    "request_id": {
                      "type": "string"
                    },
                    "correlation_id": {
                      "type": "string"
                    },
                    "data": {
                      "type": "null"
                    },
                    "error": {
                      "anyOf": [
                        {
                          "$ref": "#/components/schemas/Error"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "serviceToken": []
          }
        ],
        "tags": [
          "Deployments"
        ]
      }
    },
    "/v1/deploy/services/{serviceId}/deployments/{id}/start": {
      "parameters": [
        {
          "name": "serviceId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^dd-[a-f0-9]{64}$"
          }
        }
      ],
      "post": {
        "operationId": "startDeployment",
        "description": "Asynchronous; poll the deployment until succeeded or failed. Retry using the original start key.",
        "parameters": [
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "api_version": {
                      "type": "string"
                    },
                    "request_id": {
                      "type": "string"
                    },
                    "correlation_id": {
                      "type": "string"
                    },
                    "data": {
                      "$ref": "#/components/schemas/Deployment"
                    },
                    "error": {
                      "anyOf": [
                        {
                          "$ref": "#/components/schemas/Error"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": {
            "description": "Structured error; 400 invalid input, 401 invalid token, 403 forbidden, 404 not found/disabled, 409 conflict, 413 too large, 415 media type, 507 quota",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "api_version": {
                      "type": "string"
                    },
                    "request_id": {
                      "type": "string"
                    },
                    "correlation_id": {
                      "type": "string"
                    },
                    "data": {
                      "type": "null"
                    },
                    "error": {
                      "anyOf": [
                        {
                          "$ref": "#/components/schemas/Error"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false
              }
            }
          }
        },
        "security": [
          {
            "serviceToken": []
          }
        ],
        "tags": [
          "Deployments"
        ]
      }
    },
    "/v1/deploy/services/{serviceId}/deployments/{id}/logs": {
      "parameters": [
        {
          "name": "serviceId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^dd-[a-f0-9]{64}$"
          }
        }
      ],
      "get": {
        "operationId": "deploymentLogs",
        "description": "",
        "parameters": [
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "api_version": {
                      "type": "string"
                    },
                    "request_id": {
                      "type": "string"
                    },
                    "correlation_id": {
                      "type": "string"
                    },
                    "data": {
                      "$ref": "#/components/schemas/Logs"
                    },
                    "error": {
                      "anyOf": [
                        {
                          "$ref": "#/components/schemas/Error"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": {
            "description": "Structured error; 400 invalid input, 401 invalid token, 403 forbidden, 404 not found/disabled, 409 conflict, 413 too large, 415 media type, 507 quota",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "api_version": {
                      "type": "string"
                    },
                    "request_id": {
                      "type": "string"
                    },
                    "correlation_id": {
                      "type": "string"
                    },
                    "data": {
                      "type": "null"
                    },
                    "error": {
                      "anyOf": [
                        {
                          "$ref": "#/components/schemas/Error"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "serviceToken": []
          }
        ],
        "tags": [
          "Deployments"
        ]
      }
    },
    "/v1/deploy/services/{serviceId}/deployments/{id}/artifact": {
      "parameters": [
        {
          "name": "serviceId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^dd-[a-f0-9]{64}$"
          }
        }
      ],
      "put": {
        "operationId": "uploadDeploymentArtifact",
        "description": "Stream exactly the declared bytes. SHA-256 must match. Retry from byte zero before start.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "api_version": {
                      "type": "string"
                    },
                    "request_id": {
                      "type": "string"
                    },
                    "correlation_id": {
                      "type": "string"
                    },
                    "data": {
                      "$ref": "#/components/schemas/Deployment"
                    },
                    "error": {
                      "anyOf": [
                        {
                          "$ref": "#/components/schemas/Error"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": {
            "description": "Structured error; 400 invalid input, 401 invalid token, 403 forbidden, 404 not found/disabled, 409 conflict, 413 too large, 415 media type, 507 quota",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "api_version": {
                      "type": "string"
                    },
                    "request_id": {
                      "type": "string"
                    },
                    "correlation_id": {
                      "type": "string"
                    },
                    "data": {
                      "type": "null"
                    },
                    "error": {
                      "anyOf": [
                        {
                          "$ref": "#/components/schemas/Error"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/octet-stream": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            }
          }
        },
        "security": [
          {
            "serviceToken": []
          }
        ],
        "tags": [
          "Deployments"
        ]
      }
    },
    "/v1/deploy/services/{serviceId}/configuration/preview": {
      "parameters": [
        {
          "name": "serviceId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "previewServiceConfiguration",
        "security": [
          {
            "serviceToken": []
          }
        ],
        "description": "Service-scoped configuration using only assigned resources. Apply requires a current review_id and saves desired state without restarting.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConfigurationPreviewRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Configuration preview",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ConfigurationReview"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid configuration or binding"
          },
          "401": {
            "description": "Authentication required"
          },
          "403": {
            "description": "Resource is not assigned to this service"
          },
          "404": {
            "description": "Service or binding not found"
          },
          "409": {
            "description": "Stale review, unsupported template, or active operation"
          },
          "422": {
            "description": "Required configuration missing"
          }
        },
        "tags": [
          "Application configuration"
        ]
      }
    },
    "/v1/deploy/services/{serviceId}/configuration/apply": {
      "parameters": [
        {
          "name": "serviceId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "applyServiceConfiguration",
        "security": [
          {
            "serviceToken": []
          }
        ],
        "description": "Service-scoped configuration using only assigned resources. Apply requires a current review_id and saves desired state without restarting.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConfigurationApplyRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Configuration apply",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ConfigurationSaved"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid configuration or binding"
          },
          "401": {
            "description": "Authentication required"
          },
          "403": {
            "description": "Resource is not assigned to this service"
          },
          "404": {
            "description": "Service or binding not found"
          },
          "409": {
            "description": "Stale review, unsupported template, or active operation"
          },
          "422": {
            "description": "Required configuration missing"
          }
        },
        "tags": [
          "Application configuration"
        ]
      }
    },
    "/v1/deploy/services/{serviceId}/configuration": {
      "parameters": [
        {
          "name": "serviceId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getServiceConfiguration",
        "security": [
          {
            "serviceToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Service-scoped configuration; environment and secret values are omitted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "service_id": {
                          "type": "string"
                        },
                        "revision": {
                          "type": "string"
                        },
                        "port": {
                          "type": "integer"
                        },
                        "storage": {
                          "type": "array",
                          "items": {
                            "type": "object"
                          }
                        },
                        "environment": {
                          "type": "array",
                          "items": {
                            "type": "object"
                          }
                        },
                        "routes": {
                          "type": "array",
                          "items": {
                            "type": "object"
                          }
                        },
                        "urls": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "resource_limits": {
                          "type": "object"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Invalid, expired or revoked service token"
          }
        },
        "tags": [
          "Application configuration"
        ]
      }
    },
    "/v1/deploy/services/{serviceId}/configuration/secrets/{name}": {
      "parameters": [
        {
          "name": "serviceId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "name",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "put": {
        "operationId": "putServiceConfigurationSecret",
        "security": [
          {
            "serviceToken": []
          }
        ],
        "description": "Write-only, repeatable secret update scoped to this service and environment name. Returns secret_id for bindings.secret_refs. Reserved environment names are rejected.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "value"
                ],
                "properties": {
                  "value": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 8192,
                    "writeOnly": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved; value is never returned",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "service_id": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        },
                        "secret_id": {
                          "type": "string"
                        },
                        "saved": {
                          "type": "boolean"
                        },
                        "runtime_changed": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Invalid, expired or revoked service token"
          },
          "409": {
            "description": "An active deployment or lifecycle operation blocks changes"
          }
        },
        "tags": [
          "Application configuration"
        ]
      }
    },
    "/v1/deploy/slices/{sliceId}": {
      "get": {
        "summary": "Inspect allocation, members and combined storage usage",
        "parameters": [
          {
            "name": "sliceId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Result envelope; apply returns queued work, not runtime success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input"
          },
          "401": {
            "description": "Invalid, expired or revoked token"
          },
          "403": {
            "description": "Scope denied"
          },
          "404": {
            "description": "Not found"
          },
          "409": {
            "description": "Conflict or incomplete operation; inspect operation before reconciliation"
          }
        },
        "security": [
          {
            "sliceToken": []
          }
        ],
        "tags": [
          "Service slices"
        ],
        "operationId": "get__v1_deploy_slices_sliceId_"
      }
    },
    "/v1/deploy/slices/{sliceId}/services": {
      "post": {
        "summary": "Configure application or WordPress family",
        "parameters": [
          {
            "name": "sliceId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9_.:-]+$"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Result envelope; apply returns queued work, not runtime success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input"
          },
          "401": {
            "description": "Invalid, expired or revoked token"
          },
          "403": {
            "description": "Scope denied"
          },
          "404": {
            "description": "Not found"
          },
          "409": {
            "description": "Conflict or incomplete operation; inspect operation before reconciliation"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "type": {
                    "type": "string",
                    "enum": [
                      "application",
                      "wordpress"
                    ]
                  },
                  "display_name": {
                    "type": "string"
                  }
                },
                "required": [
                  "type",
                  "display_name"
                ]
              }
            }
          }
        },
        "security": [
          {
            "sliceToken": []
          }
        ],
        "tags": [
          "Service slices"
        ],
        "operationId": "post__v1_deploy_slices_sliceId_services"
      }
    },
    "/v1/deploy/slices/{sliceId}/storage": {
      "post": {
        "summary": "Create storage and optionally attach it",
        "parameters": [
          {
            "name": "sliceId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9_.:-]+$"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Result envelope; apply returns queued work, not runtime success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input"
          },
          "401": {
            "description": "Invalid, expired or revoked token"
          },
          "403": {
            "description": "Scope denied"
          },
          "404": {
            "description": "Not found"
          },
          "409": {
            "description": "Conflict or incomplete operation; inspect operation before reconciliation"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "service_id": {
                    "type": "string"
                  },
                  "mount_path": {
                    "type": "string"
                  },
                  "compose_service_name": {
                    "type": "string"
                  }
                },
                "required": [
                  "name"
                ]
              }
            }
          }
        },
        "security": [
          {
            "sliceToken": []
          }
        ],
        "tags": [
          "Service slices"
        ],
        "operationId": "post__v1_deploy_slices_sliceId_storage"
      }
    },
    "/v1/deploy/slices/{sliceId}/storage/attach": {
      "post": {
        "summary": "Attach slice-owned storage",
        "parameters": [
          {
            "name": "sliceId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9_.:-]+$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Result envelope; apply returns queued work, not runtime success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input"
          },
          "401": {
            "description": "Invalid, expired or revoked token"
          },
          "403": {
            "description": "Scope denied"
          },
          "404": {
            "description": "Not found"
          },
          "409": {
            "description": "Conflict or incomplete operation; inspect operation before reconciliation"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "service_id": {
                    "type": "string"
                  },
                  "mount_path": {
                    "type": "string"
                  },
                  "compose_service_name": {
                    "type": "string"
                  },
                  "storage_id": {
                    "type": "string"
                  }
                },
                "required": [
                  "storage_id",
                  "service_id",
                  "mount_path"
                ]
              }
            }
          }
        },
        "security": [
          {
            "sliceToken": []
          }
        ],
        "tags": [
          "Service slices"
        ],
        "operationId": "post__v1_deploy_slices_sliceId_storage_attach"
      }
    },
    "/v1/deploy/slices/{sliceId}/services/{serviceId}/apply": {
      "post": {
        "summary": "Queue preflight and deployment for one bundle family",
        "parameters": [
          {
            "name": "sliceId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9_.:-]+$"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Result envelope; apply returns queued work, not runtime success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input"
          },
          "401": {
            "description": "Invalid, expired or revoked token"
          },
          "403": {
            "description": "Scope denied"
          },
          "404": {
            "description": "Not found"
          },
          "409": {
            "description": "Conflict or incomplete operation; inspect operation before reconciliation"
          }
        },
        "security": [
          {
            "sliceToken": []
          }
        ],
        "tags": [
          "Service slices"
        ],
        "operationId": "post__v1_deploy_slices_sliceId_services_serviceId_apply"
      }
    },
    "/v1/deploy/slices/{sliceId}/services/{serviceId}/deployment-tokens": {
      "post": {
        "summary": "Issue a separate service token, shown once",
        "parameters": [
          {
            "name": "sliceId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Result envelope; apply returns queued work, not runtime success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input"
          },
          "401": {
            "description": "Invalid, expired or revoked token"
          },
          "403": {
            "description": "Scope denied"
          },
          "404": {
            "description": "Not found"
          },
          "409": {
            "description": "Conflict or incomplete operation; inspect operation before reconciliation"
          }
        },
        "security": [
          {
            "sliceToken": []
          }
        ],
        "tags": [
          "Service slices"
        ],
        "operationId": "post__v1_deploy_slices_sliceId_services_serviceId_deployment_tokens"
      }
    },
    "/v1/deploy/slices/{sliceId}/operations/{operationId}": {
      "get": {
        "summary": "Inspect provisioning operation",
        "parameters": [
          {
            "name": "sliceId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "operationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Result envelope; apply returns queued work, not runtime success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input"
          },
          "401": {
            "description": "Invalid, expired or revoked token"
          },
          "403": {
            "description": "Scope denied"
          },
          "404": {
            "description": "Not found"
          },
          "409": {
            "description": "Conflict or incomplete operation; inspect operation before reconciliation"
          }
        },
        "security": [
          {
            "sliceToken": []
          }
        ],
        "tags": [
          "Service slices"
        ],
        "operationId": "get__v1_deploy_slices_sliceId_operations_operationId_"
      }
    },
    "/v1/deploy/services/{serviceId}/storage": {
      "post": {
        "summary": "Create storage attached only to the service authorized by its deployment token",
        "parameters": [
          {
            "name": "serviceId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9_.:-]+$"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Result envelope; apply returns queued work, not runtime success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Envelope"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input"
          },
          "401": {
            "description": "Invalid, expired or revoked token"
          },
          "403": {
            "description": "Scope denied"
          },
          "404": {
            "description": "Not found"
          },
          "409": {
            "description": "Conflict or incomplete operation; inspect operation before reconciliation"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "service_id": {
                    "type": "string"
                  },
                  "mount_path": {
                    "type": "string"
                  },
                  "compose_service_name": {
                    "type": "string"
                  }
                },
                "required": [
                  "name",
                  "mount_path"
                ]
              }
            }
          }
        },
        "security": [
          {
            "serviceToken": []
          }
        ],
        "tags": [
          "Persistent storage"
        ],
        "operationId": "post__v1_deploy_services_serviceId_storage"
      }
    }
  },
  "components": {
    "securitySchemes": {
      "serviceToken": {
        "type": "http",
        "scheme": "bearer",
        "description": "Token bound to one application and tenant."
      },
      "sliceToken": {
        "type": "http",
        "scheme": "bearer",
        "description": "Token bound to one slice and tenant; can provision members and issue service tokens."
      }
    },
    "schemas": {
      "Input": {
        "oneOf": [
          {
            "type": "object",
            "required": [
              "type",
              "bytes",
              "sha256"
            ],
            "additionalProperties": false,
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "source",
                  "image"
                ]
              },
              "bytes": {
                "type": "integer",
                "minimum": 1,
                "maximum": 2147483648
              },
              "sha256": {
                "type": "string",
                "pattern": "^[a-f0-9]{64}$"
              }
            }
          },
          {
            "type": "object",
            "required": [
              "type",
              "deployment_id"
            ],
            "additionalProperties": false,
            "properties": {
              "type": {
                "const": "redeploy"
              },
              "deployment_id": {
                "type": "string",
                "pattern": "^dd-[a-f0-9]{64}$"
              }
            }
          }
        ]
      },
      "Deployment": {
        "type": "object",
        "required": [
          "id",
          "service_id",
          "input",
          "status"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "service_id": {
            "type": "string"
          },
          "input": {
            "$ref": "#/components/schemas/Input"
          },
          "status": {
            "type": "string",
            "enum": [
              "awaiting_upload",
              "ready",
              "queued",
              "building",
              "importing",
              "deploying",
              "verifying",
              "succeeded",
              "failed"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "image_digest": {
            "type": [
              "string",
              "null"
            ],
            "description": "Immutable repository@sha256:digest reference"
          },
          "health": {
            "type": [
              "object",
              "null"
            ]
          },
          "failure": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Error"
              },
              {
                "type": "null"
              }
            ]
          },
          "retained": {
            "type": "boolean"
          },
          "work_order_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "details": {
            "type": "object"
          },
          "deployment_id": {
            "type": "string"
          },
          "stage": {
            "type": "string"
          },
          "work_order_id": {
            "type": "string"
          }
        }
      },
      "Token": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "service_id": {
            "type": "string"
          },
          "tenant_id": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "revoked_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "Capabilities": {
        "type": "object",
        "properties": {
          "service_id": {
            "type": "string"
          },
          "ready": {
            "type": "boolean"
          },
          "platform": {
            "type": "string"
          },
          "supported_inputs": {
            "type": "array",
            "items": {
              "enum": [
                "source",
                "image",
                "redeploy"
              ]
            }
          },
          "limits": {
            "type": "object",
            "properties": {
              "source_bytes": {
                "type": "integer",
                "minimum": 1
              },
              "image_bytes": {
                "type": "integer",
                "minimum": 1
              },
              "extracted_bytes": {
                "type": "integer",
                "minimum": 1
              },
              "source_entries": {
                "type": "integer",
                "minimum": 1
              },
              "preparation_timeout_ms": {
                "type": "integer",
                "minimum": 1
              }
            }
          }
        }
      },
      "Logs": {
        "type": "object",
        "properties": {
          "entries": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "cursor": {
                  "type": "integer"
                },
                "at": {
                  "type": "string",
                  "format": "date-time"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          },
          "next_cursor": {
            "type": "integer"
          }
        }
      },
      "ProjectManifest": {
        "title": "BudgetHost project configuration",
        "type": "object",
        "additionalProperties": false,
        "required": [
          "version"
        ],
        "properties": {
          "version": {
            "const": 1
          },
          "port": {
            "type": "integer",
            "minimum": 1,
            "maximum": 65535
          },
          "readiness": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "path"
            ],
            "properties": {
              "path": {
                "type": "string",
                "maxLength": 2048,
                "pattern": "^/(?!/)[^\\s?#\\\\]*$"
              }
            }
          },
          "environment": {
            "type": "object",
            "maxProperties": 128,
            "propertyNames": {
              "pattern": "^(?!(?:__proto__|constructor|prototype)$)[a-zA-Z_][a-zA-Z0-9_]{0,127}$",
              "description": "Platform-reserved environment names are rejected by the server."
            },
            "additionalProperties": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "required": {
                  "type": "boolean"
                },
                "secret": {
                  "type": "boolean"
                },
                "default": {
                  "type": "string",
                  "maxLength": 8192
                }
              },
              "if": {
                "required": [
                  "secret"
                ],
                "properties": {
                  "secret": {
                    "const": true
                  }
                }
              },
              "then": {
                "not": {
                  "required": [
                    "default"
                  ]
                }
              }
            }
          },
          "storage": {
            "type": "array",
            "maxItems": 16,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "name",
                "mount_path"
              ],
              "properties": {
                "name": {
                  "type": "string",
                  "pattern": "^[a-z][a-z0-9-]{0,63}$"
                },
                "mount_path": {
                  "type": "string",
                  "description": "Unique absolute normalized path, excluding system paths; validated by server.",
                  "pattern": "^/[a-zA-Z0-9_./-]+$"
                }
              }
            }
          }
        }
      },
      "ConfigurationPreviewRequest": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "dockerfile": {
            "type": "string",
            "description": "At most 64 KiB of Dockerfile text; only literal final-stage EXPOSE is inspected."
          },
          "manifest": {
            "$ref": "#/components/schemas/ProjectManifest"
          },
          "bindings": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "environment": {
                "type": "object",
                "additionalProperties": {
                  "type": "string",
                  "maxLength": 8192
                }
              },
              "secret_refs": {
                "type": "object",
                "additionalProperties": {
                  "type": "string",
                  "minLength": 1
                }
              },
              "storage": {
                "type": "object",
                "additionalProperties": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "storage_id",
                    "path_key"
                  ],
                  "properties": {
                    "storage_id": {
                      "type": "string",
                      "minLength": 1
                    },
                    "path_key": {
                      "type": "string",
                      "minLength": 1
                    }
                  }
                }
              }
            }
          }
        }
      },
      "ConfigurationApplyRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "review_id"
        ],
        "properties": {
          "dockerfile": {
            "type": "string",
            "description": "At most 64 KiB of Dockerfile text; only literal final-stage EXPOSE is inspected."
          },
          "manifest": {
            "$ref": "#/components/schemas/ProjectManifest"
          },
          "bindings": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "environment": {
                "type": "object",
                "additionalProperties": {
                  "type": "string",
                  "maxLength": 8192
                }
              },
              "secret_refs": {
                "type": "object",
                "additionalProperties": {
                  "type": "string",
                  "minLength": 1
                }
              },
              "storage": {
                "type": "object",
                "additionalProperties": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "storage_id",
                    "path_key"
                  ],
                  "properties": {
                    "storage_id": {
                      "type": "string",
                      "minLength": 1
                    },
                    "path_key": {
                      "type": "string",
                      "minLength": 1
                    }
                  }
                }
              }
            }
          },
          "review_id": {
            "type": "string",
            "pattern": "^[a-f0-9]{64}$"
          }
        }
      },
      "ConfigurationReview": {
        "type": "object",
        "required": [
          "review_id",
          "can_apply",
          "changes",
          "missing",
          "warnings"
        ],
        "properties": {
          "review_id": {
            "type": "string"
          },
          "can_apply": {
            "type": "boolean"
          },
          "changes": {
            "type": "array",
            "items": {
              "type": "object",
              "description": "Safe setting descriptions; existing environment values are omitted."
            }
          },
          "missing": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "ConfigurationSaved": {
        "type": "object",
        "required": [
          "service_id",
          "saved",
          "runtime_changed"
        ],
        "properties": {
          "service_id": {
            "type": "string"
          },
          "saved": {
            "const": true
          },
          "runtime_changed": {
            "const": false
          }
        }
      },
      "Envelope": {
        "type": "object",
        "properties": {
          "data": {},
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "details": {
                "type": "object"
              }
            }
          }
        }
      }
    }
  }
}
