English (India) Text-to-Speech API in PHP
You need to generate natural-sounding speech in English (India) from PHP and return a direct MP3 URL you can stream or store. By the end of this guide, you will send text to a Text-to-Speech API, authenticate with a Bearer token, receive a JSON envelope with audio_src, and integrate the result into a PHP backend.
What you will build and what you need
You will integrate a server-side PHP function that converts text to speech in the English (India) locale and returns the audio URL. You will also learn how to validate the response, handle failures, and persist the MP3 for later playback.
- Language and locale: English (India), language=en_IN
- Voice: gender_voice=male (docs default)
- Authentication: Bearer YOUR_API_KEY
- Endpoint: POST https://www.getwoord.com/api/convert
- Body encoding: form fields (not JSON)
Important: Free plans cannot call this convert endpoint. Create an account and choose a plan that includes API access. You can Register to get your key, and consult the Documentation for plan details.
Understand the request model
The Woord convert API accepts form fields and returns a JSON envelope with a direct S3 link to the audio file. Do not send JSON in the request body. Use standard URL-encoded form data.
- URL: https://www.getwoord.com/api/convert
- Method: POST
- Headers:
- Accept: application/json
- Authorization: Bearer YOUR_API_KEY
- Form fields:
- text: the text to synthesize
- gender_voice: male (docs default)
- language: en_IN
The official examples also show speakingRate=1.00 in form data. For a minimal, portable integration, start with text, gender_voice, and language. If you include speakingRate, keep it URL-encoded in the form body like other fields.
cURL quickstart (English India)
Run this to validate your key and environment. This is the official sample for English (India), using Hello World as text.
cURL
curl "https://www.getwoord.com/api/convert" -X POST -H "Accept: application/json" -H "Authorization: Bearer YOUR_KEY" --data "text=Hello+World&gender_voice=male&language=en_IN&speakingRate=1.00"
If successful, you’ll receive a JSON envelope with message, audio_src, and error. The audio_src will be a new S3 key for your request.
PHP server integration with curl_init
This example posts form-encoded fields from PHP and parses the JSON response. It targets the English (India) voice and demonstrates minimal error checks. Insert your real API key in the Authorization header.
PHP (curl_init)
<?php
$apiUrl = "https://www.getwoord.com/api/convert";
$apiKey = "YOUR_API_KEY"; // Replace with your actual key from your Woord account
// Required form fields for English (India)
$formData = http_build_query([
"text" => "Hello World",
"gender_voice" => "male",
"language" => "en_IN",
// Optionally include speakingRate exactly as a form field:
// "speakingRate" => "1.00",
]);
$ch = curl_init($apiUrl);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $formData,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Accept: application/json",
"Authorization: Bearer " . $apiKey,
"Content-Type: application/x-www-form-urlencoded",
],
// Consider setting a timeout for production:
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_TIMEOUT => 60,
]);
$responseBody = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curlErrNo = curl_errno($ch);
$curlErr = curl_error($ch);
curl_close($ch);
// Basic transport-level error handling
if ($curlErrNo) {
http_response_code(502);
echo json_encode([ "error" => true, "message" => "Transport error: " . $curlErr ]);
exit;
}
if ($httpCode < 200 || $httpCode >= 300) {
http_response_code($httpCode);
echo json_encode([ "error" => true, "message" => "HTTP status " . $httpCode, "body" => $responseBody ]);
exit;
}
// Parse JSON envelope from Woord
$payload = json_decode($responseBody, true);
// Guard checks on the expected fields
if (!is_array($payload) || !array_key_exists("error", $payload) || !array_key_exists("message", $payload)) {
http_response_code(502);
echo json_encode([ "error" => true, "message" => "Unexpected response schema", "body" => $responseBody ]);
exit;
}
if ($payload["error"] === true) {
http_response_code(400);
echo json_encode([ "error" => true, "message" => $payload["message"] ]);
exit;
}
// At this point, success is expected and audio_src should be present
$audioUrl = isset($payload["audio_src"]) ? $payload["audio_src"] : null;
if (!$audioUrl) {
http_response_code(502);
echo json_encode([ "error" => true, "message" => "Missing audio_src in successful response" ]);
exit;
}
// Example: proxy or persist the URL, or just return it to the client
header("Content-Type: application/json");
echo json_encode([
"error" => false,
"message" => "TTS created",
"audio_src" => $audioUrl,
]);
Note: The API returns an S3 URL you can stream immediately. If you need permanent availability with your own SLA, download and store the file on your infrastructure after validating the request.
JavaScript example (fetch from a server context)
For server-side JavaScript (for example, Node.js) you can use fetch and URLSearchParams to send form-encoded fields. Embed the Authorization header with your key and read the envelope.
JavaScript (Node.js fetch)
import fetch from "node-fetch";
async function convertEnIndia(text) {
const url = "https://www.getwoord.com/api/convert";
const token = "YOUR_API_KEY";
const body = new URLSearchParams();
body.set("text", text);
body.set("gender_voice", "male");
body.set("language", "en_IN");
// Optional: body.set("speakingRate", "1.00");
const res = await fetch(url, {
method: "POST",
headers: {
"Accept": "application/json",
"Authorization": "Bearer " + token,
"Content-Type": "application/x-www-form-urlencoded",
},
body,
});
const httpOk = res.ok;
const payloadText = await res.text();
if (!httpOk) {
throw new Error("HTTP " + res.status + " - " + payloadText);
}
let json;
try {
json = JSON.parse(payloadText);
} catch (e) {
throw new Error("Invalid JSON envelope: " + e.message + " - " + payloadText);
}
if (json.error === true) {
throw new Error("API error: " + json.message);
}
if (!json.audio_src) {
throw new Error("Missing audio_src in response");
}
return json.audio_src;
}
(async () => {
try {
const audioUrl = await convertEnIndia("Hello World");
console.log("MP3 URL:", audioUrl);
} catch (err) {
console.error("TTS failed:", err.message);
}
})();
This example prints the direct MP3 URL. In production, consider downloading and caching the MP3 if you need guaranteed availability independent of external storage lifecycles.
The official response envelope and how to use it
Below is the official JSON response from the documentation. The audio_src is a docs fixture; your response will include a different key. Do not embed or hotlink the fixture URL in production.
Official JSON (from docs)
{
"message": "Your audio has been created!",
"audio_src": "https://getwoord.s3.amazonaws.com/4273352455515882618255eaaf3c1cbdbe0.55443890.mp3",
"error": false
}
Fields you will use:
- message: a human-readable status string.
- audio_src: a direct URL to your generated MP3 on S3. Expect a new key for every successful request.
- error: boolean flag. false means the request succeeded; true indicates an API-level failure.
Additional response examples you can expect
These examples use only the documented fields and emulate typical patterns. Your audio_src values will differ.
Successful conversion with a new S3 key
{
"message": "Your audio has been created!",
"audio_src": "https://getwoord.s3.amazonaws.com/8cbd1e2f9c744c388fb3e3a08a6c22d1.12345678.mp3",
"error": false
}
Another success (different input text, same locale)
{
"message": "Your audio has been created!",
"audio_src": "https://getwoord.s3.amazonaws.com/aa77d13a0f3449a0a9d2b6f35ce91ef3.87654321.mp3",
"error": false
}
Failure example (API-level error)
{
"message": "Invalid authentication token",
"audio_src": "",
"error": true
}
In error scenarios, check error === true and display message to logs or clients as appropriate. Do not attempt to use audio_src when error is true.
Preparing your English (India) input text
For this locale, use language=en_IN and set gender_voice=male to match the docs default. Start with simple phrases to validate phonetics and speed; then scale up to full paragraphs.
- Minimal sample (from docs): Hello World
- If you include punctuation, ensure it is properly URL-encoded in the form field.
- For multi-sentence passages, newlines are acceptable but must be encoded in the form body as %0A or passed directly through URL encoding utilities.
- Avoid sending extremely long strings in a single call until you benchmark latency and memory usage in your environment. Segment long text and concatenate the resulting audio on your side if needed.
If your application relies on consistent pronunciation for brand names or domain-specific terms, keep a small test suite of representative phrases in English (India) and verify output on deploys.
Saving and serving the MP3
The API returns a direct S3 URL in audio_src that you can stream to clients. For robustness, many teams persist the MP3 by downloading it after creation and serving it from their own CDN or object storage.
- Validate the envelope (error is false) before attempting to download.
- Use a safe filename convention for your own storage, and attach a unique identifier to map the file back to your request payload or user action.
- Set a reasonable timeout when fetching the MP3, and retry once or twice on transient network errors.
- Cache-control: If you re-serve the MP3 through your infrastructure, attach appropriate cache headers to match your content lifecycle.
Because the returned URL is external, your app should not assume it will remain valid indefinitely. If you require long-term availability, download and store the asset at creation time.
Error handling and operational notes
- Authentication: If the Authorization header is missing or invalid, the envelope will indicate an error and no usable audio_src will be provided.
- Free plan restriction: Free plans cannot call this /api/convert endpoint. Make sure your environment uses a plan with API access before integration.
- Timeouts: Set both connection and overall timeouts in PHP or Node.js to prevent hanging requests.
- Input validation: Ensure text is non-empty and URL-encoded in your form body.
- Retries: For transient transport errors (for example, network interruptions), retry once with backoff. Do not retry on API-level errors where error is true.
- Idempotency: If you run the same text repeatedly, expect a new audio_src each time. Cache and reuse a previous audio for identical inputs if that matches your product behavior.
- Logging: Log the message field on both success and failure for fast triage in production.
Troubleshooting common issues
1) I get an error about authentication
Confirm the Authorization header is exactly Authorization: Bearer YOUR_API_KEY. Do not place the key in the URL or the request body. Verify your plan includes API access.
2) The response is not valid JSON
Ensure Accept: application/json is present. Double-check that you are posting application/x-www-form-urlencoded and not JSON. If you read the response as text first, you can log it before attempting JSON parsing.
3) The audio link does not play
Inspect the envelope: if error is true, the audio_src is not usable. For successful conversions, verify that your network can reach S3 and that your client supports MP3 playback. If you need to ensure long-term availability, download the file and serve it from your own storage.
4) Language sounds incorrect
Make sure language=en_IN is in your form fields and that you are not overriding it elsewhere. Test with a simple phrase like Hello World to isolate locale selection from other variables.
5) The request works with cURL but fails in my code
Compare headers and encoding. Your code must send the same Accept and Authorization headers and form-encode the fields text, gender_voice, and language (and speakingRate if used). Mismatched Content-Type or JSON bodies will cause failures.
Putting it together in a PHP function
The snippet below wraps the earlier logic as a re-usable function that accepts text and returns the audio URL for English (India). This uses the same endpoint, headers, and form fields discussed above.
PHP function (reusable)
<?php
function tts_en_in($apiKey, $text) {
$apiUrl = "https://www.getwoord.com/api/convert";
$formData = http_build_query([
"text" => $text,
"gender_voice" => "male",
"language" => "en_IN",
]);
$ch = curl_init($apiUrl);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $formData,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Accept: application/json",
"Authorization: Bearer " . $apiKey,
"Content-Type: application/x-www-form-urlencoded",
],
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_TIMEOUT => 60,
]);
$body = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$errNo = curl_errno($ch);
$err = curl_error($ch);
curl_close($ch);
if ($errNo) {
throw new Exception("Transport error: " . $err);
}
if ($httpCode < 200 || $httpCode >= 300) {
throw new Exception("HTTP status " . $httpCode . " - " . $body);
}
$json = json_decode($body, true);
if (!is_array($json) || !array_key_exists("error", $json)) {
throw new Exception("Unexpected response schema: " . $body);
}
if ($json["error"] === true) {
$msg = isset($json["message"]) ? $json["message"] : "Unknown API error";
throw new Exception("API error: " . $msg);
}
if (!isset($json["audio_src"]) || !$json["audio_src"]) {
throw new Exception("Missing audio_src");
}
return $json["audio_src"];
}
// Example usage:
// $url = tts_en_in("YOUR_API_KEY", "Hello World");
// echo $url;
FAQ
Can I call the convert endpoint from a browser?
It is not recommended to expose your API key in client-side code. Call the endpoint from your server, then return only the resulting audio_src (or a proxied file) to the browser.
Which fields are required in the request body?
Send form fields text, gender_voice, and language. For English (India), set language=en_IN and gender_voice=male. The example also includes speakingRate=1.00 as a form field.
What audio format do I get back?
The audio_src points to an MP3 file you can stream or download.
Why do I get error: true in the response?
Typical causes include invalid or missing Authorization headers, or a plan that does not permit access. Free plans cannot call this endpoint.
Do I need to store the audio or can I just stream it?
You can stream directly from audio_src. For long-term control and availability, download and serve the MP3 from your own storage or CDN.
Ready to synthesize English (India) audio from PHP? Create your account now and get an API key: Register. For endpoint details and parameters, see the Documentation.
