openapi: 3.0.3
info:
  title: SOAT API Keys API
  version: 1.0.0
  description: API for managing project-scoped API keys with optional policy attachments
  contact:
    name: SOAT Team
    url: https://github.com/ttoss/soat
servers:
  - url: '{baseUrl}'
    description: Base URL of your SOAT deployment (e.g. https://your-soat.com or http://localhost:5047)
    variables:
      baseUrl:
        description: The base URL of your SOAT deployment
        default: http://localhost:5047
tags:
  - name: API Keys
    description: Manage API keys
security:
  - bearerAuth: []
paths:
  /api/v1/api-keys:
    get:
      tags:
        - API Keys
      summary: List API keys
      description: >
        Lists API keys accessible to the caller.
        - JWT admin: returns all API keys.
        - JWT regular user: returns only the user's own API keys.
        - API key: returns only API keys scoped to the key's project.
      operationId: listApiKeys
      security:
        - bearerAuth: []
      responses:
        '200':
          description: List of API keys
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ApiKeyRecord'
        '401':
          description: Unauthorized
    post:
      tags:
        - API Keys
      summary: Create an API key
      description: >
        Creates a new API key for the authenticated user.
        - `project_id` is required: every key is scoped to exactly one project.
        - If `policy_ids` is provided, the key's effective permissions are the intersection of the user's policies and the key's policies.
        - Otherwise the key inherits the user's permissions, confined to the key's project.
      operationId: createApiKey
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
                - project_id
              properties:
                name:
                  type: string
                  description: Key name for identification
                  example: CI/CD Pipeline
                project_id:
                  type: string
                  description: Project ID this key is scoped to. Required — keys cannot span projects.
                  example: proj_V1StGXR8Z5jdHi6B
                  x-soat-ref: projects
                policy_ids:
                  x-soat-ref: policies
                  type: array
                  items:
                    type: string
                  description: Optional list of policy IDs to attach. Key permissions become the intersection of user policies and these policies.
                  example: ['pol_V1StGXR8Z5jdHi6B']
      responses:
        '201':
          description: API key created successfully. The raw key value is only returned once.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiKeyCreated'
        '400':
          description: Bad request (missing name, invalid project or policy IDs)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
  /api/v1/api-keys/{api_key_id}:
    get:
      tags:
        - API Keys
      summary: Get an API key
      description: Returns details of an API key. Only the owner or an admin can access it.
      operationId: getApiKey
      parameters:
        - name: api_key_id
          in: path
          required: true
          description: API key public ID (key_ prefix)
          schema:
            type: string
            example: key_V1StGXR8Z5jdHi6B
      responses:
        '200':
          description: API key details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiKeyRecord'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden (not the key owner or admin)
        '404':
          description: API key not found
    put:
      tags:
        - API Keys
      summary: Update an API key
      description: Updates an API key's name, project scope, or policies. The project scope can be changed to another project but never cleared. Only the owner or an admin can update it.
      operationId: updateApiKey
      parameters:
        - name: api_key_id
          in: path
          required: true
          description: API key public ID (key_ prefix)
          schema:
            type: string
            example: key_V1StGXR8Z5jdHi6B
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  example: Updated Key Name
                project_id:
                  x-soat-ref: projects
                  type: string
                  description: Re-scope the key to a different project. Cannot be null — keys are always project-scoped.
                  example: proj_V1StGXR8Z5jdHi6B
                policy_ids:
                  x-soat-ref: policies
                  type: array
                  items:
                    type: string
                  description: Replace the key's policy list (empty array removes all)
                  example: ['pol_V1StGXR8Z5jdHi6B']
      responses:
        '200':
          description: API key updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiKeyRecord'
        '400':
          description: Bad request (invalid project or policy IDs)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden (not the key owner or admin)
        '404':
          description: API key not found
    delete:
      tags:
        - API Keys
      summary: Delete an API key
      description: Deletes an API key. Only the owner or an admin can delete it.
      operationId: deleteApiKey
      parameters:
        - name: api_key_id
          in: path
          required: true
          description: API key public ID (key_ prefix)
          schema:
            type: string
            example: key_V1StGXR8Z5jdHi6B
      responses:
        '204':
          description: API key deleted successfully
        '401':
          description: Unauthorized
        '403':
          description: Forbidden (not the key owner or admin)
        '404':
          description: API key not found
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: JWT token or sk_ api key
  schemas:
    ApiKeyRecord:
      type: object
      properties:
        id:
          type: string
          description: Public API key ID (key_ prefix)
          example: key_V1StGXR8Z5jdHi6B
        name:
          type: string
          example: CI/CD Pipeline
        key_prefix:
          type: string
          description: First 8 characters of the raw key for identification
          example: sk_a1b2c3
        user_id:
          x-soat-ref: users
          type: string
          description: Owner user public ID
          example: user_V1StGXR8Z5jdHi6B
        project_id:
          x-soat-ref: projects
          type: string
          description: The project this key is scoped to
          example: proj_V1StGXR8Z5jdHi6B
        policy_ids:
          x-soat-ref: policies
          type: array
          items:
            type: string
          description: Public IDs of policies attached to this key
          example: ['pol_V1StGXR8Z5jdHi6B']
        created_at:
          type: string
          format: date-time
          example: '2024-01-01T00:00:00.000Z'
        updated_at:
          type: string
          format: date-time
          example: '2024-01-01T00:00:00.000Z'
    ApiKeyCreated:
      allOf:
        - $ref: '#/components/schemas/ApiKeyRecord'
        - type: object
          properties:
            key:
              type: string
              description: The raw API key value (only returned once at creation). Use as Bearer token.
              example: sk_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4
    ErrorResponse:
      type: object
      properties:
        error:
          type: string
          example: An error occurred
