Coval Audio API

Upload audio for evaluation and access conversation audio files

OpenAPI Specification

coval-audio-api-openapi.yml Raw ↑
openapi: 3.0.3
info:
  title: Coval Agents Audio API
  version: 1.0.0
  description: '

    Manage configurations for simulations and evaluations.

    '
  contact:
    name: Coval API Support
    email: support@coval.dev
    url: https://docs.coval.ai
  license:
    name: Proprietary
    url: https://coval.dev/terms
servers:
- url: https://api.coval.dev/v1
  description: Production API
security:
- ApiKeyAuth: []
tags:
- name: Audio
  description: Upload audio for evaluation and access conversation audio files
paths:
  /audio:upload:
    post:
      tags:
      - Audio
      summary: Upload audio
      description: 'Issue an opaque `upload_id` and a short-lived presigned PUT URL for direct audio upload.

        '
      operationId: createAudioUpload
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateAudioUploadRequest'
            examples:
              wavDefault:
                summary: Default WAV upload (no body required)
                value: {}
              mp3Explicit:
                summary: MP3 upload with size hint
                value:
                  content_type: audio/mp3
                  expected_size_bytes: 12582912
      responses:
        '200':
          description: Presigned upload URL issued
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateAudioUploadResponse'
              examples:
                success:
                  summary: Successful issuance
                  value:
                    upload_id: upl_01HRAB8N9G7Q4Y3K2J5W6X1ZTC
                    upload_url: https://uploads.coval.dev/8fce4e70/upl_01HRAB8N9G7Q4Y3K2J5W6X1ZTC?signature=...
                    expires_at: '2025-11-03T15:32:00Z'
                    max_size_bytes: 104857600
                    content_type: audio/wav
        '400':
          $ref: '#/components/responses/InvalidArgument'
        '401':
          $ref: '#/components/responses/Unauthenticated'
        '500':
          $ref: '#/components/responses/InternalError'
  /conversations/{conversation_id}/audio:
    get:
      tags:
      - Audio
      summary: Get conversation audio
      description: 'Retrieve a presigned URL for downloading conversation audio.

        '
      operationId: getConversationAudio
      parameters:
      - name: conversation_id
        in: path
        description: Unique conversation identifier
        required: true
        schema:
          type: string
          minLength: 22
          maxLength: 26
        example: gk3jK9mPq2xRt5vW8yZaBc
      responses:
        '200':
          description: Presigned audio URL
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GetConversationAudioResponse'
              examples:
                success:
                  summary: Presigned URL returned
                  value:
                    audio_url: https://coval-audio-prod.s3.us-east-2.amazonaws.com/audio/2025/11/03/gk3jK9mPq2xRt5vW8yZaBc.wav?X-Amz-Signature=...
                    peaks_url: https://coval-audio-prod.s3.us-east-2.amazonaws.com/audio/2025/11/03/gk3jK9mPq2xRt5vW8yZaBc.peaks.json?X-Amz-Signature=...
                    conversation_id: gk3jK9mPq2xRt5vW8yZaBc
                    url_expires_in_seconds: 3600
        '404':
          description: Conversation not found or has no audio
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                notFound:
                  summary: Conversation not found
                  value:
                    error:
                      code: NOT_FOUND
                      message: Conversation not found
                      details: []
                noAudio:
                  summary: No audio file available
                  value:
                    error:
                      code: NOT_FOUND
                      message: Conversation has no audio file available
                      details:
                      - field: audio
                        description: No audio was provided when this conversation was submitted
        '401':
          $ref: '#/components/responses/Unauthenticated'
        '500':
          $ref: '#/components/responses/InternalError'
components:
  schemas:
    GetConversationAudioResponse:
      type: object
      required:
      - audio_url
      - conversation_id
      - url_expires_in_seconds
      properties:
        audio_url:
          type: string
          format: uri
          description: 'Presigned S3 URL for downloading audio file.


            URL is valid for duration specified in url_expires_in_seconds.

            No authentication required to access this URL.

            '
          example: https://coval-audio-prod.s3.us-east-2.amazonaws.com/audio/2025/11/03/gk3jK9mPq2xRt5vW8yZaBc.wav?X-Amz-Algorithm=AWS4-HMAC-SHA256&...
        peaks_url:
          type: string
          format: uri
          nullable: true
          description: 'Presigned S3 URL for precomputed waveform peaks JSON (valid for 1 hour).

            Contains an array of up to 800 [min, max] amplitude pairs for waveform visualization.

            Null for older recordings without precomputed peaks. May return 404 if peaks

            were not generated for this recording.

            '
          example: https://coval-audio-prod.s3.us-east-2.amazonaws.com/audio/2025/11/03/gk3jK9mPq2xRt5vW8yZaBc.peaks.json?X-Amz-Algorithm=AWS4-HMAC-SHA256&...
        conversation_id:
          type: string
          description: Conversation identifier
          example: gk3jK9mPq2xRt5vW8yZaBc
        url_expires_in_seconds:
          type: integer
          description: Number of seconds until presigned URL expires
          example: 3600
      description: 'Response containing presigned URL for audio download.

        '
    CreateAudioUploadRequest:
      type: object
      properties:
        content_type:
          type: string
          enum:
          - audio/wav
          - audio/mp3
          default: audio/wav
          description: 'MIME type of the audio that will be uploaded. MUST match the

            `Content-Type` header on your subsequent `PUT` request, otherwise

            the upload will be rejected.

            '
          example: audio/wav
        expected_size_bytes:
          type: integer
          minimum: 1
          maximum: 104857600
          description: 'Optional client-declared size hint in bytes. The presigned URL

            always enforces the 100 MB hard cap regardless of this value.

            '
          example: 12582912
      description: 'Request body for `POST /v1/audio:upload`. All fields are optional;

        an empty body issues a WAV upload URL.

        '
    ErrorResponse:
      type: object
      required:
      - error
      properties:
        error:
          type: object
          required:
          - code
          - message
          properties:
            code:
              type: string
              description: Error code
              enum:
              - INVALID_ARGUMENT
              - UNAUTHENTICATED
              - NOT_FOUND
              - ALREADY_EXISTS
              - PAYLOAD_TOO_LARGE
              - INTERNAL_ERROR
              example: INVALID_ARGUMENT
            message:
              type: string
              description: Human-readable error message
              example: Missing required input data
            details:
              type: array
              items:
                $ref: '#/components/schemas/ErrorDetail'
              description: Additional error details
              default: []
    CreateAudioUploadResponse:
      type: object
      required:
      - upload_id
      - upload_url
      - expires_at
      - max_size_bytes
      - content_type
      properties:
        upload_id:
          type: string
          pattern: ^upl_[0-9A-HJKMNP-TV-Z]{26}$
          description: 'Opaque upload identifier. Pass this as `upload_id` on

            `POST /v1/conversations:submit` after you''ve uploaded bytes to

            `upload_url`.

            '
          example: upl_01HRAB8N9G7Q4Y3K2J5W6X1ZTC
        upload_url:
          type: string
          format: uri
          description: 'Short-lived presigned PUT URL. PUT the audio bytes here with

            the matching `Content-Type` header from `content_type`.

            '
          example: https://uploads.coval.dev/8fce4e70/upl_01HRAB8N9G7Q4Y3K2J5W6X1ZTC?signature=...
        expires_at:
          type: string
          format: date-time
          description: 'Absolute UTC timestamp at which the presigned URL stops being

            valid. The `upload_id` itself remains resolvable for 7 days from

            issuance, but you cannot upload bytes after this timestamp.

            '
          example: '2025-11-03T15:32:00Z'
        max_size_bytes:
          type: integer
          description: Hard upper bound on the uploaded payload size, in bytes.
          example: 104857600
        content_type:
          type: string
          enum:
          - audio/wav
          - audio/mp3
          description: 'Content-Type the client must send on the PUT request. Equal to

            the `content_type` requested (or default `audio/wav`).

            '
          example: audio/wav
      description: 'Response for `POST /v1/audio:upload`.

        '
    ErrorDetail:
      type: object
      properties:
        field:
          type: string
          description: Field that caused the error
          example: transcript
        description:
          type: string
          description: Detailed description of the error
          example: At least one of transcript, audio, or audio_url must be provided
  responses:
    InternalError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: INTERNAL_ERROR
              message: An internal error occurred while processing the request
              details: []
    InvalidArgument:
      description: Invalid request arguments
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            missingInput:
              summary: Missing required input
              value:
                error:
                  code: INVALID_ARGUMENT
                  message: Missing required input data
                  details:
                  - field: transcript
                    description: At least one of transcript or audio_url must be provided
            invalidFilter:
              summary: Invalid filter expression
              value:
                error:
                  code: INVALID_ARGUMENT
                  message: Invalid filter expression
                  details:
                  - field: filter
                    description: 'Unknown field ''invalid_field''. Valid fields: status, create_time, occurred_at, external_conversation_id'
            invalidPageSize:
              summary: Invalid page_size
              value:
                error:
                  code: INVALID_ARGUMENT
                  message: Invalid page_size
                  details:
                  - field: page_size
                    description: page_size must be between 1 and 250
            audioFormatInvalid:
              summary: Unsupported audio format
              value:
                error:
                  code: INVALID_ARGUMENT
                  message: 'Unsupported audio format: MP4. Only WAV and MP3 files are supported.'
                  details:
                  - field: audio_url
                    description: Audio format detected as MP4 via magic byte analysis. Convert to WAV or MP3.
            audioTooShort:
              summary: Audio duration too short
              value:
                error:
                  code: INVALID_ARGUMENT
                  message: 'Audio too short: 3.0 seconds. Minimum duration is 5 seconds.'
                  details:
                  - field: audio_url
                    description: Audio file duration is below the 5 second minimum requirement
            audioTooLong:
              summary: Audio duration too long
              value:
                error:
                  code: INVALID_ARGUMENT
                  message: 'Audio too long: 75.0 minutes. Maximum duration is 60 minutes.'
                  details:
                  - field: audio_url
                    description: Audio file duration exceeds the 1 hour maximum limit
            audioTooLarge:
              summary: Audio file size too large
              value:
                error:
                  code: INVALID_ARGUMENT
                  message: 'Audio file too large: 250.0 MB. Maximum size is 200 MB.'
                  details:
                  - field: audio_url
                    description: Audio file size exceeds 200 MB limit
            audioEmpty:
              summary: Empty audio file
              value:
                error:
                  code: INVALID_ARGUMENT
                  message: Audio file is empty.
                  details:
                  - field: audio_url
                    description: Audio file contains no data
            audioCorrupt:
              summary: Corrupt or invalid audio file
              value:
                error:
                  code: INVALID_ARGUMENT
                  message: Invalid or corrupt audio file. Unable to read audio metadata.
                  details:
                  - field: audio_url
                    description: Audio file headers could not be read or are corrupted
    Unauthenticated:
      description: Missing or invalid API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: UNAUTHENTICATED
              message: Invalid or missing API key
              details: []
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
      description: API key for authentication
x-visibility: external