WellSaid Labs Text-to-Speech API

Render text to speech and receive the audio as an HTTP stream for low time-to-first-byte playback, or render with word-level timing and subtitle output. Requests take the text, a speaker_id (voice avatar), and an optional model, authenticate with an X-Api-Key header, and return MP3 audio. Limited by default to 1,000 characters per request.

OpenAPI Specification

wellsaid-labs-openapi.yml Raw ↑
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