Build for every
African voice.
Integrate speech, language and dialect capabilities into products that understand how people communicate. Use this guide to explore the Fahamu API, make your first request, and design an integration for your application.
This is the developer documentation and proposed API contract for the Fahamu platform. The endpoint paths, payloads and responses below are implementation examples, not confirmation that the routes are live. Your deployed backend must support these exact contracts before production use. Replace the example API key with a real credential issued by Fahamu.
What you can build
Use individual capabilities to create voice-first interfaces, multilingual services, accessible customer journeys and language-aware applications.
Speech to text
Turn recorded speech into structured text for search, notes, captions and voice interfaces.
Text to speech
Generate spoken audio from text for voice responses, reading assistance and conversational products.
Language translation
Translate text between supported languages while preserving the intent of the message.
Language identification
Estimate the language of a text input before routing it to the right workflow.
Dialect intelligence
Explore dialect-related signals and language variation in supported inputs.
Pronunciation feedback
Build guided speaking practice and pronunciation-feedback experiences.
Quickstart
These steps show the intended integration pattern. The sample endpoint and response are illustrative; confirm the live contract with your Fahamu backend before using it with real users.
1. Set your base URL
Use the HTTPS origin you have configured for the API. If the API is deployed on a dedicated subdomain, update the base URL to that canonical host.
2. Store your API key securely
Request an API key from the Fahamu platform operator. Store it in a server-side environment variable such as FAHAMU_API_KEY. Never put a private key in browser JavaScript, a mobile app bundle, source control or public client-side configuration.
3. Make a first request
curl -X POST "https://fahamu.co.za/api/v1/language/identify" \\ -H "Authorization: Bearer $FAHAMU_API_KEY" \\ -H "Content-Type: application/json" \\ -d '{"text":"Dumela, o kae?"}'const response = await fetch( "https://fahamu.co.za/api/v1/language/identify", { method: "POST", headers: { Authorization: `Bearer ${process.env.FAHAMU_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ text: "Dumela, o kae?" }), } ); const data = await response.json(); console.log(data);import os import requests response = requests.post( "https://fahamu.co.za/api/v1/language/identify", headers={"Authorization": f"Bearer {os.environ['FAHAMU_API_KEY']}"}, json={"text": "Dumela, o kae?"}, timeout=30, ) response.raise_for_status() print(response.json())'Dumela, o kae?']); $ch = curl_init('https://fahamu.co.za/api/v1/language/identify'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . $apiKey, 'Content-Type: application/json' ], CURLOPT_POSTFIELDS => $payload, CURLOPT_TIMEOUT => 30, ]); $result = curl_exec($ch); if ($result === false) { throw new RuntimeException(curl_error($ch)); } $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($status >= 400) { throw new RuntimeException('Fahamu API request failed: ' . $status); } echo $result;
4. Handle the response
Check the HTTP status code, parse the JSON body and handle errors. Do not assume a language prediction is always certain; design a fallback when the API returns an unsupported or uncertain result.
Authentication
For the proposed v1 contract, send your API key as a bearer token in the Authorization header on every protected request.
Authorization: Bearer YOUR_FAHAMU_API_KEY
Content-Type: application/json
Accept: application/jsonFor browser or mobile applications, route requests through your own backend. Apply authentication, usage limits and access controls there so a private key cannot be extracted from the client.
Recommended key practices
- Keep secrets in environment variables or a managed secrets vault.
- Use separate credentials for development, staging and production.
- Rotate credentials if they are exposed; revoke old keys promptly.
- Redact authorization headers from application logs and error reports.
- Issue only the access and quota a service needs.
Requests & responses
Request format
JSON endpoints accept an HTTPS POST request with a JSON body. Audio endpoints may instead use multipart/form-data for file uploads, depending on the deployed backend implementation.
| Header / field | Purpose | Example |
|---|---|---|
Authorization | Authenticates the caller | Bearer … |
Content-Type | Describes the request body | application/json |
text | Text to analyze, translate or synthesize | "Dumela" |
source_language | Optional source language identifier | "en" |
target_language | Requested target language | "zu" |
Response envelope
A consistent response shape makes integrations easier to maintain. The following is a suggested pattern; align it with the actual API implementation.
{
"success": true,
"data": {
"language": "zu",
"confidence": 0.94
},
"request_id": "req_example_123"
}Use the returned request identifier, if implemented, when reporting issues to the platform team. Avoid logging raw user audio or sensitive text unless you have a lawful purpose and appropriate safeguards.
API reference
The endpoints below form a proposed v1 interface for the capabilities described on the Fahamu platform. Routes, accepted language codes, file constraints and response fields must be confirmed against the deployed service.
Speech to text
Transcribe a supported audio file into text. Use this capability for voice search, dictation, meeting notes, voice interfaces and captioning workflows.
/speech/transcriptionsSuggested content type:
multipart/form-data with an audio file field named file.Request example
curl -X POST "https://fahamu.co.za/api/v1/speech/transcriptions" \\ -H "Authorization: Bearer $FAHAMU_API_KEY" \\ -F "file=@recording.wav" \\ -F "language=zu"import fs from "node:fs"; const form = new FormData(); form.append("file", new Blob([fs.readFileSync("recording.wav")]), "recording.wav"); form.append("language", "zu"); const response = await fetch("https://fahamu.co.za/api/v1/speech/transcriptions", { method: "POST", headers: { Authorization: `Bearer ${process.env.FAHAMU_API_KEY}` }, body: form, }); console.log(await response.json());import os, requests with open("recording.wav", "rb") as audio: response = requests.post( "https://fahamu.co.za/api/v1/speech/transcriptions", headers={"Authorization": f"Bearer {os.environ['FAHAMU_API_KEY']}"}, files={"file": ("recording.wav", audio, "audio/wav")}, data={"language": "zu"}, timeout=120, ) response.raise_for_status() print(response.json())new CURLFile(__DIR__.'/recording.wav', 'audio/wav'), 'language' => 'zu']; curl_setopt_array($ch, [CURLOPT_POST=>true, CURLOPT_RETURNTRANSFER=>true, CURLOPT_HTTPHEADER=>['Authorization: Bearer '.getenv('FAHAMU_API_KEY')], CURLOPT_POSTFIELDS=>$post]); $result = curl_exec($ch); if ($result === false) throw new RuntimeException(curl_error($ch)); echo $result; curl_close($ch);
Response example
{
"success": true,
"data": {
"text": "Sawubona, ngingakusiza ngani?",
"language": "zu"
},
"request_id": "req_example_124"
}The response includes the recognized transcript, detected language and request identifier. Send supported audio formats and a language code to receive the best transcription results.
Text to speech
Convert text into spoken audio for voice assistants, read-aloud tools, accessibility features and audio-first experiences.
/speech/synthesisSuggested content type:
application/json.curl -X POST "https://fahamu.co.za/api/v1/speech/synthesis" \\ -H "Authorization: Bearer $FAHAMU_API_KEY" \\ -H "Content-Type: application/json" \\ -d '{"text":"Welcome to Fahamu.","language":"en","format":"mp3"}'const response = await fetch("https://fahamu.co.za/api/v1/speech/synthesis", { method: "POST", headers: { Authorization: `Bearer ${process.env.FAHAMU_API_KEY}`, "Content-Type": "application/json" }, body: JSON.stringify({ text: "Welcome to Fahamu.", language: "en", format: "mp3" }), }); if (!response.ok) throw new Error(`HTTP ${response.status}`); // If the service returns audio bytes: const audio = Buffer.from(await response.arrayBuffer());import os, requests response = requests.post( "https://fahamu.co.za/api/v1/speech/synthesis", headers={"Authorization": f"Bearer {os.environ['FAHAMU_API_KEY']}"}, json={"text":"Welcome to Fahamu.", "language":"en", "format":"mp3"}, timeout=60) response.raise_for_status() # This assumes the endpoint responds with audio bytes. with open("speech.mp3", "wb") as f: f.write(response.content)'Welcome to Fahamu.', 'language'=>'en', 'format'=>'mp3']); $ch = curl_init('https://fahamu.co.za/api/v1/speech/synthesis'); curl_setopt_array($ch, [CURLOPT_POST=>true, CURLOPT_RETURNTRANSFER=>true, CURLOPT_HTTPHEADER=>['Authorization: Bearer '.getenv('FAHAMU_API_KEY'),'Content-Type: application/json'], CURLOPT_POSTFIELDS=>$payload]); $audio = curl_exec($ch); if ($audio === false) throw new RuntimeException(curl_error($ch)); file_put_contents('speech.mp3', $audio); curl_close($ch);
Confirm supported voice IDs, language variants, output formats, text limits and whether the response is raw audio or a JSON payload.
Language translation
Translate a text string from a known source language to a target language. For reliable UX, let users review translations in high-impact contexts.
/language/translationscurl -X POST "https://fahamu.co.za/api/v1/language/translations" \\ -H "Authorization: Bearer $FAHAMU_API_KEY" \\ -H "Content-Type: application/json" \\ -d '{"text":"Good morning","source_language":"en","target_language":"zu"}'const response = await fetch("https://fahamu.co.za/api/v1/language/translations", { method: "POST", headers: { Authorization: `Bearer ${process.env.FAHAMU_API_KEY}`, "Content-Type": "application/json" }, body: JSON.stringify({ text: "Good morning", source_language: "en", target_language: "zu" }), }); console.log(await response.json());import os, requests r = requests.post("https://fahamu.co.za/api/v1/language/translations", headers={"Authorization": f"Bearer {os.environ['FAHAMU_API_KEY']}"}, json={"text":"Good morning", "source_language":"en", "target_language":"zu"}, timeout=60) r.raise_for_status(); print(r.json())'Good morning','source_language'=>'en','target_language'=>'zu']); $ch = curl_init('https://fahamu.co.za/api/v1/language/translations'); curl_setopt_array($ch,[CURLOPT_POST=>true,CURLOPT_RETURNTRANSFER=>true, CURLOPT_HTTPHEADER=>['Authorization: Bearer '.getenv('FAHAMU_API_KEY'),'Content-Type: application/json'],CURLOPT_POSTFIELDS=>$body]); $out=curl_exec($ch); if($out===false) throw new RuntimeException(curl_error($ch)); echo $out; curl_close($ch);
Response example
{
"success": true,
"data": {
"translated_text": "Sawubona",
"source_language": "en",
"target_language": "zu"
},
"request_id": "req_example_125"
}Translation quality and available language pairs depend on the models deployed and evaluated by Fahamu. The output shown is a format example, not a verified translation result.
Language identification
Estimate which language a text sample is written in. This can help select a downstream model, route a customer-support interaction or tailor a learning experience.
/language/identifycurl -X POST "https://fahamu.co.za/api/v1/language/identify" \\ -H "Authorization: Bearer $FAHAMU_API_KEY" \\ -H "Content-Type: application/json" \\ -d '{"text":"Dumela, o kae?"}'const r = await fetch("https://fahamu.co.za/api/v1/language/identify", { method: "POST", headers: { Authorization: `Bearer ${process.env.FAHAMU_API_KEY}`, "Content-Type": "application/json" }, body: JSON.stringify({ text: "Dumela, o kae?" }), }); if (!r.ok) throw new Error(`HTTP ${r.status}`); console.log(await r.json());import os, requests r = requests.post("https://fahamu.co.za/api/v1/language/identify", headers={"Authorization": f"Bearer {os.environ['FAHAMU_API_KEY']}"}, json={"text":"Dumela, o kae?"}, timeout=30) r.raise_for_status(); print(r.json())true,CURLOPT_RETURNTRANSFER=>true, CURLOPT_HTTPHEADER=>['Authorization: Bearer '.getenv('FAHAMU_API_KEY'),'Content-Type: application/json'], CURLOPT_POSTFIELDS=>json_encode(['text'=>'Dumela, o kae?'])]); $r=curl_exec($ch); if($r===false) throw new RuntimeException(curl_error($ch)); echo $r; curl_close($ch);
Response example
{
"success": true,
"data": {
"language": "st",
"confidence": 0.91
},
"request_id": "req_example_126"
}Language tags and confidence scoring must match the production model. Short phrases, code-switching, names and similar languages can make identification uncertain.
Dialect analysis
Analyze language variation for applications that need more than a broad language label. A dialect model should be evaluated against representative speakers, regions and real-world recording conditions before results are used to make decisions.
/language/dialect-analysiscurl -X POST "https://fahamu.co.za/api/v1/language/dialect-analysis" \\ -H "Authorization: Bearer $FAHAMU_API_KEY" \\ -H "Content-Type: application/json" \\ -d '{"text":"Ke teng, ke a leboga.","language":"st"}'const r = await fetch("https://fahamu.co.za/api/v1/language/dialect-analysis", { method: "POST", headers: { Authorization: `Bearer ${process.env.FAHAMU_API_KEY}`, "Content-Type": "application/json" }, body: JSON.stringify({ text: "Ke teng, ke a leboga.", language: "st" }), }); console.log(await r.json());import os, requests r = requests.post("https://fahamu.co.za/api/v1/language/dialect-analysis", headers={"Authorization": f"Bearer {os.environ['FAHAMU_API_KEY']}"}, json={"text":"Ke teng, ke a leboga.", "language":"st"}, timeout=60) r.raise_for_status(); print(r.json())
The dialect labels, confidence scores and supported input modalities are not specified here because they must be defined by the actual deployed model.
Pronunciation feedback
Use pronunciation feedback to power language-learning activities, guided practice and speech coaching. The example shows a conceptual audio-plus-target-text workflow; Send the audio file and target text to receive pronunciation feedback.
/speech/pronunciation-feedbackRequest fields: audio file, target text and language code.
curl -X POST "https://fahamu.co.za/api/v1/speech/pronunciation-feedback" \\ -H "Authorization: Bearer $FAHAMU_API_KEY" \\ -F "file=@practice.wav" \\ -F "target_text=Good morning" \\ -F "language=en"import os, requests with open("practice.wav", "rb") as audio: r = requests.post("https://fahamu.co.za/api/v1/speech/pronunciation-feedback", headers={"Authorization": f"Bearer {os.environ['FAHAMU_API_KEY']}"}, files={"file": ("practice.wav", audio, "audio/wav")}, data={"target_text":"Good morning", "language":"en"}, timeout=120) r.raise_for_status(); print(r.json())
Accent and pronunciation are tied to identity. Explain what is measured, avoid presenting a single accent as inherently correct, and test performance across age, gender, region, disability and recording conditions. Do not use scores alone for hiring, education placement or other high-impact decisions.
Language examples
Fahamu can be consumed from any HTTP client. Select your language to see a complete HTTPS request using the Fahamu API. The examples use standard HTTP clients and bearer-token authentication.
JavaScript / Node.js
Use native fetch on supported Node versions. Keep API calls on the server and read the key from environment variables.
Python
Use requests or an async HTTP client. Set explicit timeouts and call raise_for_status() before processing output.
PHP
Use cURL or your framework's HTTP client. Check transport errors and HTTP status before treating a response as successful.
cURL
Great for quick integration tests from a terminal or CI job. Store secrets in environment variables, not shell history.
Environment setup
export FAHAMU_API_KEY='replace_with_your_real_key'
# Do not commit this value to source control.Client integration pattern
- Collect input and validate it before sending the request.
- Send HTTPS requests from a trusted server environment.
- Handle non-2xx responses, timeouts and network failures.
- Validate the response schema before using returned fields.
- Provide a user-friendly fallback if a language or audio type is unsupported.
Errors & troubleshooting
Use HTTP status codes and a structured error body to help diagnose failures. Use the following HTTP status codes to diagnose request failures and handle retries consistently.
| HTTP status | Meaning | What to check |
|---|---|---|
400 | Bad request | Required fields, JSON syntax, language codes and file fields. |
401 | Unauthenticated | Missing, expired or invalid API key; correct bearer header. |
403 | Forbidden | Key permissions, product access or account status. |
404 | Route not found | Base URL, API version, reverse-proxy rules and deployed route. |
413 | Payload too large | Upload size limit and audio duration. |
415 | Unsupported media type | Content-Type and accepted audio encoding. |
422 | Validation failed | Input values or required parameters. |
429 | Rate limit exceeded | Account quota; back off and retry only when appropriate. |
500 | Server error | Retry cautiously; provide request ID to support. |
503 | Temporarily unavailable | Service health, upstream dependency or maintenance. |
Suggested error body
{
"success": false,
"error": {
"code": "invalid_request",
"message": "The text field is required."
},
"request_id": "req_example_127"
}Retry strategy
- Do not repeatedly retry validation errors (400, 401, 403, 422) without changing the request.
- For 429 or transient 5xx errors, use exponential backoff with jitter and respect any
Retry-Afterheader returned by the server. - Use reasonable request timeouts, especially for audio processing.
- For operations that create jobs or incur usage charges, confirm idempotency behavior before automatic retries.
Security & privacy
- Use HTTPS for every request. Never disable certificate verification in production.
- Never expose server-side API keys in frontend code or public repositories.
- Collect only the audio and text necessary to provide the feature.
- Tell users when voice or text is processed by an AI system and obtain consent where required.
- Define retention, deletion, access controls and incident response before processing sensitive information.
- Review applicable South African privacy requirements, including POPIA, and any laws relevant to your users and deployment locations.
- For accessibility use cases, provide alternatives when recognition is uncertain and avoid treating automated output as infallible.
Production checklist
Use this checklist with the API team to confirm the documentation matches the deployed service.
- Confirm DNS, TLS certificate and API base URL.
- Verify every documented route in staging and production.
- Issue real API credentials and define key rotation/revocation.
- Publish supported languages, dialects, voices and audio formats.
- Specify request limits, maximum file size/duration, quotas and pricing.
- Document synchronous vs asynchronous processing and response formats.
- Implement consistent error objects and request IDs.
- Configure monitoring, rate limiting, abuse protection and service-health reporting.
- Test language quality and accessibility with representative users.
- Publish privacy, retention and support contact information.
Frequently asked questions
How do I call the API?
Send an HTTPS request to the endpoint with your API key in the Authorization header. Use the language tabs in each endpoint guide to copy a request for your preferred environment.
Where do I get an API key?
API access and key issuance must be provided by the Fahamu platform operator. Do not use the placeholder key in examples.
Which African languages are supported?
Pass the language code supported by the endpoint and your use case. Your account configuration determines access to available language and dialect capabilities.
Can I call the API directly from a browser?
For private-key authentication, use your own backend as a proxy. Direct browser calls can expose secrets and may also require CORS configuration.
Do you provide official SDKs?
This documentation provides HTTP examples for cURL, JavaScript/Node.js, Python and PHP.
How should I report an issue?
Capture the endpoint, approximate timestamp, HTTP status and request ID if returned. Never send passwords, API keys or unnecessary user audio/text in a support report.