{
  "components": {
    "schemas": {
      "APIToken": {
        "properties": {
          "created_at": {
            "type": "string"
          },
          "expires_at": {
            "type": "string"
          },
          "id": {
            "type": "string"
          },
          "last_used_at": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "revoked_at": {
            "type": "string"
          }
        },
        "required": [
          "created_at",
          "expires_at",
          "id",
          "last_used_at",
          "name",
          "revoked_at"
        ],
        "type": "object"
      },
      "AuditEvent": {
        "properties": {
          "action": {
            "type": "string"
          },
          "at": {
            "format": "date-time",
            "type": "string"
          },
          "detail": {}
        },
        "required": [
          "action",
          "at",
          "detail"
        ],
        "type": "object"
      },
      "Capacity": {
        "properties": {
          "disk_gb": {
            "type": "integer"
          },
          "mem_mb": {
            "type": "integer"
          },
          "vcpus": {
            "type": "integer"
          }
        },
        "required": [
          "disk_gb",
          "mem_mb",
          "vcpus"
        ],
        "type": "object"
      },
      "CreateAPITokenRequest": {
        "properties": {
          "name": {
            "type": "string"
          },
          "ttl_seconds": {
            "type": "integer"
          }
        },
        "type": "object"
      },
      "CreateAPITokenResponse": {
        "properties": {
          "expires_at": {
            "type": "string"
          },
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "token": {
            "type": "string"
          }
        },
        "required": [
          "expires_at",
          "id",
          "name",
          "token"
        ],
        "type": "object"
      },
      "CreateExposureRequest": {
        "properties": {
          "guest_port": {
            "type": "integer"
          },
          "host_port": {
            "type": "integer"
          }
        },
        "type": "object"
      },
      "CreateVMRequest": {
        "properties": {
          "cloud_init": {
            "type": "string"
          },
          "disk_gb": {
            "type": "integer"
          },
          "host_id": {
            "type": "string"
          },
          "image_sha256": {
            "type": "string"
          },
          "image_url": {
            "type": "string"
          },
          "mem_mb": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "persistent": {
            "type": "boolean"
          },
          "power_state": {
            "type": "string"
          },
          "ssh_authorized_key": {
            "type": "string"
          },
          "vcpus": {
            "type": "integer"
          }
        },
        "type": "object"
      },
      "CreateVMResponse": {
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "name"
        ],
        "type": "object"
      },
      "EnrollRequest": {
        "properties": {
          "arch": {
            "type": "string"
          },
          "bridge_cidr": {
            "type": [
              "string",
              "null"
            ]
          },
          "name": {
            "type": "string"
          },
          "os": {
            "type": "string"
          },
          "provisioner": {
            "type": "string"
          },
          "token": {
            "type": "string"
          }
        },
        "type": "object"
      },
      "EnrollResponse": {
        "properties": {
          "bridge_cidr": {
            "type": "string"
          },
          "credential": {
            "type": "string"
          },
          "host_id": {
            "type": "string"
          },
          "server_cert_sha256": {
            "type": "string"
          }
        },
        "required": [
          "bridge_cidr",
          "credential",
          "host_id",
          "server_cert_sha256"
        ],
        "type": "object"
      },
      "EnrollTokenResponse": {
        "properties": {
          "join": {
            "type": "string"
          },
          "token": {
            "type": "string"
          }
        },
        "required": [
          "join",
          "token"
        ],
        "type": "object"
      },
      "Exposure": {
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "guest_port": {
            "type": "integer"
          },
          "host_addr": {
            "type": "string"
          },
          "host_id": {
            "type": "string"
          },
          "host_port": {
            "type": "integer"
          },
          "id": {
            "type": "string"
          },
          "protocol": {
            "type": "string"
          },
          "reason": {
            "type": "string"
          },
          "scope": {
            "type": "string"
          },
          "state": {
            "type": "string"
          },
          "vm_id": {
            "type": "string"
          }
        },
        "required": [
          "created_at",
          "guest_port",
          "host_addr",
          "host_id",
          "host_port",
          "id",
          "protocol",
          "reason",
          "scope",
          "state",
          "vm_id"
        ],
        "type": "object"
      },
      "Host": {
        "properties": {
          "agent_update_available": {
            "type": "boolean"
          },
          "agent_version": {
            "type": "string"
          },
          "allocated": {
            "$ref": "#/components/schemas/Capacity"
          },
          "arch": {
            "type": "string"
          },
          "bridge_cidr": {
            "type": "string"
          },
          "capacity": {
            "$ref": "#/components/schemas/Capacity"
          },
          "cpu_model": {
            "type": "string"
          },
          "enrolled_at": {
            "format": "date-time",
            "type": "string"
          },
          "id": {
            "type": "string"
          },
          "kernel": {
            "type": "string"
          },
          "last_seen": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "metrics": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Metrics"
              },
              {
                "type": "null"
              }
            ]
          },
          "name": {
            "type": "string"
          },
          "online": {
            "type": "boolean"
          },
          "os": {
            "type": "string"
          },
          "os_id": {
            "type": "string"
          },
          "os_pretty": {
            "type": "string"
          },
          "os_version": {
            "type": "string"
          },
          "provisioner": {
            "type": "string"
          },
          "seconds_since_last_seen": {
            "type": [
              "integer",
              "null"
            ]
          },
          "sessions": {
            "type": "integer"
          },
          "stale": {
            "type": "boolean"
          },
          "status": {
            "type": "string"
          },
          "uplink_addr": {
            "type": "string"
          },
          "virt": {
            "type": "string"
          }
        },
        "required": [
          "agent_update_available",
          "agent_version",
          "allocated",
          "arch",
          "bridge_cidr",
          "capacity",
          "cpu_model",
          "enrolled_at",
          "id",
          "kernel",
          "name",
          "online",
          "os",
          "os_id",
          "os_pretty",
          "os_version",
          "provisioner",
          "sessions",
          "stale",
          "status",
          "uplink_addr",
          "virt"
        ],
        "type": "object"
      },
      "InjectedKey": {
        "properties": {
          "comment": {
            "type": "string"
          },
          "fingerprint": {
            "type": "string"
          },
          "type": {
            "type": "string"
          }
        },
        "required": [
          "comment",
          "fingerprint",
          "type"
        ],
        "type": "object"
      },
      "ManagedCAResponse": {
        "properties": {
          "created": {
            "type": "boolean"
          },
          "fingerprint": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "pubkey": {
            "type": "string"
          }
        },
        "required": [
          "created",
          "fingerprint",
          "label",
          "pubkey"
        ],
        "type": "object"
      },
      "Me": {
        "properties": {
          "email": {
            "type": "string"
          },
          "tenant": {
            "type": "string"
          }
        },
        "required": [
          "email",
          "tenant"
        ],
        "type": "object"
      },
      "Metrics": {
        "properties": {
          "disk_free_gb": {
            "type": "integer"
          },
          "disk_used_gb": {
            "type": "integer"
          },
          "load1": {
            "type": "number"
          },
          "load15": {
            "type": "number"
          },
          "load5": {
            "type": "number"
          },
          "mem_available_mb": {
            "type": "integer"
          },
          "mem_used_mb": {
            "type": "integer"
          },
          "uptime_s": {
            "type": "integer"
          }
        },
        "required": [
          "disk_free_gb",
          "disk_used_gb",
          "load1",
          "load15",
          "load5",
          "mem_available_mb",
          "mem_used_mb",
          "uptime_s"
        ],
        "type": "object"
      },
      "PatchVMRequest": {
        "properties": {
          "power_state": {
            "type": "string"
          }
        },
        "type": "object"
      },
      "RevokeSSHCertRequest": {
        "properties": {
          "certificate": {
            "type": "string"
          },
          "reason": {
            "type": "string"
          },
          "serial": {
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "RevokedCert": {
        "properties": {
          "reason": {
            "type": "string"
          },
          "revoked_at": {
            "format": "date-time",
            "type": "string"
          },
          "serial": {
            "type": "string"
          }
        },
        "required": [
          "reason",
          "revoked_at",
          "serial"
        ],
        "type": "object"
      },
      "SSHCAResponse": {
        "properties": {
          "ca": {
            "type": "string"
          }
        },
        "required": [
          "ca"
        ],
        "type": "object"
      },
      "StateSnapshot": {
        "properties": {
          "hosts": {
            "items": {
              "$ref": "#/components/schemas/Host"
            },
            "type": "array"
          },
          "latest_version": {
            "type": "string"
          },
          "server_version": {
            "type": "string"
          },
          "vms": {
            "items": {
              "$ref": "#/components/schemas/VM"
            },
            "type": "array"
          }
        },
        "required": [
          "hosts",
          "latest_version",
          "server_version",
          "vms"
        ],
        "type": "object"
      },
      "StreamTicketResponse": {
        "properties": {
          "ticket": {
            "type": "string"
          }
        },
        "required": [
          "ticket"
        ],
        "type": "object"
      },
      "UserCA": {
        "properties": {
          "fingerprint": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "pubkey": {
            "type": "string"
          }
        },
        "required": [
          "fingerprint",
          "label",
          "pubkey"
        ],
        "type": "object"
      },
      "UserCARequest": {
        "properties": {
          "label": {
            "type": "string"
          },
          "public_key": {
            "type": "string"
          }
        },
        "type": "object"
      },
      "UserCAUploadResponse": {
        "properties": {
          "fingerprint": {
            "type": "string"
          }
        },
        "required": [
          "fingerprint"
        ],
        "type": "object"
      },
      "VM": {
        "properties": {
          "actual_power": {
            "type": "string"
          },
          "assigned_ip": {
            "type": "string"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "deleted": {
            "type": "boolean"
          },
          "destroy_at": {
            "type": "integer"
          },
          "disk_gb": {
            "type": "integer"
          },
          "host_id": {
            "type": "string"
          },
          "id": {
            "type": "string"
          },
          "image_url": {
            "type": "string"
          },
          "injected_key": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/InjectedKey"
              },
              {
                "type": "null"
              }
            ]
          },
          "last_error": {
            "type": "string"
          },
          "lifecycle": {
            "type": "string"
          },
          "mem_mb": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "persistent": {
            "type": "boolean"
          },
          "phase": {
            "type": "string"
          },
          "power_state": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "vcpus": {
            "type": "integer"
          }
        },
        "required": [
          "actual_power",
          "assigned_ip",
          "created_at",
          "deleted",
          "destroy_at",
          "disk_gb",
          "host_id",
          "id",
          "image_url",
          "last_error",
          "lifecycle",
          "mem_mb",
          "name",
          "persistent",
          "phase",
          "power_state",
          "status",
          "vcpus"
        ],
        "type": "object"
      }
    },
    "securitySchemes": {
      "patToken": {
        "scheme": "bearer",
        "type": "http"
      }
    }
  },
  "info": {
    "title": "eitri server API",
    "version": "v1"
  },
  "openapi": "3.1.0",
  "paths": {
    "/api/v1/audit": {
      "get": {
        "parameters": [
          {
            "description": "max rows to return (default 100, cap 1000)",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/AuditEvent"
                  },
                  "type": "array"
                }
              }
            },
            "description": "success"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "security": [
          {
            "patToken": []
          }
        ],
        "summary": "Newest audit log rows."
      }
    },
    "/api/v1/enroll": {
      "post": {
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EnrollRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnrollResponse"
                }
              }
            },
            "description": "success"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "summary": "Redeem a one-time enrollment token: a new host joins the fleet and receives its credential. Unauthenticated but rate-limited; the token is the proof."
      }
    },
    "/api/v1/enroll-tokens": {
      "post": {
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnrollTokenResponse"
                }
              }
            },
            "description": "success"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "security": [
          {
            "patToken": []
          }
        ],
        "summary": "Mint a one-time host enrollment token plus the join blob agents consume."
      }
    },
    "/api/v1/events": {
      "get": {
        "parameters": [
          {
            "description": "one-time stream ticket",
            "in": "query",
            "name": "ticket",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "text/event-stream": {
                "schema": {
                  "$ref": "#/components/schemas/StateSnapshot"
                }
              }
            },
            "description": "success"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "summary": "Live fleet state stream (Server-Sent Events); each 'state' event carries a StateSnapshot."
      }
    },
    "/api/v1/exposures/{id}": {
      "delete": {
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "success"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "security": [
          {
            "patToken": []
          }
        ],
        "summary": "Revoke an exposure; its host closes the listener on the next converge."
      }
    },
    "/api/v1/hosts": {
      "get": {
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/Host"
                  },
                  "type": "array"
                }
              }
            },
            "description": "success"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "security": [
          {
            "patToken": []
          }
        ],
        "summary": "List fleet hosts: durable rows merged with live agent state and allocation."
      }
    },
    "/api/v1/hosts/{id}": {
      "delete": {
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "purge VM rows and remove the host immediately (dead hardware escape hatch)",
            "in": "query",
            "name": "force",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "success"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "security": [
          {
            "patToken": []
          }
        ],
        "summary": "Decommission a host: tombstone its VMs and drain gracefully (202). With ?force, purge and remove immediately, returning 200."
      }
    },
    "/api/v1/hosts/{id}/revoke-credential": {
      "post": {
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "success"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "security": [
          {
            "patToken": []
          }
        ],
        "summary": "Revoke a host's outstanding credential by bumping its generation; the host stays dark until re-enrolled."
      }
    },
    "/api/v1/hosts/{id}/upgrade-agent": {
      "post": {
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "success"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "security": [
          {
            "patToken": []
          }
        ],
        "summary": "Offer the host's agent a self-upgrade to the latest known release (per-host, human-controlled rollout)."
      }
    },
    "/api/v1/managed-ca": {
      "delete": {
        "responses": {
          "204": {
            "description": "success"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "security": [
          {
            "patToken": []
          }
        ],
        "summary": "Disable the tenant's eitri-managed CA: the signing key is destroyed and the CA leaves the tenant's set, so the gate stops accepting its certificates."
      },
      "post": {
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManagedCAResponse"
                }
              }
            },
            "description": "success"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "security": [
          {
            "patToken": []
          }
        ],
        "summary": "Enable an eitri-managed SSH user CA for the caller's tenant: eitri generates and holds the signing key, and its public half joins the tenant's CA set. Idempotent. Opt-in — BYO CAs remain the default."
      }
    },
    "/api/v1/me": {
      "get": {
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Me"
                }
              }
            },
            "description": "success"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "security": [
          {
            "patToken": []
          }
        ],
        "summary": "The signed-in identity: the caller's tenant handle and bound email."
      }
    },
    "/api/v1/ssh-ca": {
      "get": {
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SSHCAResponse"
                }
              }
            },
            "description": "success"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "summary": "The eitri SSH host CA public key (public material) for pinning `@cert-authority` in known_hosts. 404 when the jump gate is off."
      }
    },
    "/api/v1/ssh-certs/revoke": {
      "post": {
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RevokeSSHCertRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "success"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "security": [
          {
            "patToken": []
          }
        ],
        "summary": "Revoke a minted SSH user certificate by serial or certificate line; the gate rejects it before its TTL expires. Idempotent."
      }
    },
    "/api/v1/ssh-certs/revoked": {
      "get": {
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/RevokedCert"
                  },
                  "type": "array"
                }
              }
            },
            "description": "success"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "security": [
          {
            "patToken": []
          }
        ],
        "summary": "List revoked SSH user certificate serials (with reason and time), newest first."
      }
    },
    "/api/v1/stream-tickets": {
      "post": {
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StreamTicketResponse"
                }
              }
            },
            "description": "success"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "security": [
          {
            "patToken": []
          }
        ],
        "summary": "Mint a one-time short-TTL ticket for the SSE stream or console WebSocket — the only credential that ever rides in a URL."
      }
    },
    "/api/v1/tenants/{tenant}/user-cas": {
      "delete": {
        "parameters": [
          {
            "in": "path",
            "name": "tenant",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UserCARequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "success"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "security": [
          {
            "patToken": []
          }
        ],
        "summary": "Remove a registered SSH user CA by its public_key line."
      },
      "get": {
        "parameters": [
          {
            "in": "path",
            "name": "tenant",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/UserCA"
                  },
                  "type": "array"
                }
              }
            },
            "description": "success"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "security": [
          {
            "patToken": []
          }
        ],
        "summary": "List the tenant's registered SSH user CAs (pubkey, label, fingerprint)."
      },
      "post": {
        "parameters": [
          {
            "in": "path",
            "name": "tenant",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UserCARequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserCAUploadResponse"
                }
              }
            },
            "description": "success"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "security": [
          {
            "patToken": []
          }
        ],
        "summary": "Register a BYO SSH user CA public key for the tenant; eitri never holds a user signing key."
      }
    },
    "/api/v1/tokens": {
      "get": {
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/APIToken"
                  },
                  "type": "array"
                }
              }
            },
            "description": "success"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "security": [
          {
            "patToken": []
          }
        ],
        "summary": "List the tenant's personal access tokens (metadata only — never the secret), newest first."
      },
      "post": {
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateAPITokenRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateAPITokenResponse"
                }
              }
            },
            "description": "success"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "security": [
          {
            "patToken": []
          }
        ],
        "summary": "Mint a personal access token; the secret is returned exactly once. An optional TTL sets expiry (0 = non-expiring)."
      }
    },
    "/api/v1/tokens/{id}": {
      "delete": {
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "success"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "security": [
          {
            "patToken": []
          }
        ],
        "summary": "Revoke a personal access token by id; unknown or foreign ids answer 404 (no existence leak)."
      }
    },
    "/api/v1/user-cas": {
      "get": {
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/UserCA"
                  },
                  "type": "array"
                }
              }
            },
            "description": "success"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "security": [
          {
            "patToken": []
          }
        ],
        "summary": "List the caller's own tenant's registered SSH user CAs (pubkey, label, fingerprint)."
      },
      "post": {
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UserCARequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserCAUploadResponse"
                }
              }
            },
            "description": "success"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "security": [
          {
            "patToken": []
          }
        ],
        "summary": "Register a BYO SSH user CA public key for the caller's own tenant; eitri never holds a user signing key."
      }
    },
    "/api/v1/vms": {
      "get": {
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/VM"
                  },
                  "type": "array"
                }
              }
            },
            "description": "success"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "security": [
          {
            "patToken": []
          }
        ],
        "summary": "List VMs: durable rows merged with live agent-reported actual state."
      },
      "post": {
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateVMRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateVMResponse"
                }
              }
            },
            "description": "success"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "security": [
          {
            "patToken": []
          }
        ],
        "summary": "Create a VM on a host. Omitted fields get one-click defaults; the tenant must have a registered SSH user CA first."
      }
    },
    "/api/v1/vms/{id}": {
      "delete": {
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "success"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "security": [
          {
            "patToken": []
          }
        ],
        "summary": "Tombstone a VM for teardown; restorable within the grace window via restore."
      },
      "patch": {
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchVMRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "success"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "security": [
          {
            "patToken": []
          }
        ],
        "summary": "Set a VM's desired power state (running or stopped)."
      }
    },
    "/api/v1/vms/{id}/console/ws": {
      "get": {
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "one-time stream ticket",
            "in": "query",
            "name": "ticket",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "101": {
            "description": "switching protocols (WebSocket)"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "summary": "Serial-console WebSocket: raw byte pipe to the VM's serial console."
      }
    },
    "/api/v1/vms/{id}/events": {
      "get": {
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "max rows to return (default 100, cap 1000)",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/AuditEvent"
                  },
                  "type": "array"
                }
              }
            },
            "description": "success"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "security": [
          {
            "patToken": []
          }
        ],
        "summary": "One VM's lifecycle timeline (audit rows carrying its vm_id), newest first; survives the VM row being reaped."
      }
    },
    "/api/v1/vms/{id}/exposures": {
      "get": {
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/Exposure"
                  },
                  "type": "array"
                }
              }
            },
            "description": "success"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "security": [
          {
            "patToken": []
          }
        ],
        "summary": "List the VM's published ports, with the host address to dial and each listener's reported state."
      },
      "post": {
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateExposureRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Exposure"
                }
              }
            },
            "description": "success"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "security": [
          {
            "patToken": []
          }
        ],
        "summary": "Publish a guest TCP port on the VM's host. Omit host_port to allocate one from the reserved range 30000-32767; a named port must be \u003e= 1024 and is honored or refused."
      }
    },
    "/api/v1/vms/{id}/restore": {
      "post": {
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "success"
          },
          "default": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "error (plain text)"
          }
        },
        "security": [
          {
            "patToken": []
          }
        ],
        "summary": "Un-tombstone a VM still within the teardown grace window; the agent re-adopts the guest."
      }
    }
  }
}
