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

# Redeem a voice copy token

> Create an independent private copy of the source voice in an allowed destination workspace. Requires voice write permission in the destination workspace; no source-workspace access is needed. Each successful call creates a new voice and counts toward the destination custom-voice limit. Accepts workspace-scoped tokens only.

Copy a custom voice into an allowed destination workspace using a token from [Issue a voice copy token](https://docs.inworld.ai/api-reference/voiceAPI/voiceservice/issue-copy-token.md). Use the destination workspace's API key with voice write permission (`api.dsgnt.voices::rw`). You do not need access to the source workspace.

<Note>
This endpoint accepts workspace-scoped tokens only. Email-based tokens from Portal's **Export Voice** flow cannot be redeemed here.
</Note>

## Copy the voice

Send the token ID in `voiceCopyTokenId`. Use only the final segment of the issued token's `name`, not the full resource name. Set `displayName` to name the copy, or omit it to keep the source voice's display name. A blank display name also keeps the source name.

```bash
curl --request POST 'https://api.inworld.ai/voices/v1/voices:redeemCopyToken' \
  --header "Authorization: Basic $DESTINATION_API_KEY" \
  --header 'Content-Type: application/json' \
  --data '{
    "voiceCopyTokenId":"00000000-0000-4000-8000-000000000001",
    "displayName":"Production narrator"
  }'
```

The API key's workspace is the destination. Its ID must appear in the token's `allowedWorkspaces`.

The response is a voice object. An illustrative response, with optional fields omitted:

```json
{
  "voiceId": "destination-workspace__production-narrator",
  "displayName": "Production narrator",
  "source": "IVC"
}
```

Use the returned `voiceId` in [speech synthesis](https://docs.inworld.ai/api-reference/ttsAPI/texttospeech/synthesize-speech.md) with the destination workspace's API key. The copy is private and independent of the original.

## Redemption requirements

- The token must be less than seven days old and grant access to the destination workspace.
- The source voice must still exist and be available for copying. A deleted or taken-down source cannot be copied.
- The destination workspace must have room within its custom-voice limit. Redemption also requires available credits.

Each successful call creates another voice, even when you reuse the same token. Keep the returned voice ID so you can use the copy without redeeming again.

## API reference

**Endpoint:** `POST https://api.inworld.ai/voices/v1/voices:redeemCopyToken`

### Authorization

- `Authorization` (string; required) — Your [API key](../../../api-reference/introduction). Read permissions are required for GET endpoints. Write permissions are required for POST, PATCH, and DELETE endpoints.
  
   For Basic authentication, please populate `Basic $INWORLD_API_KEY`. You can create a key in one command with the [Inworld CLI](../../../developer-tools/inworld-cli): `inworld workspace add-key`.

### Request body

Content type: `application/json`

- `parent` (string) — Destination workspace in the form workspaces/{workspace}. Omit to use the workspace associated with the API key. The caller needs voice write access to this workspace, which must be on the token allowlist.
- `voiceCopyTokenId` (string; required) — The final segment of the issued token name, not the full resource name. Send it in the request body.
- `displayName` (string) — Display name for the copied voice. If omitted or blank, the source voice display name is kept.

#### Request example

```json
{
  "parent": "string",
  "voiceCopyTokenId": "00000000-0000-4000-8000-000000000001",
  "displayName": "Production narrator"
}
```

### Response

Status: `200`. Content type: `application/json`.

- `voiceId` (string) — Voice ID. SYSTEM voices use a simple name (e.g. `Alex`); IVC voices are workspace-prefixed (`{workspace}__{voice}`).
- `langCode` (enum<string>; options: "EN_US", "ZH_CN", "KO_KR", "JA_JP", "RU_RU", "AUTO", "IT_IT", "ES_ES", "PT_BR", "DE_DE", "FR_FR", "AR_SA", "PL_PL", "NL_NL", "HI_IN", "HE_IL") — Primary language of the voice in upper-snake format (e.g. `EN_US`). Note that when filtering via `lang_code`, you can pass BCP-47 (`en-US`), underscore form (`en_US`), or a language prefix (`en`) — but the response always returns upper-snake.
- `languageCode` (string) — Canonical wire form of the voice's primary language as a single string (e.g. `en-US`, `es-MX`, `vi`). Populated on every read alongside the legacy `langCode` enum. Immutable after creation.
- `displayName` (string) — The human-readable name shown anywhere the voice is listed or selected.
- `description` (string) — Longer blurb that explains the voice's tone, accent, use cases, or other relevant attributes.
- `tags` (string[]) — Free-form labels for filtering, grouping, and discovery (e.g. `british`, `calm`).
- `name` (string) — Resource identifier. Workspace voices use workspaces/{workspace}/voices/{voice}; system and shared voices may use a bare identifier. For synthesis and audio previews, use voiceId unchanged instead of constructing a resource path.
- `source` (enum<string>; options: "SYSTEM", "IVC", "TVD", "PVC", "OTHER") — Voice provenance: SYSTEM (Inworld system voice), IVC (instant voice clone), TVD (voice design), PVC (professional or supplied custom voice), or OTHER. Treat provenance separately from community-sharing and ownership metadata.
- `gender` (enum<string>; options: "male", "female", "neutral", "") — Voice gender (`male`, `female`, `neutral`). Empty string if unspecified. Voices with no gender are excluded when filtering with an explicit `gender =` predicate.
- `ageGroup` (enum<string>; options: "young", "middle_aged", "elderly", "") — Age group of the voice (`young`, `middle_aged`, `elderly`). Empty string if unspecified.
- `categories` (enum<string>[]) — Use-case categories the voice belongs to. Filterable with the `:` (has) operator.
  
  Supported values: `companions`, `enterprise`, `education_training`, `developer_assistants`, `healthcare`, `interactive_media`.
- `promptLanguages` (string[]) — Languages the voice can handle, in BCP-47 format (e.g. `en-US`). May differ from `langCode` for multilingual voices.
- `owned` (boolean) — For a community voice result, whether the calling workspace owns the voice. Interpret alongside community-sharing metadata; this field is not a general test for whether synthesis is permitted.

### Response examples

#### 200: default_response

```json
{
  "voiceId": "destination-workspace__production-narrator",
  "displayName": "Production narrator",
  "source": "IVC"
}
```

#### default: default_response

```json
{
  "code": 0,
  "message": "string",
  "details": [
    {
      "@type": "string"
    }
  ]
}
```

### Code examples

#### cURL

```bash
curl --request POST 'https://api.inworld.ai/voices/v1/voices:redeemCopyToken' \
  --header "Authorization: Basic $DESTINATION_API_KEY" \
  --header 'Content-Type: application/json' \
  --data '{"voiceCopyTokenId":"00000000-0000-4000-8000-000000000001","displayName":"Production narrator"}'
```

#### Python

```python
import requests

url = "https://api.inworld.ai/voices/v1/voices:redeemCopyToken"
payload = {
  "parent": "string",
  "voiceCopyTokenId": "00000000-0000-4000-8000-000000000001",
  "displayName": "Production narrator"
}
headers = {
  "Authorization": "<api_key>",
  "Content-Type": "application/json"
}

response = requests.request("POST", url, json=payload, headers=headers)

print(response.text)
```

#### JavaScript

```javascript
const options = {method: 'POST', headers: {"Authorization":"<api_key>","Content-Type":"application/json"}, body: JSON.stringify({
  "parent": "string",
  "voiceCopyTokenId": "00000000-0000-4000-8000-000000000001",
  "displayName": "Production narrator"
})};

fetch('https://api.inworld.ai/voices/v1/voices:redeemCopyToken', options)
  .then(response => response.json())
  .then(response => console.log(response))
  .catch(err => console.error(err));
```
