openapi: 3.0.3 info: title: WellSaid Labs API description: >- The WellSaid Labs API renders text into studio-quality AI voiceover. It exposes streaming text-to-speech (audio returned as an HTTP stream for low time-to-first-byte playback), word-level timing and subtitle rendering, asynchronous clip creation and combination, a catalog of voice avatars, and pronunciation control via replacement libraries and respelling suggestions. All requests authenticate with an X-Api-Key header. WellSaid does not currently support end-user authentication and recommends making requests from an internal or trusted source. API access is gated behind a trial API key and a business plan. Endpoints, request fields, and response shapes here are modeled from the public documentation at docs.wellsaidlabs.com and are honestly approximated where the reference does not publish a full schema. version: '1.0' contact: name: WellSaid Labs url: https://wellsaidlabs.com servers: - url: https://api.wellsaidlabs.com/v1 description: WellSaid Labs API security: - apiKeyAuth: [] tags: - name: Text-to-Speech description: Render text to speech, with streaming audio and word timing. - name: Clips description: Asynchronous clip creation, retrieval, and combination. - name: Voice Avatars description: Catalog of available AI voice avatars and their metadata. - name: Pronunciation description: Replacement libraries and respelling suggestions for pronunciation control. paths: /tts/stream: post: operationId: renderTtsStream tags: - Text-to-Speech summary: Render text to speech (streaming) description: >- Renders the supplied text with the chosen voice avatar and returns the result as a stream of an audio file (MP3), not the finished file, so the client can begin playback with a low time-to-first-byte. Default keys are limited to 1,000 characters per request. Accepts a subset of SSML tags. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/TtsRequest' responses: '200': description: A stream of the rendered audio. content: audio/mpeg: schema: type: string format: binary '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/RateLimited' /word-timing: post: operationId: renderWordTiming tags: - Text-to-Speech summary: Render text to speech with timing information description: >- Renders text to speech and returns the audio together with word-level timing information and subtitles, so captions can be aligned to the generated voiceover. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/TtsRequest' responses: '200': description: Rendered audio with word timing and subtitle data. content: application/json: schema: $ref: '#/components/schemas/WordTimingResponse' '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/RateLimited' /clips: get: operationId: listClips tags: - Clips summary: List recent clips description: Returns a list of recently created text-to-speech clips. responses: '200': description: A list of clips. content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/Clip' '401': $ref: '#/components/responses/Unauthorized' post: operationId: createClip tags: - Clips summary: Create a clip asynchronously description: >- Creates a new text-to-speech clip asynchronously. The clip is rendered in the background; poll the clip by id to retrieve its status and audio. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/TtsRequest' responses: '202': description: The clip was accepted for asynchronous rendering. content: application/json: schema: $ref: '#/components/schemas/Clip' '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/RateLimited' /clips/{clip_id}: get: operationId: getClip tags: - Clips summary: Get a single clip description: Returns information about a single clip, including its render status and audio URL. parameters: - $ref: '#/components/parameters/ClipId' responses: '200': description: The requested clip. content: application/json: schema: $ref: '#/components/schemas/Clip' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' /clips/combine: post: operationId: combineClips tags: - Clips summary: Combine clips into one file description: >- Combines a list of clips into a single audio file, inserting pauses between them. Useful for assembling longer-form voiceover from many rendered segments. requestBody: required: true content: application/json: schema: type: object properties: clip_ids: type: array items: type: string description: The ids of the clips to combine, in order. pause: type: number format: float description: Pause in seconds to insert between clips. required: - clip_ids responses: '200': description: The combined audio file (or a clip referencing it). content: application/json: schema: $ref: '#/components/schemas/Clip' '401': $ref: '#/components/responses/Unauthorized' /avatars: get: operationId: listAvatars tags: - Voice Avatars summary: Get available voice avatars description: >- Lists all available voice avatars with their metadata - the numeric speaker id, avatar name, style, language, accent, descriptive characteristics, and compatible models. responses: '200': description: A list of voice avatars. content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/Avatar' '401': $ref: '#/components/responses/Unauthorized' /replacement-libraries: get: operationId: listReplacementLibraries tags: - Pronunciation summary: List replacement libraries description: Returns the list of available pronunciation replacement libraries. responses: '200': description: A list of replacement libraries. content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/ReplacementLibrary' '401': $ref: '#/components/responses/Unauthorized' post: operationId: createReplacementLibrary tags: - Pronunciation summary: Create a replacement library description: Creates a new replacement library for grouping pronunciation replacements. requestBody: required: true content: application/json: schema: type: object properties: name: type: string description: A human-readable name for the library. required: - name responses: '201': description: The created replacement library. content: application/json: schema: $ref: '#/components/schemas/ReplacementLibrary' '401': $ref: '#/components/responses/Unauthorized' /replacement-libraries/{library_id}: get: operationId: getReplacementLibrary tags: - Pronunciation summary: Get a replacement library description: Returns information about a single replacement library. parameters: - $ref: '#/components/parameters/LibraryId' responses: '200': description: The requested replacement library. content: application/json: schema: $ref: '#/components/schemas/ReplacementLibrary' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' delete: operationId: deleteReplacementLibrary tags: - Pronunciation summary: Delete a replacement library description: Deletes a replacement library and its replacements. parameters: - $ref: '#/components/parameters/LibraryId' responses: '204': description: The replacement library was deleted. '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' /replacement-libraries/{library_id}/replacements: get: operationId: listReplacements tags: - Pronunciation summary: List replacements in a library description: Returns the list of replacements contained in a replacement library. parameters: - $ref: '#/components/parameters/LibraryId' responses: '200': description: A list of replacements. content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/Replacement' '401': $ref: '#/components/responses/Unauthorized' post: operationId: createReplacement tags: - Pronunciation summary: Create a replacement description: Creates a new pronunciation replacement in the library. parameters: - $ref: '#/components/parameters/LibraryId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ReplacementInput' responses: '201': description: The created replacement. content: application/json: schema: $ref: '#/components/schemas/Replacement' '401': $ref: '#/components/responses/Unauthorized' /replacement-libraries/{library_id}/replacements/{replacement_id}: get: operationId: getReplacement tags: - Pronunciation summary: Get a replacement description: Returns a single replacement from a library. parameters: - $ref: '#/components/parameters/LibraryId' - $ref: '#/components/parameters/ReplacementId' responses: '200': description: The requested replacement. content: application/json: schema: $ref: '#/components/schemas/Replacement' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' delete: operationId: deleteReplacement tags: - Pronunciation summary: Delete a replacement description: Removes a replacement from a library. parameters: - $ref: '#/components/parameters/LibraryId' - $ref: '#/components/parameters/ReplacementId' responses: '204': description: The replacement was deleted. '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' /respelling-suggestions: get: operationId: getRespellingSuggestions tags: - Pronunciation summary: Get respelling suggestions description: >- Returns respelling suggestions for a word to help coax the correct pronunciation from the voice avatar. parameters: - name: word in: query required: true schema: type: string description: The word to get respelling suggestions for. responses: '200': description: A list of respelling suggestions. content: application/json: schema: type: object properties: data: type: array items: type: string '401': $ref: '#/components/responses/Unauthorized' components: securitySchemes: apiKeyAuth: type: apiKey in: header name: X-Api-Key description: >- API key issued by WellSaid Labs, passed in the X-Api-Key header. Request a trial key from the console; production use requires a business plan. parameters: ClipId: name: clip_id in: path required: true schema: type: string description: The id of the clip. LibraryId: name: library_id in: path required: true schema: type: string description: The id of the replacement library. ReplacementId: name: replacement_id in: path required: true schema: type: string description: The id of the replacement. responses: Unauthorized: description: Missing or invalid X-Api-Key. content: application/json: schema: $ref: '#/components/schemas/Error' NotFound: description: The requested resource was not found. content: application/json: schema: $ref: '#/components/schemas/Error' RateLimited: description: >- Rate limit or monthly character quota exceeded. Inspect the x-rate-limit-* and x-quota-* response headers. content: application/json: schema: $ref: '#/components/schemas/Error' schemas: TtsRequest: type: object properties: text: type: string description: The text to convert to speech. Default keys allow up to 1,000 characters per request. speaker_id: type: string description: The voice avatar (speaker) id to render with, for example "3". model: type: string description: The voice model to use, for example "caruso" or "legacy". required: - text - speaker_id WordTimingResponse: type: object properties: audio_url: type: string description: URL to the rendered audio. subtitles: type: string description: Subtitle text aligned to the audio. words: type: array description: Per-word timing entries. items: type: object properties: word: type: string start: type: number format: float description: Start time in seconds. end: type: number format: float description: End time in seconds. Clip: type: object properties: id: type: string description: The clip id. status: type: string description: Render status of the clip, for example "processing" or "complete". text: type: string speaker_id: type: string audio_url: type: string description: URL to the rendered audio once the clip is complete. created_at: type: string format: date-time Avatar: type: object properties: id: type: integer description: The numeric speaker id used as speaker_id in render requests. name: type: string description: The voice avatar name, for example "Alana B.". style: type: string description: Voice style such as Narration, Promo, Conversational, or Character. language: type: string accent: type: string description: Accent or region, for example "United States" or "England". characteristics: type: array items: type: string description: Descriptive tags such as "Clear", "Crisp", "Focused". models: type: array items: type: string description: Compatible models such as "caruso" and "legacy". ReplacementLibrary: type: object properties: id: type: string name: type: string created_at: type: string format: date-time ReplacementInput: type: object properties: original: type: string description: The original word or phrase to replace. replacement: type: string description: The respelled or substitute pronunciation to speak instead. required: - original - replacement Replacement: type: object properties: id: type: string original: type: string replacement: type: string Error: type: object properties: message: type: string code: type: string