Audio Generation API
Text-to-speech and sound-effect generation with POST /api/v1/speech and POST /api/v1/sound-effects, plus the public voice catalog.
Speech and sound effects render before the call returns: the response usually already has status: "success" and the audio URL in data.taskUrls. Keep the connection open until it responds. The returned data.id also works with GET /api/v1/tasks/{taskId} if you prefer one polling flow.
List voices
GET /api/v1/voices is public (no API key) and cached for up to an hour.
curl https://viewmax.studio/api/v1/voices{
"code": 0,
"message": "ok",
"data": {
"default_model": "eleven_v3",
"characters_per_credit": 20,
"minimum_credits": 1,
"voices": [
{
"id": "EXAVITQu4vr4xnSDxMaL",
"name": "Sarah",
"gender": "female",
"language": "en",
"languages": ["en", "fr", "ar", "zh", "es", "hi"],
"accent": "american",
"use_case": "entertainment_tv",
"description": "Young adult woman with a confident and warm, mature quality and a reassuring, professional tone.",
"preview_url": "https://…/preview.mp3",
"recommended_model": "eleven_v3"
}
]
}
}| Field | Description |
|---|---|
default_model | Model used when a voice has no recommended_model |
characters_per_credit | Speech costs max(minimum_credits, ceil(text characters / characters_per_credit)) |
minimum_credits | Lowest price of one speech request |
voices[] | id (send as voice_id), name, gender, language, languages, accent, use_case, description, preview_url, recommended_model |
Text to speech
POST /api/v1/speech converts text to speech with a selected voice. It costs max(1, ceil(characters / 20)) credits, counted on the trimmed text: 19 characters cost 1 credit, 1,000 characters cost 50. Plan allowances do not apply to speech on the API.
| Field | Required | Type | Description |
|---|---|---|---|
text | Yes | string | Non-empty text to speak; trimmed |
voice_id | Yes | string | A voice id from GET /api/v1/voices |
options | No | object | See below |
| Option | Type | Description |
|---|---|---|
model_id | string | Defaults to the voice's recommended_model. An unknown value fails at the provider (the task fails and is refunded) |
speed | number | 0.25–4; values outside the range are clamped |
stability | number | 0–1; values outside the range are clamped |
similarity_boost | number | 0–1; values outside the range are clamped |
curl -X POST https://viewmax.studio/api/v1/speech \
-H "Authorization: Bearer $VIEWMAX_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: welcome-001" \
-d '{
"text": "Welcome to ViewMax.",
"voice_id": "EXAVITQu4vr4xnSDxMaL",
"options": { "speed": 1.0 }
}'Sound effects
POST /api/v1/sound-effects generates a sound effect from a text prompt. Each sound effect costs 5 credits.
| Field | Required | Type | Description |
|---|---|---|---|
prompt | Yes | string | Non-empty description of the sound |
options | No | object | See below |
| Option | Type | Description |
|---|---|---|
duration_seconds | number | JSON number from 0.5 to 22 |
prompt_influence | number | JSON number from 0 to 1 |
Values outside these ranges return 400 before any charge.
curl -X POST https://viewmax.studio/api/v1/sound-effects \
-H "Authorization: Bearer $VIEWMAX_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: thunder-001" \
-d '{ "prompt": "A distant rolling thunder clap", "options": { "duration_seconds": 5 } }'Successful response
Speech example:
{
"code": 0,
"message": "ok",
"data": {
"id": "9d1f3b5c-7e9a-4c2d-8f1b-3a5c7e9b1d24",
"userId": "usr_123",
"mediaType": "audio",
"model": "eleven_v3",
"prompt": "Welcome to ViewMax.",
"options": "{\"voice_id\":\"EXAVITQu4vr4xnSDxMaL\",\"speed\":1}",
"status": "success",
"createdAt": "2026-09-29T08:00:00.000Z",
"updatedAt": "2026-09-29T08:00:03.000Z",
"deletedAt": null,
"taskId": "sync:9d1f3b5c-7e9a-4c2d-8f1b-3a5c7e9b1d24",
"taskInfo": null,
"taskResult": "{\"output\":[\"https://cdn.example.com/audio/speech.mp3\"]}",
"taskUrls": ["https://cdn.example.com/audio/speech.mp3"],
"costCredits": 1,
"scene": "text-to-speech",
"visibility": "user",
"creditId": "cr_246",
"waivedCredits": 0,
"fairUseKey": null
}
}A sound effect returns the same shape with scene: "text-to-sound-effects" and costCredits: 5. The fields are described under Task fields in the Video Generation API. taskUrls is always an array.
Idempotency and refunds
- Send
Idempotency-Key(1–200 visible ASCII characters, no spaces). Repeating a key returns the original task and itscostCreditswithout charging again; the body is not compared, and keys are shared by all create endpoints of the account. Retry a timed-out request with the same key; use a new key for a deliberate new attempt. Without the header, every POST creates and charges a new task. - Credits are deducted when the task is created. If the balance is lower than the cost, the call returns 402 and creates no task. A task that ends
failedorcanceledis refunded automatically.
Errors
All errors use the error envelope.
| HTTP | error.type | Example message | What to do |
|---|---|---|---|
| 400 | invalid_request | text is required / voice_id is required / prompt is required | Send the required field |
| 400 | invalid_request | unknown voice_id: abc. Call GET /api/v1/voices (MCP: list_voices) for available voices. | Use a voice id from GET /api/v1/voices |
| 400 | invalid_request | options.duration_seconds must be a number from 0.5 to 22 | Send a JSON number in range (sound effects) |
| 400 | invalid_request | options.prompt_influence must be a number from 0 to 1 | Send a JSON number in range (sound effects) |
| 400 | invalid_request | the generation request uses unsupported settings, with error.task_id | The provider rejected the settings; the task failed and was refunded. Read its taskInfo.errorMessage, adjust, and retry with a new key |
| 400 | content_rejected | input content was rejected by safety filters | Change the text or prompt; do not retry unchanged |
| 402 | insufficient_credits | insufficient credits | No task was created. Add credits; do not retry until then |
| 500 | internal_error | the generation service is temporarily unavailable | With error.task_id the task failed and was refunded: retry once. If the hint says the outcome is unknown, poll that task instead of retrying |
| 503 | internal_error | — | Sound effects only: the content-safety check is temporarily unavailable; retry after a short delay |