openapi: 3.0.3 info: title: Phoenix Deploy API / Phoenix API Railing description: | Gitea webhook, deploy stub, and Phoenix API Railing (Infra, VE, Health). Optional partner API key for /api/v1/* when PHOENIX_PARTNER_KEYS is set. version: 1.0.0 servers: - url: http://localhost:4001 description: Default tags: - name: Webhook - name: Infra - name: VE - name: Health - name: PublicSector - name: System paths: /health: get: tags: [System] summary: Health check responses: '200': description: OK content: application/json: schema: type: object properties: status: { type: string } service: { type: string } /webhook/gitea: post: tags: [Webhook] summary: Gitea webhook receiver requestBody: required: true content: application/json: schema: { type: object } responses: '200': { description: Accepted } '400': { description: No payload } '401': { description: Invalid signature } /api/deploy: post: tags: [Webhook] summary: Deploy request requestBody: content: application/json: schema: type: object required: [repo] properties: repo: { type: string } branch: { type: string } target: { type: string } sha: { type: string } responses: '202': { description: Accepted } '401': { description: Unauthorized } /api/v1/public-sector/programs: get: tags: [PublicSector] summary: Public-sector and eIDAS program manifest (JSON) description: | Serves `config/public-sector-program-manifest.json` from the proxmox repo (or `PUBLIC_SECTOR_MANIFEST_PATH`). No API key required. Returns 503 if the file is missing on the host. responses: '200': description: Manifest JSON content: application/json: schema: type: object properties: schemaVersion: { type: string } updated: { type: string } programs: { type: array, items: { type: object } } '500': { description: Invalid JSON or read error } '503': { description: Manifest file not found } /api/v1/infra/nodes: get: tags: [Infra] summary: List cluster nodes responses: '200': content: application/json: schema: type: object properties: nodes: { type: array } stub: { type: boolean } '502': { description: Proxmox error } /api/v1/infra/storage: get: tags: [Infra] summary: List storage pools responses: '200': content: application/json: schema: type: object properties: storage: { type: array } stub: { type: boolean } '502': { description: Proxmox error } /api/v1/ve/vms: get: tags: [VE] summary: List VMs/CTs parameters: - name: node in: query schema: { type: string } responses: '200': content: application/json: schema: type: object properties: vms: { type: array } stub: { type: boolean } '502': { description: Proxmox error } /api/v1/ve/vms/{node}/{vmid}/status: get: tags: [VE] summary: VM/CT status parameters: - name: node in: path required: true schema: { type: string } - name: vmid in: path required: true schema: { type: string } - name: type in: query schema: { type: string, enum: [qemu, lxc], default: qemu } responses: '200': { description: Status object } '502': { description: Proxmox error } /api/v1/ve/vms/{node}/{vmid}/start: post: tags: [VE] summary: Start VM/CT parameters: - name: node in: path required: true schema: { type: string } - name: vmid in: path required: true schema: { type: string } - name: type in: query schema: { type: string, enum: [qemu, lxc], default: qemu } responses: '200': { description: OK } '403': { description: Lifecycle disabled } '502': { description: Proxmox error } /api/v1/ve/vms/{node}/{vmid}/stop: post: tags: [VE] summary: Stop VM/CT parameters: - name: node in: path required: true schema: { type: string } - name: vmid in: path required: true schema: { type: string } - name: type in: query schema: { type: string, enum: [qemu, lxc], default: qemu } responses: '200': { description: OK } '403': { description: Lifecycle disabled } '502': { description: Proxmox error } /api/v1/ve/vms/{node}/{vmid}/reboot: post: tags: [VE] summary: Reboot VM/CT parameters: - name: node in: path required: true schema: { type: string } - name: vmid in: path required: true schema: { type: string } - name: type in: query schema: { type: string, enum: [qemu, lxc], default: qemu } responses: '200': { description: OK } '403': { description: Lifecycle disabled } '502': { description: Proxmox error } /api/v1/health/metrics: get: tags: [Health] summary: Prometheus query proxy parameters: - name: query in: query required: true schema: { type: string } description: PromQL (URL-encoded) responses: '200': { description: Prometheus response } '400': { description: Missing query } '502': { description: Prometheus unreachable } /api/v1/health/alerts: get: tags: [Health] summary: Active alerts responses: '200': content: application/json: schema: type: object properties: alerts: { type: array } stub: { type: boolean } /api/v1/health/summary: get: tags: [Health] summary: Aggregated health for Portal responses: '200': content: application/json: schema: type: object properties: status: { type: string } updated_at: { type: string, format: date-time } hosts: { type: array } alerts: { type: array } components: securitySchemes: BearerAuth: type: http scheme: bearer description: PHOENIX_DEPLOY_SECRET for /api/deploy ApiKeyAuth: type: apiKey in: header name: X-API-Key description: Optional partner key (or Authorization Bearer)