Voice API
Speak text
Synthesizes speech and plays it into the live call.
/api/v1/voice/call-control/speakBefore you start
Use an active call-control ID, text, a voice_api voice and an Idempotency-Key.
Result
Keep the returned media reference and public tts_charge transaction reference.
Charges and safe retries
Text is charged by character. Reuse the same key while voice_request_pending; only voice_request_closed permits a new request.
Authentication
Send your account API key in the X-Api-Key header. Keep it on your server; never embed it in browser code.
Request examples
Replace the example values with your own inputs. Examples do not run on this page. Production requests can change your account or incur charges.
cURL
curl -X POST "https://api.illyvoip.com/api/v1/voice/call-control/speak" \
-H "X-Api-Key: ${ILLYVOIP_API_KEY:?Set ILLYVOIP_API_KEY}" \
-H "Idempotency-Key: YOUR_UNIQUE_IDEMPOTENCY_KEY" \
-H "Content-Type: application/json" \
-d '{
"call_control_id": "YOUR_CALL_CONTROL_ID",
"text": "Hello. This call is generated by IllyVoIP.",
"language": "en-US",
"voice": "illyvoip-emma"
}'Node.js
const response = await fetch("https://api.illyvoip.com/api/v1/voice/call-control/speak", {
method: "POST",
headers: {
"X-Api-Key": process.env.ILLYVOIP_API_KEY,
"Idempotency-Key": "YOUR_UNIQUE_IDEMPOTENCY_KEY",
'Content-Type': 'application/json'
},
body: JSON.stringify({
"call_control_id": "YOUR_CALL_CONTROL_ID",
"text": "Hello. This call is generated by IllyVoIP.",
"language": "en-US",
"voice": "illyvoip-emma"
})
});
const data = await response.json();
console.log(response.status, data);PHP
<?php
$ch = curl_init('https://api.illyvoip.com/api/v1/voice/call-control/speak');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'X-Api-Key: ' . getenv('ILLYVOIP_API_KEY'),
'Idempotency-Key: YOUR_UNIQUE_IDEMPOTENCY_KEY',
'Content-Type: application/json'
],
CURLOPT_POSTFIELDS => '{
"call_control_id": "YOUR_CALL_CONTROL_ID",
"text": "Hello. This call is generated by IllyVoIP.",
"language": "en-US",
"voice": "illyvoip-emma"
}',
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status . PHP_EOL;
echo $response;Python
import os
import json
import requests
response = requests.request(
"POST",
"https://api.illyvoip.com/api/v1/voice/call-control/speak",
headers={
"X-Api-Key": os.environ["ILLYVOIP_API_KEY"],
"Idempotency-Key": "YOUR_UNIQUE_IDEMPOTENCY_KEY",
'Content-Type': 'application/json'
},
json=json.loads("{\n \"call_control_id\": \"YOUR_CALL_CONTROL_ID\",\n \"text\": \"Hello. This call is generated by IllyVoIP.\",\n \"language\": \"en-US\",\n \"voice\": \"illyvoip-emma\"\n}"),
)
print(response.status_code)
print(response.json())Node.js examples run on the server (Node.js 22.17+). Python examples require requests; PHP examples require cURL. Set the environment variables referenced in each example.
Request parameters
Header parameters
Idempotency-KeystringrequiredUnique retry key for this mutation. Reuse the same key only when retrying the same request.
Request body
application/json
Body required.
call_control_idstringrequiredLive control session ID.
textstringrequiredText to synthesize, maximum 2,000 characters.
languagestringoptionalOptional TTS language. Use the canonical code from List TTS languages with context=voice_api, such as en-US.
voicestringoptionalOptional voice name from List TTS voices with context=voice_api, for example illyvoip-emma.
tts_enginestringoptionalDeprecated compatibility selector. Omit to use the current speech settings. Existing supported values remain accepted.
enginestringoptionalDeprecated compatibility selector. Omit to use the current speech settings. Existing supported values remain accepted.
Additional properties: not allowed.
Full schema
{
"type": "object",
"additionalProperties": false,
"properties": {
"call_control_id": {
"type": "string",
"nullable": false,
"description": "Live control session ID."
},
"text": {
"type": "string",
"maxLength": 2000,
"description": "Text to synthesize, maximum 2,000 characters."
},
"language": {
"type": "string",
"description": "Optional TTS language. Use the canonical code from `List TTS languages` with `context=voice_api`, such as `en-US`."
},
"voice": {
"type": "string",
"description": "Optional voice name from `List TTS voices` with `context=voice_api`, for example `illyvoip-emma`."
},
"tts_engine": {
"type": "string",
"deprecated": true,
"description": "Deprecated compatibility selector. Omit to use the current speech settings. Existing supported values remain accepted."
},
"engine": {
"type": "string",
"deprecated": true,
"description": "Deprecated compatibility selector. Omit to use the current speech settings. Existing supported values remain accepted."
}
},
"required": [
"call_control_id",
"text"
]
}Example body
{
"call_control_id": "vapi_760da5ee5a3c8b70777bae20fbda",
"text": "Hello. This call is generated by IllyVoIP.",
"language": "en-US",
"voice": "illyvoip-emma"
}Request behavior
Use this to read text into the call with the selected voice key. TTS usage is billed per submitted character and successful responses include tts_charge when a billable prompt is created. The response media value is an opaque, short-lived reference scoped to this call.
Each charge includes a public transaction_id matching the ledger (null when no balance movement exists). An Idempotency-Key header is required. Reuse the same key while voice_request_pending is returned.
Only voice_request_closed confirms the unsuccessful request is settled and a new request may use a new key. Use an exact current voice ID from the Voice API catalog. Omitting voice uses the current default.
Deprecated tts_engine/engine values remain accepted for compatibility and use the current speech settings. Previously supported voice selections remain accepted and resolve to the corresponding current voice. Use the voice catalog for current identifiers.
Unknown names and ambiguous voice_N ordinals are rejected. Language hints remain separate from voice selection. A selected text request may return HTTP 403 with voice_content_review_required and fields.review_reference.
That request is not charged or played. Open Communication reviews in your account to explain the activity. Repeating its key returns the same refusal; approval does not automatically replay it.
An existing media reference takes precedence over unused text.
Conditions and examples
Idempotency-Key is required; reuse it only for the identical request. Voice API speak uses the Voice API TTS catalog. Call List TTS languages with context=voice_api, then List TTS voices with the same context=voice_api and the language you want. Current Voice API TTS language options: en-US.
Response fields
status: Request outcome. Read the resource state separately; success does not always mean delivery or completion.call_control_id: Control session reference returned by Create or Answer; use it for subsequent live actions.media: Opaque temporary media reference scoped to this call; do not parse or reuse it across calls.tts_charge: Text-to-speech usage and charge, including a public ledger transaction reference when charged.
HTTP responses
Expand a status to inspect its documented response format and examples. Example prices, IDs and timestamps are illustrative values, not quotes or account records.
200 Successful customer-facing response.
application/json
{
"status": "success",
"call_control_id": "vapi_760da5ee5a3c8b70777bae20fbda",
"media": "vcm2.OPAQUE_CALL_SCOPED_MEDIA_REFERENCE",
"tts_charge": {
"transaction_id": "TX-1A2B3C4D5E6F",
"product": "voice_api_tts",
"characters": 44,
"rate_per_char_eur": 5e-05,
"amount_eur": 0.0022
}
}statusstringrequiredcall_control_idstringrequiredmediastringrequiredOpaque, short-lived media reference valid only for this account and call.
tts_chargeobjectrequiredView nested fields
transaction_idstringrequiredPublic transaction reference matching your ledger, or null when no balance movement exists.
productstringrequiredcharactersintegerrequiredrate_per_char_eurnumberrequiredamount_eurnumberrequiredAdditional properties: not allowed.
Additional properties: not allowed.
Full schema
{
"type": "object",
"additionalProperties": false,
"properties": {
"status": {
"type": "string",
"enum": [
"success"
]
},
"call_control_id": {
"type": "string",
"nullable": false
},
"media": {
"type": "string",
"description": "Opaque, short-lived media reference valid only for this account and call."
},
"tts_charge": {
"type": "object",
"additionalProperties": false,
"properties": {
"transaction_id": {
"type": "string",
"nullable": true,
"pattern": "^TX-[A-F0-9]{12,24}$",
"description": "Public transaction reference matching your ledger, or null when no balance movement exists."
},
"product": {
"type": "string"
},
"characters": {
"type": "integer"
},
"rate_per_char_eur": {
"type": "number"
},
"amount_eur": {
"type": "number"
}
},
"required": [
"transaction_id",
"product",
"characters",
"rate_per_char_eur",
"amount_eur"
],
"nullable": true
}
},
"required": [
"status",
"call_control_id",
"media",
"tts_charge"
]
}400 The request failed validation.
application/json
statusstringrequiredmessagestringrequirederror_codestringoptionalPublic incident or validation code when the endpoint provides one.
fieldsobjectoptionalPublic validation details when supplied by the endpoint.
Additional properties: not allowed.
Full schema
{
"type": "object",
"additionalProperties": false,
"required": [
"status",
"message"
],
"properties": {
"status": {
"type": "string",
"enum": [
"error"
]
},
"message": {
"type": "string"
},
"error_code": {
"type": "string",
"nullable": true,
"description": "Public incident or validation code when the endpoint provides one."
},
"fields": {
"type": "object",
"additionalProperties": true,
"description": "Public validation details when supplied by the endpoint."
}
}
}401 The API key or browser token is missing or invalid.
application/json
statusstringrequiredmessagestringrequirederror_codestringoptionalPublic incident or validation code when the endpoint provides one.
fieldsobjectoptionalPublic validation details when supplied by the endpoint.
Additional properties: not allowed.
Full schema
{
"type": "object",
"additionalProperties": false,
"required": [
"status",
"message"
],
"properties": {
"status": {
"type": "string",
"enum": [
"error"
]
},
"message": {
"type": "string"
},
"error_code": {
"type": "string",
"nullable": true,
"description": "Public incident or validation code when the endpoint provides one."
},
"fields": {
"type": "object",
"additionalProperties": true,
"description": "Public validation details when supplied by the endpoint."
}
}
}402 The account has insufficient available credit.
application/json
statusstringrequiredmessagestringrequirederror_codestringoptionalPublic incident or validation code when the endpoint provides one.
fieldsobjectoptionalPublic validation details when supplied by the endpoint.
Additional properties: not allowed.
Full schema
{
"type": "object",
"additionalProperties": false,
"required": [
"status",
"message"
],
"properties": {
"status": {
"type": "string",
"enum": [
"error"
]
},
"message": {
"type": "string"
},
"error_code": {
"type": "string",
"nullable": true,
"description": "Public incident or validation code when the endpoint provides one."
},
"fields": {
"type": "object",
"additionalProperties": true,
"description": "Public validation details when supplied by the endpoint."
}
}
}403 The account is not allowed to perform this operation.
application/json
statusstringrequiredmessagestringrequirederror_codestringoptionalPublic incident or validation code when the endpoint provides one.
fieldsobjectoptionalPublic validation details when supplied by the endpoint.
Additional properties: not allowed.
Full schema
{
"type": "object",
"additionalProperties": false,
"required": [
"status",
"message"
],
"properties": {
"status": {
"type": "string",
"enum": [
"error"
]
},
"message": {
"type": "string"
},
"error_code": {
"type": "string",
"nullable": true,
"description": "Public incident or validation code when the endpoint provides one."
},
"fields": {
"type": "object",
"additionalProperties": true,
"description": "Public validation details when supplied by the endpoint."
}
}
}404 The requested owned resource was not found.
application/json
statusstringrequiredmessagestringrequirederror_codestringoptionalPublic incident or validation code when the endpoint provides one.
fieldsobjectoptionalPublic validation details when supplied by the endpoint.
Additional properties: not allowed.
Full schema
{
"type": "object",
"additionalProperties": false,
"required": [
"status",
"message"
],
"properties": {
"status": {
"type": "string",
"enum": [
"error"
]
},
"message": {
"type": "string"
},
"error_code": {
"type": "string",
"nullable": true,
"description": "Public incident or validation code when the endpoint provides one."
},
"fields": {
"type": "object",
"additionalProperties": true,
"description": "Public validation details when supplied by the endpoint."
}
}
}409 The request conflicts with an earlier request, is in progress, or has finished unsuccessfully. Only error_code voice_request_closed confirms billing is settled and permits a new request with a new key.
application/json
statusstringrequiredmessagestringrequirederror_codestringoptionalPublic incident or validation code when the endpoint provides one.
fieldsobjectoptionalPublic validation details when supplied by the endpoint.
Additional properties: not allowed.
Full schema
{
"type": "object",
"additionalProperties": false,
"required": [
"status",
"message"
],
"properties": {
"status": {
"type": "string",
"enum": [
"error"
]
},
"message": {
"type": "string"
},
"error_code": {
"type": "string",
"nullable": true,
"description": "Public incident or validation code when the endpoint provides one."
},
"fields": {
"type": "object",
"additionalProperties": true,
"description": "Public validation details when supplied by the endpoint."
}
}
}429 The request rate limit was exceeded.
application/json
statusstringrequiredmessagestringrequirederror_codestringoptionalPublic incident or validation code when the endpoint provides one.
fieldsobjectoptionalPublic validation details when supplied by the endpoint.
Additional properties: not allowed.
Full schema
{
"type": "object",
"additionalProperties": false,
"required": [
"status",
"message"
],
"properties": {
"status": {
"type": "string",
"enum": [
"error"
]
},
"message": {
"type": "string"
},
"error_code": {
"type": "string",
"nullable": true,
"description": "Public incident or validation code when the endpoint provides one."
},
"fields": {
"type": "object",
"additionalProperties": true,
"description": "Public validation details when supplied by the endpoint."
}
}
}500 An unexpected service error occurred.
application/json
statusstringrequiredmessagestringrequirederror_codestringoptionalPublic incident or validation code when the endpoint provides one.
fieldsobjectoptionalPublic validation details when supplied by the endpoint.
Additional properties: not allowed.
Full schema
{
"type": "object",
"additionalProperties": false,
"required": [
"status",
"message"
],
"properties": {
"status": {
"type": "string",
"enum": [
"error"
]
},
"message": {
"type": "string"
},
"error_code": {
"type": "string",
"nullable": true,
"description": "Public incident or validation code when the endpoint provides one."
},
"fields": {
"type": "object",
"additionalProperties": true,
"description": "Public validation details when supplied by the endpoint."
}
}
}503 For voice_request_pending, keep the same request key while the outcome is checked. For voice_billing_review, contact support before trying again.
application/json
statusstringrequiredmessagestringrequirederror_codestringoptionalPublic incident or validation code when the endpoint provides one.
fieldsobjectoptionalPublic validation details when supplied by the endpoint.
Additional properties: not allowed.
Full schema
{
"type": "object",
"additionalProperties": false,
"required": [
"status",
"message"
],
"properties": {
"status": {
"type": "string",
"enum": [
"error"
]
},
"message": {
"type": "string"
},
"error_code": {
"type": "string",
"nullable": true,
"description": "Public incident or validation code when the endpoint provides one."
},
"fields": {
"type": "object",
"additionalProperties": true,
"description": "Public validation details when supplied by the endpoint."
}
}
}Sandbox scenarios
Use https://sandbox-api.illyvoip.com with Sandbox credentials and the X-Illyvoip-Sandbox-Scenario header. Omit the header for the documented success default. This header belongs to sandbox requests.
success, not-found, rate-limited, forbidden, service-unavailable, insufficient-credit, idempotency-conflict
Try this operation in Sandbox · Environment setup and limitations