> ## Documentation Index
> Fetch the complete documentation index at: https://docs.teamfollowup.ai/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Use the public API base URL: https://api.teamfollowup.ai/api.
> Authenticate public API requests with Authorization: Bearer YOUR_API_KEY.
> Use product-owned terms: agents, campaigns, projects (GoHighLevel sub-accounts), contacts, calls, outcomes, skills, cadences, phone numbers.
> Scope requests by locationId rather than projectName.
> Read the guide linked from each API reference group before recommending an endpoint.

# Remove a voice

> Give up an added voice and free its allowance slot. Any agent still speaking with it is moved to the default voice FIRST, and the response says how many were, so read `reassignedAgents` before reporting the removal as clean. `incompleteAgents` counts the ones that could not be moved and still need attention. Only a voice this agency added can be removed; a shared voice is not yours to remove.

Required API key scope: `voices:write`.



## OpenAPI

````yaml /openapi.yaml delete /api/agent-builder/voices/library/{providerVoiceId}
openapi: 3.1.0
info:
  title: TFUAI Server API
  version: 1.0.0
  description: >-
    API reference for the TFUAI SaaS server.


    All published endpoints are mounted under `/api`. Responses use a standard
    envelope: `{ "success": true, ... }` on success and `{ "success": false,
    "error": "..." }` on failure.


    Product API modules are being launched module by module. This spec currently
    exposes only contracted public modules.


    Authenticate public API requests with an API key in the `Authorization`
    header: `Authorization: Bearer YOUR_API_KEY`.
servers:
  - url: https://api.teamfollowup.ai
    description: Production API origin. Public API paths are under /api.
security: []
tags:
  - name: Agents
    description: Manage voice agents, campaigns, workflows, and outcomes.
  - name: Analytics
    description: >-
      Minimal, non-billing performance summary: volume, conversion, and pickup
      metrics.
  - name: Billing
    description: >-
      Billing for your own agency: balance, spend, transaction history, invoices
      and sub-account wallets; auto-recharge, rebilling, Credit Guard and Stripe
      customers; and, with the billing:charge scope, purchases and charges.
  - name: Calls
    description: Review calls, test runs, and execution history.
  - name: Campaign Workflows
    description: >-
      What runs after a call lands: for each outcome (booked, opted out, asked
      for a callback…), an ordered chain of actions — tag the contact, move a
      pipeline stage, send an SMS, book an appointment. Stored as a graph:
      `nodes` are the actions, `edges` say what follows what, and
      `dispositionEntries` maps each outcome to the node its chain starts at.


      **Pick the narrowest endpoint that does the job.**


      | To | Call | |

      | --- | --- | --- |

      | See what fires per outcome | `GET .../workflow/digest` | Reads as plain
      text, no graph walking |

      | Add steps to an outcome | `POST .../outcomes/{outcome}/nodes` | Server
      derives node ids, edge ids, handles, layout |

      | Change a message, tag or setting | `PATCH .../workflow` | Merges;
      carries no graph, so it cannot damage one |

      | Remove one step | `DELETE .../nodes/{nodeId}` | Also re-links the chain
      around it |

      | Author or replace the whole graph | `PUT .../workflow` | Replaces
      everything you send |


      `PUT` is the only one that can re-wire, position nodes, build an `if`,
      save an unconfigured draft, or copy a whole workflow — and the only one
      that can overwrite a change someone else made after you read it. Use it
      when you are genuinely authoring the graph, and send `expectedVersion`
      when you do. For everything else the narrower endpoints are both easier
      and safer.
  - name: Contacts
    description: Contact list, filters, contact call history, and do-not-call actions.
  - name: GHL
    description: CRM variables and contact helpers used by agent and campaign setup flows.
  - name: Phone Numbers
    description: >-
      Caller ID pool, number search, assignment, movement, and release
      endpoints.
  - name: Power Dialer
    description: >-
      Power Dialer queue, lead cadence, callback, parked lead, and campaign
      schedule endpoints.
  - name: Projects
    description: >-
      Project management endpoints: list, update, disconnect, configure project
      campaigns, and validate setup.
  - name: Skills and Tools
    description: Manage reusable agent behaviors and in-call tool descriptions.
  - name: Split Testing
    description: >-
      Split live campaign traffic across agent variants and shift the weights
      between them.
  - name: Voices
    description: Voice catalogue endpoints for choosing the voice used by an agent.
paths:
  /api/agent-builder/voices/library/{providerVoiceId}:
    delete:
      tags:
        - Voices
      summary: Remove a voice
      description: >-
        Give up an added voice and free its allowance slot. Any agent still
        speaking with it is moved to the default voice FIRST, and the response
        says how many were, so read `reassignedAgents` before reporting the
        removal as clean. `incompleteAgents` counts the ones that could not be
        moved and still need attention. Only a voice this agency added can be
        removed; a shared voice is not yours to remove.


        Required API key scope: `voices:write`.
      operationId: remove-voice-from-library
      parameters:
        - name: providerVoiceId
          in: path
          required: true
          schema:
            type: string
            minLength: 1
          description: >-
            The voice id as the speech provider knows it: the id used when the
            voice was added.
          example: EXAVITQu4vr4xnSDxMaL
      responses:
        '200':
          description: Voice removed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VoicesRemoveVoiceResponse'
              examples:
                default:
                  value:
                    success: true
                    voices: []
                    used: 0
                    limit: 5
                    remaining: 5
                    reassignedAgents: 2
                    incompleteAgents: 0
        '400':
          description: >-
            The request is malformed (`BadRequest`), or the library refused it
            (`VALIDATION`), for example because the voice is already in your
            library.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VoicesErrorResponse'
              examples:
                validation:
                  value:
                    success: false
                    error: VALIDATION
                    message: That voice is already in your library.
                badRequest:
                  value:
                    success: false
                    error: BadRequest
                    message: voiceId required
        '401':
          description: Missing or invalid authentication.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VoicesErrorResponse'
              examples:
                default:
                  value:
                    success: false
                    error: Unauthorized
                    message: Authentication required.
        '403':
          description: Authenticated but not permitted to use the voice endpoints.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VoicesErrorResponse'
              examples:
                default:
                  value:
                    success: false
                    error: Forbidden
                    message: You do not have access to voice catalogue endpoints.
        '404':
          description: The voice is not in your library.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VoicesErrorResponse'
              examples:
                default:
                  value:
                    success: false
                    error: NOT_FOUND
                    message: That voice is not in your library.
        '429':
          description: Rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VoicesErrorResponse'
              examples:
                default:
                  value:
                    success: false
                    error: TooManyRequests
                    message: Too many requests, please try again later.
        '500':
          description: Unexpected server error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VoicesErrorResponse'
              examples:
                default:
                  value:
                    success: false
                    error: InternalError
                    message: Unexpected server error.
      security:
        - ApiKeyAuth: []
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |-
            curl --request DELETE \
              --url https://api.teamfollowup.ai/api/agent-builder/voices/library/{providerVoiceId} \
              --header 'Authorization: Bearer YOUR_API_KEY'
components:
  schemas:
    VoicesRemoveVoiceResponse:
      type: object
      additionalProperties: false
      required:
        - success
        - voices
        - used
        - limit
        - remaining
        - reassignedAgents
        - incompleteAgents
      description: The library after the removal, plus what had to be moved off the voice.
      properties:
        success:
          type: boolean
        voices:
          type: array
          items:
            $ref: '#/components/schemas/VoicesLibraryVoice'
        used:
          type: integer
          minimum: 0
          example: 0
        limit:
          type:
            - integer
            - 'null'
          minimum: 0
          example: 5
        remaining:
          type:
            - integer
            - 'null'
          minimum: 0
          example: 5
        reassignedAgents:
          type: integer
          minimum: 0
          description: >-
            Agents that were speaking with this voice and have been moved to the
            default one. Reported so the caller can say so rather than leaving
            it to be discovered on the next call.
          example: 2
        incompleteAgents:
          type: integer
          minimum: 0
          description: >-
            Agents that could NOT be moved. The removal still succeeded; this is
            the only signal that one of them still needs attention, so treat a
            non-zero value as work to do rather than noise.
          example: 0
    VoicesErrorResponse:
      type: object
      additionalProperties: {}
      required:
        - success
        - error
        - message
      properties:
        success:
          type: boolean
        error:
          type: string
          description: >-
            Machine-readable error code. The catalogue reads answer `BadRequest`
            and `NotFound`. The voice library answers `VALIDATION`, `NOT_FOUND`,
            `FORBIDDEN`, `VOICE_ALLOWANCE` (the plan's voice allowance is used
            up), `VOICE_CAPACITY` (new voices are temporarily unavailable) and
            `VOICE_ALREADY_SHARED` (the voice is already on the account; see
            `references`).
          example: NotFound
        message:
          type: string
          description: Human-readable explanation safe to show to an operator.
          example: Voice "custom_voice_missing" not found.
        references:
          type: object
          additionalProperties: false
          description: >-
            Sent only with `VOICE_ALREADY_SHARED`: what to use instead of
            adding.
          properties:
            voiceId:
              type: string
              description: >-
                The id of the voice already on the account. Select it on the
                agent rather than adding the voice again.
              example: custom_voice_9b1f2a7c4d3e5f6a8b0c1d2e3f
    VoicesLibraryVoice:
      type: object
      additionalProperties: false
      required:
        - providerVoiceId
        - displayName
        - addedAt
        - voiceIds
      description: One voice the agency added for itself.
      properties:
        providerVoiceId:
          type: string
          description: >-
            The voice id as the speech provider knows it. This is the id to send
            when removing the voice or asking what removing it would affect.
          example: EXAVITQu4vr4xnSDxMaL
        displayName:
          type:
            - string
            - 'null'
          description: >-
            What this voice is called in the picker. Null when the provider's
            own name is used.
          example: Sarah (warm)
        addedAt:
          type:
            - string
            - 'null'
          format: date-time
          example: '2026-09-04T11:20:00.000Z'
        voiceIds:
          type: array
          items:
            type: string
          description: >-
            The ids to select this voice on an agent. Plural because the voice
            is held in every library the agency's agents are served from, and
            only the copy in a given agent's library will play. It still counts
            as one voice against the allowance, however many copies it takes.
          example:
            - custom_voice_9b1f2a7c4d3e5f6a8b0c1d2e3f
  securitySchemes:
    ApiKeyAuth:
      type: http
      scheme: bearer
      bearerFormat: API key
      description: 'Send your API key as `Authorization: Bearer YOUR_API_KEY`.'

````