openapi: "3.1.0"
info:
  title: Qpher Key Management API
  description: PQC key lifecycle management — generate, rotate, list, retire, and query keys.
  version: "1.1.0"
  contact:
    name: Qpher Support
    url: https://qpher.ai/support
    email: support@qpher.ai

servers:
  - url: https://api.qpher.ai
    description: Production

security:
  - apiKey: []

paths:
  /api/v1/kms/keys/generate:
    post:
      operationId: generateKey
      summary: Generate a new PQC key pair
      description: |
        Generate a new PQC key pair for the specified algorithm.
        The key starts in "active" status at version 1 (or next available version).
        Private keys are stored encrypted and never returned.
      tags: [Key Management]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [algorithm]
              properties:
                algorithm:
                  type: string
                  enum: [Kyber768, Dilithium3, X-Wing, Composite-ML-DSA]
                  description: PQC algorithm for key generation
                  example: Kyber768
      responses:
        "201":
          description: Key generated successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/KeyResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "429":
          $ref: "#/components/responses/RateLimited"

  /api/v1/kms/keys/rotate:
    post:
      operationId: rotateKey
      summary: Rotate an active key
      description: |
        Create a new active key version and retire the current active key.
        The old key transitions to "retired" (decrypt/verify only).
      tags: [Key Management]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [algorithm]
              properties:
                algorithm:
                  type: string
                  enum: [Kyber768, Dilithium3, X-Wing, Composite-ML-DSA]
                  description: Algorithm of the key to rotate
                  example: Kyber768
      responses:
        "201":
          description: Key rotated successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RotateResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "429":
          $ref: "#/components/responses/RateLimited"

  /api/v1/kms/keys:
    get:
      operationId: listKeys
      summary: List all PQC keys
      description: List all PQC keys for the current tenant, optionally filtered by algorithm or status.
      tags: [Key Management]
      parameters:
        - name: algorithm
          in: query
          schema:
            type: string
            enum: [Kyber768, Dilithium3, X-Wing, Composite-ML-DSA]
          description: Filter by algorithm (optional)
          example: Kyber768
        - name: status
          in: query
          schema:
            type: string
            enum: [active, retired, archived]
          description: Filter by key status (optional)
      responses:
        "200":
          description: Keys listed
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/KeyListResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "429":
          $ref: "#/components/responses/RateLimited"

  /api/v1/kms/keys/active:
    get:
      operationId: getActiveKey
      summary: Get the active key for an algorithm
      description: Returns the currently active key version for the specified algorithm.
      tags: [Key Management]
      parameters:
        - name: algorithm
          in: query
          required: true
          schema:
            type: string
            enum: [Kyber768, Dilithium3, X-Wing, Composite-ML-DSA]
          example: Kyber768
      responses:
        "200":
          description: Active key info
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/KeyResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "429":
          $ref: "#/components/responses/RateLimited"

  /api/v1/kms/keys/retire:
    post:
      operationId: retireKey
      summary: Retire a key version
      description: |
        Transition a key from "active" to "retired".
        Retired keys can only be used for decrypt/verify, not encrypt/sign.
      tags: [Key Management]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [algorithm, key_version]
              properties:
                algorithm:
                  type: string
                  enum: [Kyber768, Dilithium3, X-Wing, Composite-ML-DSA]
                  description: Algorithm of the key to retire
                  example: Kyber768
                key_version:
                  type: integer
                  minimum: 1
                  description: Key version to retire
                  example: 1
      responses:
        "200":
          description: Key retired
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/KeyResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "429":
          $ref: "#/components/responses/RateLimited"

components:
  securitySchemes:
    apiKey:
      type: apiKey
      in: header
      name: X-API-Key

  schemas:
    KeyResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            key_version:
              type: integer
              example: 1
            algorithm:
              type: string
              example: Kyber768
            status:
              type: string
              enum: [active, retired, archived]
              example: active
            public_key:
              type: string
              format: byte
              description: Base64-encoded public key
              example: TUlJQm9qQU5CZ3B1YmxpY19rZXlfZXhhbXBsZV9iYXNlNjRfcGxhY2Vob2xkZXI=
            created_at:
              type: string
              format: date-time
              example: "2026-01-15T10:30:00.000Z"
        request_id:
          type: string
          format: uuid
          example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
        timestamp:
          type: string
          format: date-time
          example: "2026-01-15T10:30:00.000Z"

    RotateResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            public_key:
              type: string
              format: byte
              description: Base64-encoded public key of the new active key
              example: TUlJQm9qQU5CZ3B1YmxpY19rZXlfZXhhbXBsZV9iYXNlNjRfcGxhY2Vob2xkZXI=
            key_version:
              type: integer
              description: Version number of the new active key
              example: 2
            algorithm:
              type: string
              example: Kyber768
            old_key_version:
              type: integer
              description: Version number of the previously active key (now retired)
              example: 1
        request_id:
          type: string
          format: uuid
          example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
        timestamp:
          type: string
          format: date-time
          example: "2026-01-15T10:30:00.000Z"

    KeyListResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            keys:
              type: array
              items:
                type: object
                properties:
                  key_version:
                    type: integer
                    example: 1
                  algorithm:
                    type: string
                    example: Kyber768
                  status:
                    type: string
                    example: active
                  public_key:
                    type: string
                    format: byte
                    example: TUlJQm9qQU5CZ3B1YmxpY19rZXlfZXhhbXBsZV9iYXNlNjRfcGxhY2Vob2xkZXI=
                  created_at:
                    type: string
                    format: date-time
                    example: "2026-01-15T10:30:00.000Z"
            total:
              type: integer
              description: Total number of keys returned
              example: 2
        request_id:
          type: string
          format: uuid
          example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
        timestamp:
          type: string
          format: date-time
          example: "2026-01-15T10:30:00.000Z"

    ErrorResponse:
      type: object
      properties:
        error:
          type: object
          properties:
            error_code:
              type: string
              pattern: "^ERR_[A-Z_]+_\\d{3}$"
              example: ERR_INVALID_001
            message:
              type: string
              example: Invalid request — unsupported algorithm
        request_id:
          type: string
          format: uuid
          example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
        timestamp:
          type: string
          format: date-time
          example: "2026-01-15T10:30:00.000Z"

  responses:
    BadRequest:
      description: Invalid request
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
    Unauthorized:
      description: Missing or invalid API key
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
    Forbidden:
      description: Operation not allowed
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
    Conflict:
      description: Resource conflict
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
    RateLimited:
      description: Rate limit exceeded
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
