Turkish Text-to-Speech API in Python
You need to turn Turkish text into natural-sounding speech from Python, and you want an API you can call directly with a simple POST. By the end of this guide, you will be able to authenticate with a Bearer token, send a form-encoded request to generate Turkish audio, handle the response envelope, and download the resulting MP3 using Python and curl.
What you will build and what you need to know first
This tutorial shows how to use the Woord Text-to-Speech convert endpoint to synthesize Turkish speech. You will:
- Send POST /api/convert with a Bearer token and form fields.
- Target the Turkish locale explicitly (language=tr_TR) and a male voice.
- Receive a JSON envelope that contains a direct MP3 URL.
- Download the MP3 to disk in Python safely.
Woord’s convert endpoint accepts form-encoded fields, not JSON. Free accounts cannot call this endpoint; you must register and use an API key with Bearer authentication. If you do not have an API key yet, create one here: Register.
Endpoint, HTTP method, and authentication model
The Woord Text-to-Speech convert endpoint details used in this guide:
- HTTP method: POST
- URL: https://www.getwoord.com/api/convert
- Auth: Bearer token in the Authorization header
- Body encoding: application/x-www-form-urlencoded (form fields)
Required form fields used here:
- text: the input text to speak
- gender_voice: voice gender (using the default from docs here: male)
- language: locale code (tr_TR for Turkish)
Optional field shown in the curl example below:
- speakingRate: numeric rate like 1.00
Turkish locale quick reference (language, defaults, sample)
- Language: Turkish
- language=tr_TR
- gender_voice=male (docs default)
- Sample text from editorial/docs for this locale: Hello World
Origin catalog facts (must-know reference)
The following items are copied from the official catalog. Use them exactly as shown when testing basic connectivity or comparing responses:
- Language: Turkish
- language=tr_TR
- gender_voice=male (docs default)
- Sample text from editorial/docs for this locale: Hello World
- 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=tr_TR&speakingRate=1.00"
Official convert envelope:
{"message":"Your audio has been created!","audio_src":"https://getwoord.s3.amazonaws.com/4273352455515882618255eaaf3c1cbdbe0.55443890.mp3","error":false}
The S3 filename in this envelope is a documentation fixture. The audio_src you receive at runtime will be a different key. Do not hotlink the docs fixture; use your own returned URL in your app.
One-minute smoke test with curl (labeled example)
Label: curl request — Turkish male voice, form-encoded, Bearer auth.
curl "https://www.getwoord.com/api/convert" \
-X POST \
-H "Accept: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
--data "text=Hello+World&gender_voice=male&language=tr_TR&speakingRate=1.00"
What to expect:
- HTTP 200 with a small JSON envelope if the request is valid.
- The JSON contains a message, a boolean error flag, and an audio_src URL for your MP3.
- If your token is invalid or you use a free plan, expect an error response (see the examples further below).
Python guide: POST to Woord and save the MP3
Below is a copy-pasteable Python example using the requests library. It sends the required form fields, parses the JSON envelope, validates the audio_src, downloads the MP3, and writes it to disk. The sample uses the Turkish locale tr_TR and the male voice.
Python example — end-to-end convert and download
import os
import sys
import requests
API_URL = "https://www.getwoord.com/api/convert"
API_KEY = "YOUR_API_KEY" # Bearer token
OUTPUT_PATH = "woord_tr_sample.mp3"
def convert_to_speech(text, language="tr_TR", gender_voice="male", speaking_rate="1.00"):
headers = {
"Accept": "application/json",
"Authorization": f"Bearer {API_KEY}",
}
# Form-encoded fields (not JSON)
data = {
"text": text,
"gender_voice": gender_voice,
"language": language,
"speakingRate": speaking_rate,
}
resp = requests.post(API_URL, headers=headers, data=data, timeout=30)
# Raise for non-2xx quickly; callers can catch and inspect
resp.raise_for_status()
# Expecting a small JSON envelope per docs
payload = resp.json()
if not isinstance(payload, dict):
raise ValueError("Unexpected response format (not a JSON object)")
# The documented fields to rely on:
# - message (string)
# - audio_src (string URL to mp3)
# - error (boolean)
if payload.get("error") is True:
raise RuntimeError(f"Convert error: {payload.get('message', 'Unknown error')}")
audio_src = payload.get("audio_src")
if not audio_src or not isinstance(audio_src, str) or not audio_src.startswith("https://"):
raise ValueError("Missing or invalid audio_src in response")
return payload["message"], audio_src
def download_mp3(url, dest_path):
with requests.get(url, stream=True, timeout=60) as r:
r.raise_for_status()
# Save in chunks to avoid holding large files in memory
with open(dest_path, "wb") as f:
for chunk in r.iter_content(chunk_size=8192):
if chunk:
f.write(chunk)
return dest_path
if __name__ == "__main__":
# Example input from docs for this locale
text = "Hello World"
try:
message, audio_url = convert_to_speech(text)
print(f"Convert message: {message}")
print(f"Audio URL: {audio_url}")
saved = download_mp3(audio_url, OUTPUT_PATH)
print(f"Saved MP3 to: {os.path.abspath(saved)}")
except requests.HTTPError as http_err:
# Network or non-2xx server response
print(f"HTTP error: {http_err}", file=sys.stderr)
sys.exit(1)
except Exception as exc:
print(f"Error: {exc}", file=sys.stderr)
sys.exit(1)
Notes for production:
- Always time out both the convert call and the file download to avoid deadlocks on bad networks.
- Persist the audio_src (or a pointer to it) if you plan to reuse the same speech for identical inputs to avoid repeat synthesis costs and latency.
- If you run high-volume jobs, stagger requests and implement backoff on 429/5xx responses. The endpoint uses Bearer auth; do not embed your key in client-side code.
JSON response examples you will actually use
The following examples demonstrate what you will typically parse. Values are illustrative unless otherwise stated. All envelopes use only the documented fields: message, audio_src, error.
Example 1 — Official successful envelope (from docs)
{"message":"Your audio has been created!","audio_src":"https://getwoord.s3.amazonaws.com/4273352455515882618255eaaf3c1cbdbe0.55443890.mp3","error":false}
Interpretation:
- message: informational success text.
- audio_src: direct S3 URL for your generated MP3. Do not hardcode the docs fixture in production; use your own returned URL.
- error: false means success.
Example 2 — Another successful envelope (illustrative)
{
"message": "Your audio has been created!",
"audio_src": "https://getwoord.s3.amazonaws.com/a9d1e4e088f04b8fa7e7e8c9e2e04d21.mp3",
"error": false
}
Interpretation is the same as above. Your file name will vary; store the URL immediately if you plan to download later.
Example 3 — Missing or invalid field (error=true)
{
"message": "Invalid parameter: language is required",
"audio_src": "",
"error": true
}
If you omit language or provide an unsupported value, expect error=true and a message indicating what to fix.
Example 4 — Unauthorized (error=true)
{
"message": "Unauthorized: invalid or missing API key",
"audio_src": "",
"error": true
}
Check that your Authorization header is exactly Authorization: Bearer YOUR_API_KEY and that your plan allows access to this endpoint.
Example 5 — Invalid gender or voice option (error=true)
{
"message": "Invalid parameter: gender_voice",
"audio_src": "",
"error": true
}
Use the documented gender_voice=male default for this locale unless you have confirmed alternatives in the docs.
Form fields and encoding details
The convert endpoint requires application/x-www-form-urlencoded encoding, not JSON. When using curl, pass fields with --data. In Python requests, send data= dict, not json=. Minimum fields you must include for Turkish synthesis in this guide:
- text: any UTF-8 text string to synthesize. For a quick sanity check, use Hello World as in the docs.
- gender_voice: male (docs default for this guide).
- language: tr_TR for Turkish.
Optional field shown here:
- speakingRate: string or numeric value like 1.00.
If you send these fields as JSON rather than form data, you will receive an error. Ensure that server-side frameworks forward the request body unmodified and include the correct Content-Type header if you set it manually.
Error handling, retries, and file download tips
Typical failures fall into three buckets:
- Validation errors (e.g., missing language), which return error=true and a descriptive message.
- Authentication errors, where the Authorization header is missing or the plan cannot call this endpoint.
- Transient network issues while either posting the convert request or downloading the MP3 from the audio_src URL.
Recommendations:
- On HTTP errors (non-2xx) from the POST, log status code and body. Avoid infinite retries; use exponential backoff with jitter.
- On JSON parse errors, print the raw body once to confirm you are hitting the right endpoint and that Accept: application/json is present.
- When downloading audio_src, stream the response and write in chunks; do not load the entire MP3 into memory if not needed.
- Verify the audio_src starts with https:// to avoid accidentally following a relative or unexpected URL.
Testing Turkish synthesis with reproducible inputs
To quickly validate that your environment and key are correct, use the exact sample fields below. They are minimal, known-good combinations to confirm end-to-end behavior before trying dynamic content:
- text: Hello World
- gender_voice: male
- language: tr_TR
- speakingRate: 1.00
After you receive a successful envelope, copy the audio_src to your browser or download it programmatically as shown in the Python example. Once you hear audio, replace the text with your own content.
Caching, deduplication, and storage strategy
The audio_src in the response points to a concrete MP3 file for your request. If you repeatedly send the same text, language, and voice, you can:
- Hash the input parameters (e.g., SHA-256 of text|language|gender_voice|speakingRate) and use the hash as a cache key.
- Store the returned audio_src or the downloaded MP3 under that key.
- On subsequent requests with the same key, skip synthesis and reuse the existing MP3.
This avoids unnecessary convert calls and latency. Keep your cache invalidation policy clear: if you change any field (e.g., rate or voice), the hash must change as well.
Operational guardrails for production deployments
Because free plans cannot call this endpoint, ensure you provision and securely store an API key before deploying. Operationally:
- Inject YOUR_API_KEY via environment variables or a secret manager.
- Put input validation up front (length limits, supported locales) before calling the API.
- Apply timeouts on network calls and throttle parallel conversions to protect your service.
- Capture the JSON envelope as an audit trail (message, error boolean, audio_src) along with your request ID.
If you need more specifics on optional parameters beyond those listed here, refer to the official docs: Documentation.
Troubleshooting common pitfalls
- Receiving HTML instead of JSON: verify Accept: application/json and that you are posting to the exact URL shown in this guide. Ensure form-encoded fields, not JSON.
- audio_src is missing or empty: check the error flag first. If error=true, fix the parameter described in message. If error=false but no audio_src, log the full response and contact support with the request details.
- Unauthorized with a valid key: confirm that the header is Authorization: Bearer YOUR_API_KEY and that you are not passing the key in a query string or body field.
- Timeouts on large inputs: split your text and sequence multiple calls, or validate that the network path is not filtering large POST bodies.
FAQs
Q1: Can I call the convert endpoint with a free plan?
A: No. Free cannot call convert. Use a paid plan with a valid API key and Bearer authentication.
Q2: Which fields are required in the form body for Turkish TTS?
A: text, gender_voice, and language. For this guide, use gender_voice=male and language=tr_TR. speakingRate=1.00 is shown in the curl example and may be included.
Q3: How do I download the audio after a successful convert?
A: Read audio_src from the JSON envelope and perform an HTTP GET to that URL. Stream the response and write it to an .mp3 file.
Q4: Do I send JSON or form data to the convert endpoint?
A: Send application/x-www-form-urlencoded form fields (text, gender_voice, language, and optional extras like speakingRate), not JSON.
Q5: What should I log for debugging failed conversions?
A: Log the HTTP status, full JSON envelope (message, error, audio_src), a hashed version of your request text, and the exact field values you sent (language, gender_voice, speakingRate).
Get your key and start converting Turkish text to speech
Set up your API key and run the curl or Python example above with language=tr_TR and gender_voice=male to confirm end-to-end synthesis. If you do not have access yet, create your account here: Register. For optional parameters and additional notes, see the official Documentation.
