ThunderPhone 2.0 is live.Self-serve, from 2¢/min.Read the announcement

Agents

Voice samples

Generate a spoken sample of any voice from your own text.

Voice samples turn a short piece of your own text into speech in any ThunderPhone voice — any catalog voice or any of your organization's ready custom voices. Use them to audition voices, preview a greeting before an agent goes live, or let your users hear a voice say their own words.

Samples are meant for exactly that — sampling. Text is capped at 500 characters and generation is rate limited per organization. If you need longer samples or a higher limit, contact support@thunderphone.com.

Endpoints

MethodPathDescription
POST/v1/voices/previewGenerate a sample and get a signed audio URL
GET/v1/voices/previews/{id}Stream a generated sample's MP3

Generate a sample

cURL
curl -X POST https://api.thunderphone.com/v1/voices/preview \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "voice": "sarah",
    "language": "en",
    "text": "Thanks for calling Northwind Dental. How can I help you today?"
  }'
FieldTypeRequiredDescription
voicestringyesA voice name from GET /v1/voices — a catalog voice like sarah, or one of your ready custom voices like custom:cv_2f6f90b0e9a34ee8b39be7d1
languagestringyesLanguage code for the sample. For a custom voice, this must be the clone's language
textstringyesThe text to speak, 1–500 characters
Response (200 OK)
{
  "id": "vp_9c2f90b0e9a34ee8b39be7d1",
  "url": "https://api.thunderphone.com/v1/voices/previews/vp_9c2f90b0e9a34ee8b39be7d1?sig=...",
  "cached": false,
  "charged_cents": 3,
  "expires_at": "2026-08-07T14:12:08.317Z"
}
FieldTypeDescription
idstringIdentifier of the generated sample
urlstringSigned URL that streams the sample's MP3 without authentication
cachedbooleantrue when the sample was served from cache instead of freshly generated
charged_centsintegerWhat this request cost: 3 for a fresh generation, 0 for a cache hit
expires_attimestampISO 8601 time the signed URL stops working

Pricing and caching

A fresh generation costs from your prepaid balance. Repeating an identical request — same voice, language, and text — is served from cache, costs nothing, and returns "cached": true with a fresh signed URL. That also means expired URLs are cheap to replace: re-send the same request and you get a new one free.

Generation is limited to 30 fresh samples per organization per hour; cache hits don't count against the limit.

Fetch the audio

The url in the response is a signed link to:

GET /v1/voices/previews/{id}?sig={signature}

It streams audio/mpeg without an Authorization header, so you can hand it straight to an <audio> element or a media player. Signed URLs are valid for 7 days. You can also call the endpoint without sig while authenticated:

cURL
curl \
  https://api.thunderphone.com/v1/voices/previews/vp_9c2f90b0e9a34ee8b39be7d1 \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  --output sample.mp3

An unsigned, unauthenticated request — or one with an invalid or expired signature — returns 401 Unauthorized. A sample generated for another organization's custom voice returns 404 Not Found.

Errors

StatusCode or responseWhen
400{"voice":"Voice is required."}Voice is missing
400{"language":"Language is required."}Language is missing
400{"text":"Text must be between 1 and 500 characters."}Text is empty or too long
400{"voice":"Voice is not available."}Custom voice doesn't exist, isn't ready, or belongs to another organization
400{"language":"Language is not available for this voice."}The voice doesn't speak that language
402insufficient_balancePrepaid balance is below the sample price
422preview_unavailable_languageSample generation isn't available for this voice in that language yet
429preview_rate_limitedThe organization used its 30 fresh generations this hour

The 402, 422, and 429 responses share one shape:

{
  "code": "preview_rate_limited",
  "detail": "Sample generation limit reached. Try again later."
}

A 422 means the voice exists but ThunderPhone can't generate ad-hoc samples for it in that language yet — the voice still works normally on calls. Pick another voice or language for the sample.