curl --location 'https://api.inworld.ai/voices/v1/pvcVoices/<voice-id>/samples' \
--header "Authorization: Basic $INWORLD_API_KEY" \
--form 'files[]=@"sample-01.wav"' \
--form 'files[]=@"sample-02.wav"' \
--form 'remove_background_noise="false"'import requests
voice_id = "<voice-id>"
url = f"https://api.inworld.ai/voices/v1/pvcVoices/{voice_id}/samples"
headers = {"Authorization": "Basic <api-key>"}
files = [
("files[]", ("sample-01.wav", open("sample-01.wav", "rb"), "audio/wav")),
("files[]", ("sample-02.wav", open("sample-02.wav", "rb"), "audio/wav")),
]
data = {"remove_background_noise": "false"}
response = requests.post(url, headers=headers, files=files, data=data)
print(response.json())import { openAsBlob } from 'node:fs';
const voiceId = '<voice-id>';
const url = `https://api.inworld.ai/voices/v1/pvcVoices/${voiceId}/samples`;
const form = new FormData();
form.append('files[]', await openAsBlob('sample-01.wav'), 'sample-01.wav');
form.append('files[]', await openAsBlob('sample-02.wav'), 'sample-02.wav');
form.append('remove_background_noise', 'false');
const response = await fetch(url, {
method: 'POST',
headers: { 'Authorization': 'Basic <api-key>' },
body: form,
});
const data = await response.json();
console.log(data);{
"samples": [
{
"sampleId": "s_9f1c2e",
"name": "workspaces/your_workspace_id/pvcVoices/my-professional-voice/samples/s_9f1c2e",
"sizeBytes": 24883220,
"durationSecs": 312.4,
"mimeType": "audio/wav",
"hash": "<base64-gcs-md5>"
},
{
"sampleId": "s_4b7a01",
"name": "workspaces/your_workspace_id/pvcVoices/my-professional-voice/samples/s_4b7a01",
"sizeBytes": 19004112,
"durationSecs": 238.1,
"mimeType": "audio/wav",
"hash": "<base64-gcs-md5>"
}
]
}{
"code": 3,
"message": "invalid request: unsupported audio format for file 'sample-03.m4a'",
"details": []
}{
"code": 123,
"message": "<string>",
"details": [
{
"@type": "<string>"
}
]
}{
"code": 123,
"message": "<string>",
"details": [
{
"@type": "<string>"
}
]
}{
"code": 123,
"message": "<string>",
"details": [
{
"@type": "<string>"
}
]
}Upload PVC voice samples
Uploads one or more audio samples to a draft PVC voice. The request is all-or-nothing — if any file is rejected, none of the files in that request are saved. Only allowed while the voice is in state PVC_VOICE_STATE_DRAFT or PVC_VOICE_STATE_FAILED.
curl --location 'https://api.inworld.ai/voices/v1/pvcVoices/<voice-id>/samples' \
--header "Authorization: Basic $INWORLD_API_KEY" \
--form 'files[]=@"sample-01.wav"' \
--form 'files[]=@"sample-02.wav"' \
--form 'remove_background_noise="false"'import requests
voice_id = "<voice-id>"
url = f"https://api.inworld.ai/voices/v1/pvcVoices/{voice_id}/samples"
headers = {"Authorization": "Basic <api-key>"}
files = [
("files[]", ("sample-01.wav", open("sample-01.wav", "rb"), "audio/wav")),
("files[]", ("sample-02.wav", open("sample-02.wav", "rb"), "audio/wav")),
]
data = {"remove_background_noise": "false"}
response = requests.post(url, headers=headers, files=files, data=data)
print(response.json())import { openAsBlob } from 'node:fs';
const voiceId = '<voice-id>';
const url = `https://api.inworld.ai/voices/v1/pvcVoices/${voiceId}/samples`;
const form = new FormData();
form.append('files[]', await openAsBlob('sample-01.wav'), 'sample-01.wav');
form.append('files[]', await openAsBlob('sample-02.wav'), 'sample-02.wav');
form.append('remove_background_noise', 'false');
const response = await fetch(url, {
method: 'POST',
headers: { 'Authorization': 'Basic <api-key>' },
body: form,
});
const data = await response.json();
console.log(data);{
"samples": [
{
"sampleId": "s_9f1c2e",
"name": "workspaces/your_workspace_id/pvcVoices/my-professional-voice/samples/s_9f1c2e",
"sizeBytes": 24883220,
"durationSecs": 312.4,
"mimeType": "audio/wav",
"hash": "<base64-gcs-md5>"
},
{
"sampleId": "s_4b7a01",
"name": "workspaces/your_workspace_id/pvcVoices/my-professional-voice/samples/s_4b7a01",
"sizeBytes": 19004112,
"durationSecs": 238.1,
"mimeType": "audio/wav",
"hash": "<base64-gcs-md5>"
}
]
}{
"code": 3,
"message": "invalid request: unsupported audio format for file 'sample-03.m4a'",
"details": []
}{
"code": 123,
"message": "<string>",
"details": [
{
"@type": "<string>"
}
]
}{
"code": 123,
"message": "<string>",
"details": [
{
"@type": "<string>"
}
]
}{
"code": 123,
"message": "<string>",
"details": [
{
"@type": "<string>"
}
]
}PVC_VOICE_STATE_DRAFT or PVC_VOICE_STATE_FAILED. Call this endpoint as many times as you need — samples accumulate on the voice until you train it.
.wav does not make it a WAV file.Accepted audio
| Format | Notes |
|---|---|
| WAV | PCM (8/16/24/32-bit), 32-bit float, or WAVE_FORMAT_EXTENSIBLE |
| MP3 | — |
| WEBM | Must include a Duration element in its metadata |
.m4a, zero-byte files, truncated WAV files, and WEBM files missing Duration metadata.
Limits
| Limit | Value |
|---|---|
| Files per request | 10 |
| Size per file | 1 GB |
| Combined sample storage per voice | 5 GB |
| Samples per voice | 50 |
| Concurrent uploads per account | plan-dependent |
400 (per-request/per-file/per-voice limits) or 429 (too many concurrent uploads).
For recording and preparation tips, see Voice Cloning best practices.Authorizations
Your API key. 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: inworld workspace add-key.
Path Parameters
Voice ID of the draft PVC voice to add samples to.
Body
Multipart form for UploadPvcVoiceSamples.
Audio files to upload, up to 10 per request. Repeat the files[] form field once per file (e.g. files[]=@"sample-01.wav", files[]=@"sample-02.wav") — it is not a single field containing a list. Accepted formats: WAV, WEBM, MP3 — the actual byte content is sniffed to determine format, not the declared MIME type or file extension. Each file is capped at 1 GB; the voice's combined sample storage is capped at 5 GB and 50 samples total.
Whether to run an audio isolation model over the uploaded samples to remove background noise before training. Can degrade quality on already-clean recordings. Defaults to false.
Response
A successful response.
Response message for UploadPvcVoiceSamples.
The samples accepted by this request, in the order they were uploaded.
Show child attributes
Show child attributes