openapi: 3.1.0
info:
  title: Client-Side Authentication & API
  version: "1.0.0"
  description: |
    Endpoints for managing and using client-side tokens (JWT). 
    Generate or revoke tokens with your org-level API key, 
    then call the client-specific endpoints using the JWT.

servers:
  - url: "https://platform-api.wisprflow.ai/api/v1/dash"
    description: Production server

paths:
  /generate_access_token:
    post:
      summary: Generate a new client token (JWT)
      description: |
        Use your org-level API key (`Bearer fl-xxxxxx`) to create a 
        JWT token for a specific client. The token can be used at 
        client-facing endpoints.
      operationId: generateAccessToken
      security:
        - bearerAuthOrg: []  # Use an org-level key
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - client_id
                - duration_secs
              properties:
                client_id:
                  type: string
                  description: Identifier for the client
                duration_secs:
                  type: integer
                  description: Token lifetime in seconds
                metadata:
                  type: object
                  additionalProperties: true
                  description: Optional metadata to store with the token
      responses:
        "200":
          description: Returns the newly generated token
          content:
            application/json:
              schema:
                type: object
                properties:
                  access_token:
                    type: string
                    description: The JWT token
                  expires_in:
                    type: integer
                    description: How long the token remains valid (in seconds)
        "401":
          description: Unauthorized (invalid org-level API key)
        "500":
          description: Internal server error

  /revoke_token:
    post:
      summary: Revoke a specific client token
      description: |
        Use your org-level API key to revoke a single JWT token, 
        rendering it invalid for future requests.
      operationId: revokeUserToken
      security:
        - bearerAuthOrg: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - access_token
              properties:
                access_token:
                  type: string
                  description: The JWT token to revoke
      responses:
        "200":
          description: Token revoked successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  message:
                    type: string
                    example: "Token successfully revoked"
        "401":
          description: Unauthorized (invalid org-level API key)
        "404":
          description: Token not found
        "500":
          description: Internal server error

  /revoke_client_tokens:
    post:
      summary: Revoke all tokens for a specific client
      description: |
        Use your org-level API key to revoke every token associated with
        a particular client_id.
      operationId: revokeClientTokens
      security:
        - bearerAuthOrg: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - client_id
              properties:
                client_id:
                  type: string
                  description: The client ID whose tokens you want to invalidate
      responses:
        "200":
          description: All tokens revoked successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  message:
                    type: string
                    example: "All tokens for client successfully revoked"
        "401":
          description: Unauthorized (invalid org-level API key)
        "404":
          description: No tokens found for this client
        "500":
          description: Internal server error

  /client_api:
    post:
      summary: Client-side speech-to-text (JWT-based)
      description: |
        Identical to the standard `/api` endpoint, but uses a client token (JWT)
        in the Authorization header instead of an org-level API key.
      operationId: clientApiTranscription
      security:
        - jwtAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - audio
                - properties
              properties:
                audio:
                  type: string
                  description: Base64-encoded audio data (up to 25MB / 6 minutes)
                properties:
                  type: object
                  description: Additional config for transcription
      responses:
        "200":
          description: Successful transcription
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    format: uuid
                  text:
                    type: string
                  detected_language:
                    type: string
                  total_time:
                    type: number
                  generated_tokens:
                    type: integer
        "400":
          description: Bad request
        "401":
          description: Unauthorized (invalid or expired client JWT)
        "413":
          description: Payload too large
        "500":
          description: Internal server error

  /client_ws:
    post:
      summary: Client-side WebSocket audio streaming (JWT-based)
      description: |
        Identical to the standard `/ws` endpoint for real-time audio streaming, but uses a client token (JWT)
        in the query string or header for authentication. The real-time streaming flow follows the same pattern
        of `start`, `append`, and `commit` messages, with partial and final transcription responses.
      operationId: clientWebSocket
      security:
        - jwtAuth: []
      requestBody:
        required: true
        description: Send one of three message types, start, append or commit
        content:
          application/json:
            schema:
              oneOf:
                - $ref: '#/components/schemas/StartMessage'
                - $ref: '#/components/schemas/AppendMessage'
                - $ref: '#/components/schemas/CommitMessage'
      responses:
        '101':
          description: WebSocket connection established successfully.
        '200':
          description: WebSocket message responses, including partial and final transcriptions.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - $ref: '#/components/schemas/ChunkReceivedResponse'
                  - $ref: '#/components/schemas/PartialResponse'
                  - $ref: '#/components/schemas/SessionStartedResponse'
                  - $ref: '#/components/schemas/ErrorResponse'
        '400':
          description: Invalid message format or missing required fields.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized (invalid or expired client JWT)
        '500':
          description: Internal server error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

components:
  securitySchemes:
    bearerAuthOrg:
      type: http
      scheme: bearer
      bearerFormat: "OrganizationKey"
      description: >
        **Org-level key** (format: `Bearer fl-xxxxx`) 
        used to manage client tokens.
    jwtAuth:
      type: http
      scheme: bearer
      bearerFormat: "JWT"
      description: >
        **Client-side token** (format: `Bearer <JWT>`) 
        for calling client endpoints like `/client_api`.

  schemas:
    StartMessage:
      type: object
      required:
        - type
      properties:
        type:
          type: string
          enum: [start]
          description: Indicates the beginning of a WebSocket session.
        properties:
          type: object
          description: Optional API properties for transcription
          properties:
            language:
              type: string
              description: Force a specific language for transcription (e.g. "en")
              default: "en"
            app_type:
              type: string
              description: Type of application using the API
              default: "other"
            dictionary:
              type: array
              description: Custom dictionary for transcription
              items:
                type: string
              default: []
            after_text:
              type: string
              description: Text that comes after the current transcription
              default: ""
            before_text:
              type: string
              description: Text that comes before the current transcription
              default: ""
            selected_text:
              type: string
              description: Currently selected text
              default: ""
    AppendMessage:
      type: object
      required:
        - type
        - audio
        - chunk_number
      properties:
        type:
          type: string
          enum: [append]
          description: Indicates that a new audio chunk is being sent.
        audio:
          type: string
          format: base64
          description: Base64 encoded WAV audio chunk. First chunk should include WAV header (44 bytes), subsequent chunks should only include PCM data.
        volume:
          type: number
          description: Average volume of the chunk. Optional.
        chunk_number:
          type: integer
          description: Sequential number of the audio chunk.
    CommitMessage:
      type: object
      required:
        - type
      properties:
        type:
          type: string
          enum: [commit]
          description: Indicates the end of the WebSocket session and triggers final transcription processing.
    SuccessResponse:
      type: object
      properties:
        status:
          type: string
          enum: [success]
          example: success
        transcript_id:
          type: string
          format: uuid
          description: Unique identifier for the transcription session.
        text:
          type: string
          description: The fully transcribed and formatted text.
        total_time:
          type: number
          description: Total processing time in seconds.
        tokens_used:
          type: integer
          description: Number of tokens used in transcription.
        detected_language:
          type: string
          description: Detected language of the transcription.
          example: 'en'
    ChunkReceivedResponse:
      type: object
      properties:
        status:
          type: string
          enum: [chunk_received]
          example: chunk_received
        chunk:
          type: integer
          description: The sequential number of the chunk that was successfully received.
    PartialResponse:
      type: object
      properties:
        status:
          type: string
          enum: [partial]
          example: partial
        text:
          type: string
          description: Partial transcription text.
        transcript_id:
          type: string
          format: uuid
          description: Unique identifier for the transcription session.
    SessionStartedResponse:
      type: object
      properties:
        status:
          type: string
          enum: [session_started]
          example: session_started
    ErrorResponse:
      type: object
      properties:
        status:
          type: string
          enum: [error]
          example: error
        error:
          type: string
          description: Details of the error encountered.