> ## 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.

# Issue a voice copy token

> Issue a token that lets the listed workspaces copy a custom voice. Requires voice write permission in the source workspace. The token expires after seven days.

Create a token that lets specific workspaces copy one of your custom voices. Use the source workspace's API key with voice write permission (`api.dsgnt.voices::rw`).

## Issue and share a token

Send the source voice's `voiceId`, such as `source-workspace__narrator`, in the URL. Set `allowedWorkspaces` to at least one destination workspace ID:

```bash
curl --request POST 'https://api.inworld.ai/voices/v1/voices/source-workspace__narrator:issueCopyToken' \
  --header "Authorization: Basic $SOURCE_API_KEY" \
  --header 'Content-Type: application/json' \
  --data '{"allowedWorkspaces":["destination-workspace"]}'
```

Use bare workspace IDs in `allowedWorkspaces`, such as `destination-workspace`. The server trims whitespace, ignores blank entries, and removes duplicate IDs. The response returns bare workspace IDs.

An illustrative response, with other fields omitted:

```json
{
  "name": "workspaces/source-workspace/voiceCopyTokens/00000000-0000-4000-8000-000000000001",
  "allowedWorkspaces": ["destination-workspace"]
}
```

Share the final segment of `name`, here `00000000-0000-4000-8000-000000000001`, with the destination workspace. Pass that token ID to [Redeem a voice copy token](https://docs.inworld.ai/api-reference/voiceAPI/voiceservice/redeem-copy-token.md), not the full resource name.

The token expires **seven days** after creation. It can be redeemed more than once before expiry. Treat it as a secret. Each successful redemption creates a new, independent private voice; later edits to the original do not update the copies.

## Token types

These tokens grant access to workspaces. The email-based tokens created by [Voice export in Portal](https://docs.inworld.ai/tts/voice-export.md) use a separate flow. Workspace-scoped tokens cannot be imported through Portal's email-based flow, and Portal's email-based tokens cannot be redeemed by this API.

## API reference

**Endpoint:** `POST https://api.inworld.ai/voices/v1/voices/{voiceId}:issueCopyToken`

### 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`.

### Path parameters

- `voiceId` (string; required) — Custom voice ID in the form {workspace}__{voice}, such as source-workspace__narrator.

### Request body

Content type: `application/json`

- `allowedWorkspaces` (string[]; required) — Destination workspace IDs allowed to redeem the token, such as destination-workspace. Blank entries are ignored; at least one non-blank, valid workspace ID is required. Duplicate IDs are removed. The response returns bare workspace IDs.

#### Request example

```json
{
  "allowedWorkspaces": [
    "destination-workspace"
  ]
}
```

### Response

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

- `name` (string) — Token resource name: workspaces/{workspace}/voiceCopyTokens/{token}. Pass only the final segment to redeemCopyToken.
- `voiceName` (string) — Source voice resource name: workspaces/{workspace}/voices/{voice}.
- `allowedWorkspaces` (string[]) — Bare IDs of the workspaces allowed to redeem this token. Duplicate IDs are removed.
- `allowedEmails` (string[]) — Empty or omitted for tokens issued by this endpoint. Email-based Portal tokens cannot be redeemed with redeemCopyToken.

### Response examples

#### 200: default_response

```json
{
  "name": "workspaces/source-workspace/voiceCopyTokens/00000000-0000-4000-8000-000000000001",
  "allowedWorkspaces": [
    "destination-workspace"
  ]
}
```

#### 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/source-workspace__narrator:issueCopyToken' \
  --header "Authorization: Basic $SOURCE_API_KEY" \
  --header 'Content-Type: application/json' \
  --data '{"allowedWorkspaces":["destination-workspace"]}'
```

#### Python

```python
import requests

url = "https://api.inworld.ai/voices/v1/voices/%7BvoiceId%7D:issueCopyToken"
payload = {
  "allowedWorkspaces": [
    "destination-workspace"
  ]
}
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({
  "allowedWorkspaces": [
    "destination-workspace"
  ]
})};

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