{
  "openapi": "3.1.0",
  "info": {
    "title": "Auto Deploy API",
    "version": "1.0.0",
    "description": "Publish ZIP archives containing static websites. Sign in on the management site and generate a personal Agent token. See /docs/agent.md for optional review before packaging."
  },
  "servers": [
    {
      "url": "https://deploy.sites.tzxys.cn"
    }
  ],
  "security": [
    {
      "agentToken": []
    }
  ],
  "components": {
    "securitySchemes": {
      "agentToken": {
        "type": "http",
        "scheme": "bearer",
        "description": "Personal Agent token generated in the signed-in dashboard."
      }
    },
    "parameters": {
      "ProjectId": {
        "name": "id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "integer"
        }
      },
      "DomainProjectId": {
        "name": "projectId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "integer"
        }
      },
      "DomainId": {
        "name": "id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "integer"
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid input",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing or invalid user session or Agent token",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "Project or domain not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Conflict": {
        "description": "Domain is already attached or state changed",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "TooLarge": {
        "description": "Archive exceeds a size or file-count limit",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string"
          }
        }
      },
      "Deployment": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "projectId": {
            "type": "integer"
          },
          "deployKey": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CustomDomain": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "domain": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "active",
              "failed",
              "removing"
            ]
          },
          "lastError": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "Project": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "status": {
            "type": "string"
          },
          "deploymentCount": {
            "type": "integer"
          },
          "latestDeployment": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Deployment"
              },
              {
                "type": "null"
              }
            ]
          },
          "customDomains": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CustomDomain"
            }
          },
          "visibility": {
            "type": "string",
            "enum": [
              "private",
              "public"
            ],
            "description": "Existing projects without a visibility field are public."
          },
          "ownerId": {
            "type": [
              "integer",
              "null"
            ]
          },
          "canDelete": {
            "type": "boolean"
          },
          "canSetVisibility": {
            "type": "boolean"
          }
        }
      },
      "DeployResult": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "project": {
            "$ref": "#/components/schemas/Project"
          },
          "deployment": {
            "$ref": "#/components/schemas/Deployment"
          },
          "url": {
            "type": "string",
            "format": "uri"
          }
        }
      }
    }
  },
  "paths": {
    "/api/projects": {
      "get": {
        "summary": "List private projects owned by the user and all public projects",
        "responses": {
          "200": {
            "description": "Projects",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "projects": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Project"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "post": {
        "summary": "Create a project",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 100
                  },
                  "visibility": {
                    "type": "string",
                    "enum": [
                      "private",
                      "public"
                    ],
                    "default": "private"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created project",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "project": {
                      "$ref": "#/components/schemas/Project"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/api/deploy": {
      "post": {
        "summary": "Create a new project in subdomain mode and deploy a ZIP",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "file"
                ],
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "file": {
                    "type": "string",
                    "format": "binary"
                  },
                  "visibility": {
                    "type": "string",
                    "enum": [
                      "private",
                      "public"
                    ],
                    "default": "private"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Published",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeployResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          }
        }
      }
    },
    "/api/projects/{id}/deploy": {
      "post": {
        "summary": "Deploy a ZIP to an exact project ID",
        "parameters": [
          {
            "$ref": "#/components/parameters/ProjectId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Published",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeployResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          }
        }
      }
    },
    "/api/projects/{id}": {
      "delete": {
        "summary": "Delete a project and its files",
        "description": "Any signed-in user may delete a public project. Only its owner may delete a private project.",
        "parameters": [
          {
            "$ref": "#/components/parameters/ProjectId"
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted project"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/projects/{id}/domains": {
      "post": {
        "summary": "Attach a manually resolved custom hostname",
        "parameters": [
          {
            "$ref": "#/components/parameters/ProjectId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "domain"
                ],
                "properties": {
                  "domain": {
                    "type": "string",
                    "example": "www.example.com"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Pending certificate setup",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "domain": {
                      "$ref": "#/components/schemas/CustomDomain"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/api/projects/{projectId}/domains/{id}": {
      "delete": {
        "summary": "Remove a custom hostname",
        "parameters": [
          {
            "$ref": "#/components/parameters/DomainProjectId"
          },
          {
            "$ref": "#/components/parameters/DomainId"
          }
        ],
        "responses": {
          "200": {
            "description": "Removal queued"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/projects/{projectId}/domains/{id}/retry": {
      "post": {
        "summary": "Retry failed certificate setup",
        "parameters": [
          {
            "$ref": "#/components/parameters/DomainProjectId"
          },
          {
            "$ref": "#/components/parameters/DomainId"
          }
        ],
        "responses": {
          "200": {
            "description": "Retry queued"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/auth/register": {
      "post": {
        "summary": "Register a user",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "username",
                  "password"
                ],
                "properties": {
                  "username": {
                    "type": "string",
                    "minLength": 3,
                    "maxLength": 32
                  },
                  "password": {
                    "type": "string",
                    "minLength": 10
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Registered and signed in"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/api/auth/login": {
      "post": {
        "summary": "Sign in with username and password",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "username",
                  "password"
                ],
                "properties": {
                  "username": {
                    "type": "string"
                  },
                  "password": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Signed in with an HttpOnly session cookie"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/api/me/token": {
      "post": {
        "summary": "Generate or replace the current user’s Agent token; the plain token is returned once",
        "responses": {
          "200": {
            "description": "New token",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "token": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/api/projects/{id}/visibility": {
      "patch": {
        "summary": "Owner changes a project between private and public",
        "parameters": [
          {
            "$ref": "#/components/parameters/ProjectId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "visibility"
                ],
                "properties": {
                  "visibility": {
                    "type": "string",
                    "enum": [
                      "private",
                      "public"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Visibility updated"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Only owner can change visibility"
          }
        }
      }
    }
  },
  "x-note": "Public projects can be edited by any signed-in user. Existing projects are public. Internal domain worker endpoints are omitted."
}
