English (Australia) Text-to-Speech API in PHP
You need to turn English (Australia) text into speech from PHP, using a simple HTTP call that returns a direct MP3 URL. By the end of this guide, you will be able to authenticate with a Bearer token, submit text using form fields, and programmatically save the resulting audio for your application.
What you will build and the constraints to be aware of
This guide focuses on creating English (Australia) speech using the Woord Text-to-Speech convert endpoint from PHP. You will submit a short text (Hello World), choose the male voice, and explicitly set the Australian locale. The endpoint returns JSON with a direct S3 URL to the MP3 you can download or cache. Important constraint: free accounts cannot call this convert endpoint; make sure your account has access before you start.
- Language: English (Australia)
- language=en_AU
- gender_voice=male (docs default)
- Sample text: Hello World
- Endpoint: POST https://www.getwoord.com/api/convert
- Authorization: Bearer YOUR_API_KEY
- Body encoding: form fields (not JSON)
We will also cover operational details that save time in production: choosing parameters, handling server responses, reliably saving MP3 files, retry logic, and caching strategies for repeated inputs.
Endpoint, authentication and request format
Woord exposes a single convert endpoint that you can call with a POST. You must pass a Bearer token in the Authorization header. The request body should be URL-encoded form fields, not JSON. The endpoint returns a small JSON envelope indicating success and the final MP3 URL.
- URL: https://www.getwoord.com/api/convert
- Method: POST
- Headers:
- Accept: application/json
- Authorization: Bearer YOUR_API_KEY
- Body (form fields):
- text: the content to synthesize (e.g., Hello World)
- gender_voice: male
- language: en_AU
- speakingRate: 1.00 (shown in the official sample)
Do not send JSON in the request body. Form fields are required. Also, do not use placeholders with braces; pass actual values (e.g., Hello World).
Official cURL request and response
The following command and JSON are the official samples. Copy them to verify your setup works end-to-end. Replace only YOUR_KEY with your token.
cURL (official sample):
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_AU&speakingRate=1.00"
JSON (official sample envelope):
{
"message": "Your audio has been created!",
"audio_src": "https://getwoord.s3.amazonaws.com/4273352455515882618255eaaf3c1cbdbe0.55443890.mp3",
"error": false
}
Field usage:
- message: human-readable status. Use it for logs.
- audio_src: the final MP3 URL you can download. This URL is a docs fixture; your call returns a new key.
- error: boolean flag. Check it before attempting to download audio.
Do not hotlink the example S3 URL above in your app; your own requests will produce a unique audio_src that you should use instead.
Parameters to produce English (Australia) speech
For the locale in this article, ensure the following form fields are set exactly:
- language=en_AU
- gender_voice=male
- text=Hello World (or your own content)
- Optional: speakingRate=1.00 (as in the official cURL sample)
language=en_AU enforces English (Australia). gender_voice=male uses the default male voice for this locale. The minimal viable call is exactly the official cURL shown above, which you can adapt in your code.
PHP implementation: sending the request and saving the MP3
The following PHP example uses curl_init to post form fields and then saves the resulting MP3. It mirrors the official cURL parameters and headers. Replace only YOUR_API_KEY with your token.
Code: PHP (curl_init)
<?php
$apiUrl = "https://www.getwoord.com/api/convert";
$apiKey = "YOUR_API_KEY"; // Free cannot call this endpoint
// Form fields: must be application/x-www-form-urlencoded
$postFields = http_build_query([
"text" => "Hello World",
"gender_voice" => "male",
"language" => "en_AU",
"speakingRate" => "1.00"
]);
$ch = curl_init($apiUrl);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Accept: application/json",
"Authorization: Bearer " . $apiKey,
"Content-Type: application/x-www-form-urlencoded"
],
CURLOPT_POSTFIELDS => $postFields,
// Optional: timeouts to avoid hanging connections
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);
if ($curlErrNo !== 0) {
// Network or cURL-level failure
error_log("cURL error: " . $curlErr);
http_response_code(502);
exit("Upstream request failed");
}
if ($httpCode < 200 || $httpCode >= 300) {
// Handle non-2xx statuses
error_log("Unexpected HTTP status: " . $httpCode . " Body: " . $responseBody);
http_response_code(502);
exit("Non-2xx status from TTS service");
}
$payload = json_decode($responseBody, true);
if (!is_array($payload)) {
error_log("Invalid JSON: " . $responseBody);
http_response_code(502);
exit("Bad JSON from TTS service");
}
if (!empty($payload["error"])) {
error_log("TTS indicated error: " . ($payload["message"] ?? "Unknown error"));
http_response_code(502);
exit("TTS reported an error");
}
$audioUrl = $payload["audio_src"] ?? "";
if ($audioUrl === "") {
error_log("No audio_src in response: " . $responseBody);
http_response_code(502);
exit("Missing audio URL");
}
// Download and persist the MP3
$mp3 = file_get_contents($audioUrl);
if ($mp3 === false) {
error_log("Failed to download audio from: " . $audioUrl);
http_response_code(502);
exit("Audio download failed");
}
// Save to disk (ensure directory is writable)
$filename = __DIR__ . "/en_AU_hello_world.mp3";
if (file_put_contents($filename, $mp3) === false) {
error_log("Failed to write file: " . $filename);
http_response_code(500);
exit("Could not save audio");
}
echo "Saved audio to: " . $filename;
Notes:
- Send form fields using application/x-www-form-urlencoded.
- Check the error boolean before using audio_src.
- Persist the returned MP3 promptly so you do not rely on a transient remote URL.
Python example to match the PHP workflow
If you also need a quick script to verify your account or parallel your PHP logic locally, this Python example performs the same POST and saves the MP3 it receives.
Code: Python (requests)
import requests
import sys
api_url = "https://www.getwoord.com/api/convert"
api_key = "YOUR_API_KEY" # Free cannot call this endpoint
headers = {
"Accept": "application/json",
"Authorization": f"Bearer {api_key}",
}
data = {
"text": "Hello World",
"gender_voice": "male",
"language": "en_AU",
"speakingRate": "1.00",
}
resp = requests.post(api_url, headers=headers, data=data, timeout=60)
if resp.status_code // 100 != 2:
print(f"HTTP {resp.status_code} - {resp.text}", file=sys.stderr)
sys.exit(1)
payload = resp.json()
if payload.get("error"):
print(f"Service error: {payload.get('message')}", file=sys.stderr)
sys.exit(1)
audio_src = payload.get("audio_src", "")
if not audio_src:
print(f"Missing audio_src: {payload}", file=sys.stderr)
sys.exit(1)
mp3 = requests.get(audio_src, timeout=60)
if mp3.status_code // 100 != 2:
print(f"Failed to fetch audio {audio_src}: {mp3.status_code}", file=sys.stderr)
sys.exit(1)
with open("en_AU_hello_world.mp3", "wb") as f:
f.write(mp3.content)
print("Saved en_AU_hello_world.mp3")
Multiple response examples you should be ready to handle
Success responses will have error: false and a populated audio_src. Errors will set error: true and include a message you can log. Below are several complete examples so you can build realistic parsers and tests.
Success (official fixture):
{
"message": "Your audio has been created!",
"audio_src": "https://getwoord.s3.amazonaws.com/4273352455515882618255eaaf3c1cbdbe0.55443890.mp3",
"error": false
}
Success (another typical success):
{
"message": "Your audio has been created!",
"audio_src": "https://getwoord.s3.amazonaws.com/9b90e7c4b4a641cfa1c1b957a0a1c5a2a1.12345678.mp3",
"error": false
}
Authentication failure (Bearer token issue):
{
"message": "Authentication failed: invalid API key",
"audio_src": "",
"error": true
}
Missing field (language or text omitted):
{
"message": "Bad request: required field missing",
"audio_src": "",
"error": true
}
Service temporarily unavailable (transient error):
{
"message": "Please retry later",
"audio_src": "",
"error": true
}
In all cases, use the error flag to branch logic. If error is false, proceed to fetch audio_src; if true, surface the message to logs and decide whether a retry is appropriate.
Practical implementation details for production
These details will save you time when you move from a single test script to a production integration.
- Idempotency and caching: When synthesizing the same text, language=en_AU and gender_voice=male combination repeatedly, compute a stable cache key (for example, a SHA-256 hash of the normalized input and parameters). If you already have an MP3 file for this key, serve it from your storage layer instead of calling the API again.
- Normalization: Normalize whitespace and punctuation in text before hashing to avoid duplicate but near-identical entries like trailing spaces causing cache misses.
- Timeouts: Set both connect and overall timeouts (e.g., 10s connect, 60s total) so hung sockets do not stall your web workers.
- Retries: Only retry safe failure modes (network timeouts or HTTP 5xx from your download of audio_src). Do not blindly retry 4xx authentication errors.
- Concurrency: If you call the endpoint in batch, throttle concurrent calls in your job queue to stay within your plan’s operational boundaries. The documentation is the source of truth for any plan-based execution rules.
- Persistence: Download the MP3 from audio_src immediately and store it in your own bucket or file store. Treat audio_src as a transient delivery URL.
- Metrics: Log message, error, and timing (request and download durations). Aggregate by language=en_AU to track locale-specific performance.
- Security: Keep YOUR_API_KEY out of client-side code and public repos. Inject it through environment variables on the server side.
Testing English (Australia) end-to-end
Below is a short process to verify your stack is correct from request to persisted MP3. Use the same values across tools so differences are traceable.
- Run the official cURL with Hello World, gender_voice=male, language=en_AU. Confirm you receive error: false and a valid audio_src.
- Paste the audio_src into a separate terminal with curl -I to confirm it returns a 200 OK and content-type audio/mpeg.
- Run the PHP sample. Ensure it saves en_AU_hello_world.mp3 and that the content is not zero bytes.
- Listen locally to confirm the accent and phrasing meet your expectations for English (Australia).
- Repeat with slightly different text to validate cache logic in your application.
Common pitfalls and how to avoid them
- Sending JSON instead of form fields: The convert endpoint expects URL-encoded form fields. If you post JSON, you may receive a 4xx error or an error: true response.
- Omitting headers: Both Accept: application/json and Authorization: Bearer YOUR_API_KEY are required to match the official sample.
- Wrong locale: language must be en_AU for English (Australia). Do not substitute other locales in this guide.
- Placeholder mistakes: Avoid curly-brace placeholders in final code. Pass literal values.
- Relying on docs fixture URL: Do not hardcode the official sample’s audio_src; always read the runtime value and use that.
- Free account usage: Free cannot call this endpoint. If your calls fail with authentication or plan errors, upgrade after you register.
Minimal alternative: PHP using file_get_contents for the POST
If you prefer a very compact approach and your PHP environment allows it, this example posts using file_get_contents with a stream context. It is concise but offers less granular control than curl_init.
Code: PHP (file_get_contents POST)
<?php
$apiUrl = "https://www.getwoord.com/api/convert";
$apiKey = "YOUR_API_KEY"; // Free cannot call this endpoint
$postData = http_build_query([
"text" => "Hello World",
"gender_voice" => "male",
"language" => "en_AU",
"speakingRate" => "1.00"
]);
$opts = [
"http" => [
"method" => "POST",
"header" => "Accept: application/json\r\n"
. "Authorization: Bearer {$apiKey}\r\n"
. "Content-Type: application/x-www-form-urlencoded\r\n",
"content" => $postData,
"timeout" => 60
]
];
$context = stream_context_create($opts);
$response = file_get_contents($apiUrl, false, $context);
if ($response === false) {
exit("Failed to reach TTS service");
}
$payload = json_decode($response, true);
if (!is_array($payload) || !empty($payload["error"])) {
exit("Service error: " . ($payload["message"] ?? "Unknown"));
}
$audioUrl = $payload["audio_src"] ?? "";
$audio = file_get_contents($audioUrl);
file_put_contents("en_AU_hello_world_min.mp3", $audio);
echo "Saved en_AU_hello_world_min.mp3";
Operational notes: encoding, length, and content
Keep these details in mind for reliable synthesis and playback:
- Form encoding: Ensure application/x-www-form-urlencoded is set and values are URL-encoded. For example, Hello World should be encoded as Hello+World in raw cURL data as shown.
- Text length: If you plan to send long text, consider chunking by sentence boundaries and concatenating audio on your server, or consult the Documentation for any guidance.
- Audio format: The convert response is an MP3 file at the provided audio_src. Save as .mp3 and set Content-Type to audio/mpeg if you stream it back to clients.
- Timekeeping: If you log events, normalize timestamps to UTC and record both request and download durations to quickly detect network slowness versus synthesis time.
- Storage: Keep a writeable directory or a configured bucket for MP3 persistence; avoid serving the upstream audio_src directly to end users for long-term use.
FAQ
Can I call convert with a free account?
No. Free cannot call this endpoint. Use a paid plan to access convert.
Do I send JSON in the request body?
No. The body must be form fields: text, gender_voice, language (and optional speakingRate=1.00 as shown). The response is JSON.
What locale and voice should I use for English (Australia)?
Use language=en_AU and gender_voice=male to match this guide and the docs default.
How do I download the audio file?
Read audio_src from the JSON response and issue a regular HTTP GET. Save the bytes as an .mp3 file.
How do I ensure repeatable results?
Normalize your text and cache by a stable key combining language=en_AU and gender_voice=male. Store the MP3 locally so your app does not depend on repeated upstream synthesis.
Ready to implement this in your stack? Create your account and get your API key here: Register. For complete parameter references and any updates, consult the Documentation.
