Voice profiles Planned
Clone your brand voice from a 15-second audio sample and use it for AI-driven phone interactions: Smart Hold, AI Receptionist, automated confirmations, and IVR prompts. Voice profiles are workspace-scoped and can be attached per phone number.
This endpoint is on the roadmap (Phase 1, alongside the rest of the AI phone stack). The API surface may change before launch. Watch the changelog for the live announcement.
Create a voice profile
Uploads a 15-second sample as multipart form-data. The clone runs server-side through our neural voice synthesis pipeline and is typically ready within 30 seconds. Returns the profile record with status: pending initially; poll or subscribe for the voice_profile:ready event.
Form fields
| Field | Type | Description |
|---|---|---|
| displayNamerequired | string | Internal label. Shown in the dashboard voice picker. |
| personalityTagrequired | enum | One of warm, professional, energetic, calm, custom. |
| sampleAudiorequired | file | 15-second mp3 or wav. We accept 10 to 30 seconds; longer samples are truncated. |
POST /api/v1/voice-profiles
Authorization: Bearer YOUR_WORKSPACE_JWT
Content-Type: multipart/form-data
displayName: Acme Brand Voice
personalityTag: warm
sampleAudio: @./sample-15s.mp3Code samples
curl -X POST 'https://app.message.com/api/v1/voice-profiles' \
-H 'Authorization: Bearer YOUR_WORKSPACE_JWT' \
-F 'displayName=Acme Brand Voice' \
-F 'personalityTag=warm' \
-F 'sampleAudio=@./sample-15s.mp3'const form = new FormData();
form.append('displayName', 'Acme Brand Voice');
form.append('personalityTag', 'warm');
form.append('sampleAudio', audioBlob, 'sample-15s.mp3');
const res = await fetch('https://app.message.com/api/v1/voice-profiles', {
method: 'POST',
headers: { Authorization: 'Bearer ' + token },
body: form
});
const profile = await res.json();import requests
files = {"sampleAudio": open("sample-15s.mp3", "rb")}
data = {"displayName": "Acme Brand Voice", "personalityTag": "warm"}
r = requests.post(
"https://app.message.com/api/v1/voice-profiles",
headers={"Authorization": f"Bearer {token}"},
files=files,
data=data,
)
profile = r.json()require "net/http"
require "uri"
require "json"
uri = URI("https://app.message.com/api/v1/voice-profiles")
File.open("sample-15s.mp3") do |sample|
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{token}"
req.set_form([
["displayName", "Acme Brand Voice"],
["personalityTag", "warm"],
["sampleAudio", sample]
], "multipart/form-data")
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
@profile = JSON.parse(res.body)
end<?php
$file = new CURLFile("sample-15s.mp3", "audio/mpeg", "sample-15s.mp3");
$ch = curl_init("https://app.message.com/api/v1/voice-profiles");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer $token"],
CURLOPT_POSTFIELDS => [
"displayName" => "Acme Brand Voice",
"personalityTag" => "warm",
"sampleAudio" => $file
],
CURLOPT_RETURNTRANSFER => true,
]);
$profile = json_decode(curl_exec($ch), true);List profiles
Cursor-paginated list. Includes both ready and pending profiles.
Get one profile
{
"id": "uuid",
"displayName": "Acme Brand Voice",
"personalityTag": "warm",
"providerVoiceId": "fish_xyz_abc",
"sampleAudioUrl": "https://cdn.message.com/...mp3",
"status": "ready",
"createdAt": "2026-05-13T15:30:00Z"
}Preview audio
Synthesizes a short phrase in the cloned voice. Pass text (up to 250 chars). Returns a signed mp3 URL valid for 15 minutes. Use this to QA before wiring the profile to a phone number.
Delete a profile
Removes the profile. Phone numbers referencing it fall back to the workspace default voice. Sample audio is purged from object storage; the upstream voice resource is released.
Attaching to a phone number
Once status: ready, PATCH the phone-number record with voiceProfileId:
{
"voiceProfileId": "uuid-of-profile",
"expectedVersion": 2
}Use policy
Voice cloning is regulated in some jurisdictions. By using this API you assert that you have written consent from the speaker whose voice you cloned. We require workspace owners to confirm this on first use; abuse triggers profile revocation under our Acceptable Use Policy. See Acceptable use.
Errors
| Code | When |
|---|---|
400 invalid_audio | Sample is too short, too long, or in an unsupported format. |
402 plan_limit | Workspace plan does not include voice cloning. |
403 forbidden | Agent role is not admin. |
409 conflict | Profile with this display name already exists. |
422 still_processing | Preview attempted before status: ready. |
Common pitfalls
- Recording in a noisy room. Background hiss degrades the clone. Use a quiet space and a phone or USB mic.
- Sample too short. Below 10 seconds the clone is generic. 15 seconds of natural speech is the sweet spot.
- Voice consent. Cloning a public figure or a competitor's voice without consent will get the profile revoked.