openapi: 3.1.0
info:
  title: Qumo Deploy REST API
  description: |
    The Qumo Deploy REST API provides programmatic control over edge relay clusters,
    ephemeral token issuance, tenant lifecycle, bot machine identities, and billing.
  version: 1.0.0
servers:
  - url: https://api.qumo.dev
    description: Production Control Plane
  - url: http://localhost:8080
    description: Local Development / Sandbox

security:
  - BearerAuth: []
  - ApiKeyAuth: []

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: |
        Bearer token (User session, Bot machine token, or Personal Access Token).
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: |
        Project-scoped API key (`qumo_live_...` or `qumo_test_...`).

  schemas:
    ErrorResponse:
      type: object
      required:
        - error
      properties:
        error:
          type: string
          example: "invalid or expired token"

    HealthStatus:
      type: object
      required:
        - status
      properties:
        status:
          type: string
          example: "ok"

    PricingInfo:
      type: object
      required:
        - bandwidth_per_gb
        - currency
      properties:
        bandwidth_per_gb:
          type: number
          example: 0.08
        currency:
          type: string
          example: "USD"

    Plan:
      type: object
      required:
        - id
        - name
      properties:
        id:
          type: string
          example: "plan_pro"
        name:
          type: string
          example: "Pro Plan"
        included_usage_bytes:
          type: integer
          format: int64
          example: 107374182400

    User:
      type: object
      required:
        - id
        - email
      properties:
        id:
          type: string
          example: "usr_9918231"
        email:
          type: string
          example: "alex@example.com"
        name:
          type: string
          example: "Alex Developer"
        github_login:
          type: string
          example: "alexdev"

    Session:
      type: object
      required:
        - user
        - org_id
        - org_name
        - role
      properties:
        user:
          $ref: '#/components/schemas/User'
        org_id:
          type: string
          example: "ten_8f29acb0"
        org_name:
          type: string
          example: "Acme Corp"
        role:
          type: string
          example: "roles/tenant.admin"

    Project:
      type: object
      required:
        - id
        - name
        - tenant_id
        - environment
      properties:
        id:
          type: string
          example: "prj_prod_01"
        name:
          type: string
          example: "live-stream-prod"
        tenant_id:
          type: string
          example: "ten_8f29acb0"
        environment:
          type: string
          enum: [production, test]
          example: "production"

    CreateProjectRequest:
      type: object
      required:
        - name
      properties:
        name:
          type: string
          example: "live-stream-prod"
        environment:
          type: string
          enum: [production, test]
          default: production

    IssuedCredential:
      type: object
      required:
        - token
        - expires_at
        - jti
      properties:
        token:
          type: string
          example: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
        expires_at:
          type: string
          format: date-time
          example: "2026-09-12T12:00:00Z"
        jti:
          type: string
          example: "c0b7e28e-8a5f-4a3e-bfa1-e28373b984d2"
        relays:
          type: array
          items:
            $ref: '#/components/schemas/RelayEndpoint'
        fallback:
          type: array
          items:
            type: string
            example: "tyo1.relay.qumo.live:4433"

    IssueCredentialRequest:
      type: object
      required:
        - scopes
      properties:
        scopes:
          type: array
          items:
            type: string
            example: "relay:session"
        ttl_seconds:
          type: integer
          default: 3600
          example: 3600

    RelayEndpoint:
      type: object
      required:
        - id
        - region
        - host
        - port
        - url
        - status
      properties:
        id:
          type: string
          example: "relay-tyo-01"
        region:
          type: string
          example: "ap-northeast-1"
        host:
          type: string
          example: "tyo1.relay.qumo.live"
        port:
          type: integer
          example: 4433
        url:
          type: string
          example: "https://tyo1.relay.qumo.live:4433"
        status:
          type: string
          enum: [healthy, degraded]
          example: "healthy"

    Bot:
      type: object
      required:
        - id
        - project_id
        - name
      properties:
        id:
          type: string
          example: "bot_18b29c10"
        project_id:
          type: string
          example: "prj_prod_01"
        name:
          type: string
          example: "github-actions-deployer"
        created_at:
          type: string
          format: date-time
          example: "2026-06-01T12:00:00Z"

    CreateBotRequest:
      type: object
      required:
        - name
      properties:
        name:
          type: string
          example: "github-actions-deployer"

paths:
  /healthz:
    get:
      summary: Liveness probe
      description: Returns 200 OK if the process is running.
      security: []
      responses:
        '200':
          description: Process healthy
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HealthStatus'

  /readyz:
    get:
      summary: Readiness probe
      description: Checks database and storage dependency connectivity.
      security: []
      responses:
        '200':
          description: Ready to serve traffic
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HealthStatus'
        '503':
          description: Service Unavailable (database disconnect)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /v1/pricing:
    get:
      summary: Public platform pricing
      description: Retrieve bandwidth and stream egress rates.
      security: []
      responses:
        '200':
          description: Platform pricing
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PricingInfo'

  /v1/plans:
    get:
      summary: List subscription plans
      description: Lists active tiers and included bandwidth quotas.
      security: []
      responses:
        '200':
          description: List of plans
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Plan'

  /admin/v1/auth/session:
    get:
      summary: Get active session
      description: Returns the authenticated user profile, active tenant, and IAM role.
      responses:
        '200':
          description: Current session info
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Session'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /admin/v1/projects:
    get:
      summary: List projects
      description: Returns all projects under the active tenant.
      parameters:
        - in: query
          name: tenant_id
          schema:
            type: string
          required: false
          description: Tenant filter
      responses:
        '200':
          description: Array of projects
          content:
            application/json:
              schema:
                type: object
                properties:
                  projects:
                    type: array
                    items:
                      $ref: '#/components/schemas/Project'
    post:
      summary: Create project
      description: Creates a new isolated deployment project.
      parameters:
        - in: query
          name: tenant_id
          schema:
            type: string
          required: false
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateProjectRequest'
      responses:
        '200':
          description: Created project
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Project'
        '409':
          description: Conflict (duplicate project name)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /api/v1/credentials:
    post:
      summary: Issue temporary relay credentials
      description: |
        Direct machine issuance: mints a short-lived scoped JWT used to connect to MoQ/WebTransport edge relays.
        The client must authenticate with an active API key (`X-API-Key`).
      security:
        - ApiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/IssueCredentialRequest'
      responses:
        '200':
          description: Ephemeral credential with assigned relay endpoints
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IssuedCredential'
        '400':
          description: Invalid request parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '402':
          description: Plan connection limit reached
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Scope not permitted
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /admin/v1/credentials/{jti}/revoke:
    post:
      summary: Revoke issued credential
      description: Revokes an active token before natural expiration.
      parameters:
        - in: path
          name: jti
          required: true
          schema:
            type: string
          description: Credential JWT identifier
      responses:
        '204':
          description: Token revoked successfully
        '401':
          description: Unauthorized
        '403':
          description: Forbidden

  /admin/v1/projects/{project_id}/bots:
    get:
      summary: List bots
      description: Lists machine identities belonging to the specified project.
      parameters:
        - in: path
          name: project_id
          required: true
          schema:
            type: string
      responses:
        '200':
          description: List of bots
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Bot'
    post:
      summary: Create bot
      description: Provisions a new machine identity principal in the project.
      parameters:
        - in: path
          name: project_id
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateBotRequest'
      responses:
        '200':
          description: Created bot
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Bot'
