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