# Save a designed voice

`POST https://api.paxalabs.com/v1/voices/designed`

POST /v1/voices/designed saves a draft from POST /v1/voices/design as one of the account's voices and returns it with its id.

Send `name` to choose the voice's name, or leave it out to keep the name the design call gave. Saving the same draft again returns the same voice and takes no slot. A retry is safe.

A full account answers [403 voice_slots_full](https://paxalabs.com/docs/errors#voice_slots_full), and [Designed voices](https://paxalabs.com/docs/designed-voices#plans) lists each plan's slots. Saving costs nothing and takes no rate-limit token.

## Headers

- `authorization` (Bearer pxa_..., required): Authorization: Bearer pxa_... (recommended).
- `x-api-key` (pxa_..., optional): Alternative to the Authorization header. Ignored when Authorization is present.

See authentication at https://paxalabs.com/docs/authentication.

## Body

- `draft` (string, required, 1 to 4,096 characters): The draft a design response returned. Saving one draft again returns the voice it made and takes no slot.
- `name` (string, optional, 1 to 60 characters): A name for the voice, up to 60 characters. Omitted, the voice keeps the name the design response gave it. A catalog voice's name answers 400 voice_name_taken.

## Response

- `id` (string, required): The voice id, starting "voice_". Send it as voice with model paxa-tts-flash-v2 on POST /v1/tts, POST /v1/audio/speech, or the /v1/tts/live socket.
- `name` (string, required): Display name, which PATCH changes. The voice field does not accept it.
- `role` (string, required): Who the voice is, in a few words.
- `description` (string, required): How the voice sounds, in one sentence.
- `gender` ("f" or "m", required): Voice gender, "f" or "m".
- `language` ("th" or "en" or "zh", required): The one language the voice speaks: "th" (Thai), "en" (English), or "zh" (Mandarin Chinese, Simplified script).
- `model` (string, required): The model the voice speaks on.
- `created_at` (string, required): Save time, ISO 8601.

## Errors

- `validation` (400): The request body, query, or headers failed validation against the endpoint schema, or broke a rule the endpoint's reference states. A field the schema refused adds two fields to the problem body. path names the first failing field by location and name in dot form, such as body.voice or headers.idempotency-key. A body that could not be read gives the path body alone. reason is one stable code from the validation reasons list.
- `draft_invalid` (400): The draft field holds no draft this account received from POST /v1/voices/design. It is altered or cut short, belongs to another account, or no longer opens after a platform update. Nothing was charged.
- `voice_name_taken` (400): The name is a catalog voice's name, which no designed voice can take. Nothing was saved.
- `unauthorized` (401): The request carried no API key, or the key is invalid or disabled.
- `voice_slots_full` (403): The account holds as many designed voices as its plan allows. Nothing was saved.

## Example

curl:

```bash
curl -X POST https://api.paxalabs.com/v1/voices/designed \
  -H "Authorization: Bearer $PAXA_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"draft\": \"$(jq -r .draft design.json)\", \"name\": \"Nok\"}"
```

TypeScript:

```typescript
// draft is the string POST /v1/voices/design returned. Saving it
// again returns the same voice.
const response = await fetch("https://api.paxalabs.com/v1/voices/designed", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.PAXA_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ draft, name: "Nok" }),
});
if (!response.ok) throw new Error(`Save failed: ${response.status}`);
const voice = await response.json();
console.log(voice.id);
```

Python:

```python
import os
import requests

# draft is the string POST /v1/voices/design returned. Saving it
# again returns the same voice.
voice = requests.post(
    "https://api.paxalabs.com/v1/voices/designed",
    headers={"Authorization": f"Bearer {os.environ['PAXA_API_KEY']}"},
    json={"draft": draft, "name": "Nok"},
)
voice.raise_for_status()
print(voice.json()["id"])
```

Response:

```json
{
  "id": "voice_3f9a1c2e7b4d4e8a9c0b1d2e3f4a5b6c",
  "name": "Nok",
  "role": "Pharmacist",
  "description": "A calm, warm voice that explains each step slowly.",
  "gender": "f",
  "language": "th",
  "model": "paxa-tts-flash-v2",
  "created_at": "2026-10-23T08:41:16.204Z"
}
```
