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

# List voices and voice previews

> List available speech voices, your saved custom voices, playable unexpired previews, and your voice creation allowances.

List available speech voices, your saved custom voices, playable unexpired previews, and your voice creation allowances.

```http theme={null}
POST https://api.voicecheap.ai/v1/actions/voices_list
```

## Authentication and permissions

<ParamField header="x-api-key" type="string" required>
  Send a VoiceCheap API key in this header. Authorization: Bearer with the same API key is also supported. OAuth access tokens are accepted only by
  MCP, not by this REST endpoint.
</ParamField>

Required permissions: `voices:read`.

An active paid subscription is required. Permissions do not change team roles, resource ownership, media credits, or plan limits.

## Parameters

Send an empty JSON object. This action has no input fields.

<Accordion title="Complete input schema">
  The JSON Schema below preserves the exact field names, nested types, defaults, bounds, and accepted values exposed by discovery. Additional cross-field rules are listed in the operation notes.

  ```json theme={null}
  {
    "type": "object",
    "properties": {},
    "additionalProperties": false
  }
  ```
</Accordion>

## Request examples

Replace example resource identifiers and media keys with values returned for your account. Keep the request identifier stable when retrying the same mutation.

<RequestExample>
  ```bash cURL theme={null}
  curl --request POST 'https://api.voicecheap.ai/v1/actions/voices_list' \
    --header "x-api-key: $VOICECHEAP_API_KEY" \
    --header 'Content-Type: application/json' \
    --data '{}'
  ```

  ```javascript JavaScript theme={null}
  const input = {};
  const response = await fetch('https://api.voicecheap.ai/v1/actions/voices_list', {
    method: 'POST',
    headers: {
      'x-api-key': process.env.VOICECHEAP_API_KEY,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(input),
  });
  const body = await response.json();
  if (!response.ok) throw new Error(body.code + ': ' + body.message);
  console.log(body);
  ```

  ```python Python theme={null}
  import os
  import requests

  response = requests.post(
      "https://api.voicecheap.ai/v1/actions/voices_list",
      headers={"x-api-key": os.environ["VOICECHEAP_API_KEY"]},
      json={},
      timeout=120,
  )
  body = response.json()
  if not response.ok:
      raise RuntimeError(f"{body.get('code')}: {body.get('message')}")
  print(body)
  ```
</RequestExample>

## Response

A successful first execution returns HTTP 200 with the operation result under data. A replay may return saved request state instead. The example shows one supported response, not every optional field.

Available TTS catalog voices and owned saved custom voices, saved-slot allowance, active unsaved previews, and voice creation allowances.

<ResponseExample>
  ```json HTTP 200 theme={null}
  {
    "data": {
      "voices": [
        {
          "accent": "original",
          "id": "clone:33333333-3333-4333-8333-333333333333",
          "name": "Studio narrator",
          "previewUrl": "https://files.example.com/saved-narrator.mp3",
          "source": "clone"
        },
        {
          "id": "933563129e564b19a115bedd57b7406a",
          "name": "Sarah",
          "accent": "english",
          "gender": "female",
          "style": "conversational",
          "previewFileName": "sarah-en.mp3",
          "source": "catalog"
        }
      ],
      "cloneUsage": {
        "canClone": true,
        "limit": 10,
        "remaining": 9,
        "used": 1
      },
      "voicePreviews": [
        {
          "id": "44444444-4444-4444-8444-444444444444",
          "kind": "clone",
          "name": "Studio narrator",
          "previewUrl": "https://files.example.com/narrator-preview.mp3",
          "expiresAt": 1792238400000,
          "durationSeconds": 10
        }
      ],
      "creationUsage": {
        "cloneTrial": {
          "limit": 1,
          "used": 1,
          "remaining": 0
        },
        "design": {
          "limit": 5,
          "used": 0,
          "remaining": 5,
          "resetsAt": 1792195200000
        },
        "previewExpiresAfterHours": 24
      }
    }
  }
  ```
</ResponseExample>

## Result fields

| Field | Description |
| - | - |
| `data.voices` | Owned saved TTS voices followed by available catalog voices. |
| `data.voices[].id` | TTS selection ID for tts\_generate; custom values use clone:\<UUID>. |
| `data.voices[].name` | Voice display name. |
| `data.voices[].source` | catalog or clone. |
| `data.voices[].accent` | Voice accent; original for custom voices. |
| `data.voices[].gender` | Optional catalog voice gender. |
| `data.voices[].style` | Optional catalog voice delivery style. |
| `data.voices[].previewFileName` | Optional bundled catalog preview filename; it is not a download URL. |
| `data.voices[].previewUrl` | Optional playable URL; custom voice URLs are temporary. |
| `data.cloneUsage.canClone` | Whether the current plan permits saved custom TTS voices; inspect remaining for available slots. |
| `data.cloneUsage.limit` | Plan limit for saved custom TTS voice slots. |
| `data.cloneUsage.used` | Occupied TTS voice slots, including reserved creations. |
| `data.cloneUsage.remaining` | Available saved TTS voice slots. |
| `data.voicePreviews` | All currently active, unsaved previews for this account, including candidates from earlier requests. |
| `data.voicePreviews[].id` | Preview UUID v4 used by voices\_preview\_get and voices\_save\_preview. |
| `data.voicePreviews[].kind` | clone or design. |
| `data.voicePreviews[].name` | Preview display name; designed candidates append a number to the requested name. |
| `data.voicePreviews[].previewUrl` | Temporary playable audio URL. Request a fresh URL with voices\_preview\_get while the preview remains active. |
| `data.voicePreviews[].expiresAt` | Preview expiry as a Unix timestamp in milliseconds. |
| `data.voicePreviews[].durationSeconds` | Preview audio duration in seconds. |
| `data.creationUsage.cloneTrial` | Lifetime clone preview trial allowance with limit, used, and remaining. |
| `data.creationUsage.design` | Daily voice design allowance with limit, used, remaining, and resetsAt in Unix milliseconds. |
| `data.creationUsage.previewExpiresAfterHours` | Lifetime of an unsaved preview in hours, currently 24. |

## Operation notes

* The example catalog is shortened. The action returns the available TTS library with saved custom voices before catalog entries.
* Use voices\[].id in tts\_generate. Saved voices use clone:\<UUID>; catalog IDs are opaque. These IDs are separate from dubbing\_voices\_list.
* Catalog entries include accent, gender, style, and previewFileName; previewUrl is optional. Saved custom entries include accent: original, source: clone, and a temporary previewUrl.
* canClone indicates whether the plan supports saved custom TTS voices; remaining indicates free slots. Reserved creations can count toward used.
* voicePreviews includes only owned, unsaved, ready candidates that have not expired. A preview lasts 24 hours; its playable URL can expire sooner.
* cloneTrial is a lifetime allowance of one clone preview. Paid plans have five design requests per UTC day; each successful design creates two candidates. creationUsage reports the current allowance and reset time.
* Speech history and custom voices belong to the authenticated account. Team billing does not grant access to another member’s speech or voices.

## Usage

Each successful invocation consumes one monthly API/MCP call. Media credits and the operation's own generation allowances also apply.

## Errors

| HTTP status | Code | Meaning or recovery |
| - | - | - |
| 400 | `CREDENTIAL_IN_QUERY` | Credentials were supplied in an access\_token or api\_key query parameter. Send credentials in headers. |
| 400 | `VALIDATION_ERROR` | The input does not match the action schema; inspect details for field errors. |
| 401 | `API_KEY_EXPIRED` | The API key has expired. |
| 401 | `INVALID_API_KEY` | Provide a valid, unexpired API key. |
| 401 | `INVALID_CREDENTIAL` | The Authorization header is malformed or conflicts with x-api-key. |
| 401 | `MISSING_CREDENTIAL` | No usable header credential was supplied, or it exceeded 4096 characters. |
| 401 | `USER_NOT_FOUND` | The credential's account no longer exists. |
| 403 | `AMBIGUOUS_TEAM_API_KEY` | The credential's user belongs to more than one team, so the billing context is ambiguous. |
| 403 | `INSUFFICIENT_SCOPE` | Grant every required permission or choose another credential. |
| 403 | `INTEGRATION_PLAN_UNSUPPORTED` | The account's integration limits could not be verified. |
| 403 | `SUBSCRIPTION_REQUIRED` | Use an active paid subscription. |
| 403 | `TEAM_OWNER_NOT_FOUND` | The effective team owner account could not be found. |
| 404 | `USER_NOT_FOUND` | The authenticated account no longer exists. |
| 429 | `INTEGRATION_MONTHLY_LIMIT_REACHED` | Wait for the monthly reset or change plan. |
| 429 | `INTEGRATION_RATE_LIMIT_REACHED` | Wait for Retry-After when present and use backoff. |
| 500 | `INTERNAL_ERROR` | Check saved request state and resource history before deciding to retry a mutation. |
| 503 | `SERVER_RESTARTING` | The server is restarting. Retry shortly and keep the same request identifier for a mutation. |

```json theme={null}
{
  "code": "INSUFFICIENT_SCOPE",
  "message": "This credential does not permit the requested action.",
  "status": 403,
  "details": {
    "requiredScopes": ["voices:read"]
  }
}
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.