# Namu API > Speech models for the languages of the Sahel: text to speech, speech to text, translation and voice conversation. Beta: free, 30 minutes of audio a month per account. Base URL: https://api.namuai-lab.com Auth: send `Authorization: Bearer $NAMU_API_KEY` on every request. Create a key at https://www.namuai-lab.com/account/keys and keep it on a server, never in a web page or mobile app. Docs: https://developers.namuai-lab.com (guides, API reference, SDKs) SDKs: `pip install namu-ai` (Python 3.9+) and `npm install namu-ai` (Node 18+, server side only). Both read NAMU_API_KEY. Source: https://github.com/namu-ai-lab/namu-sdks ## First request ```bash curl https://api.namuai-lab.com /v1/speech \ -H "Authorization: Bearer $NAMU_API_KEY" \ -H "Content-Type: application/json" \ -d '{"text": "Barka da safiya! Ga labaran yau.", "voice": "nadia"}' \ -o labarai.wav ``` With the Python SDK: ```python from namu import Namu client = Namu(base_url="https://api.namuai-lab.com\n") # reads NAMU_API_KEY audio = client.speech("Barka da safiya! Ga labaran yau.", voice="nadia") open("labarai.wav", "wb").write(audio) ``` With the JavaScript SDK: ```javascript import { writeFile } from "node:fs/promises"; import { Namu } from "namu-ai"; const namu = new Namu({ baseUrl: "https://api.namuai-lab.com\n" }); // reads NAMU_API_KEY const audio = await namu.speech("Barka da safiya! Ga labaran yau.", { voice: "nadia" }); await writeFile("labarai.wav", Buffer.from(audio)); ``` ## Models - Speech synthesis (text to speech): POST /v1/speech. Languages: Hausa (ha), French (fr), Zarma (dje). Status: beta. - Speech recognition (speech to text): POST /v1/transcribe. Languages: Hausa (ha), Zarma (dje), French (fr). Status: beta. - Translation (translation): POST /v1/translate. Languages: Hausa (ha), French (fr). Directions: ha→fr, fr→ha. Status: beta. - Voice agent (voice conversation): POST /v1/converse. Languages: Hausa (ha). Status: research. ## Languages - Hausa (ha): text to speech, speech to text, translation, voice conversation - Zarma (dje): text to speech, speech to text - Fulfulde (ff): coming - Tamasheq (tmh): coming - French (fr): text to speech, speech to text, translation ## Voices - nadia: Hausa, female - fr: French - mouhamad: Zarma, Hausa, male ## Endpoints ### Text to speech: POST /v1/speech Turns Hausa, Zarma or French text into speech, in a voice. A voice may speak several languages. Send JSON. - `text`: Required. Up to 2,000 characters. - `voice`: nadia (Hausa, the default; warm is the same voice), mouhamad (Zarma and Hausa) or fr (French). See GET /v1/voices. - `language`: The language of the text: ha, dje or fr, one the voice speaks. Optional: without it the voice speaks its first language (mouhamad: Zarma). - `format`: wav (default), mp3, opus (Ogg Opus, for WhatsApp voice notes) or json (base64 WAV in JSON). Returns: audio/wav (24 kHz mono), audio/mpeg or audio/ogg, with the duration in the X-Audio-Seconds header. With format json: { model, voice, language, audio_seconds, audio (base64 WAV), sample_rate }. ```bash curl https://api.namuai-lab.com /v1/speech \ -H "Authorization: Bearer $NAMU_API_KEY" \ -H "Content-Type: application/json" \ -d '{"text": "Barka da safiya! Ga labaran yau.", "voice": "nadia"}' \ -o labarai.wav ``` ### Speech to text: POST /v1/transcribe Transcribes Hausa, Zarma or French speech. Send the audio as the raw request body (with language in the query string) or as a multipart field named file. The text comes in lower case, without punctuation. - `file`: WAV, MP3, M4A, AAC, OGG, WebM or FLAC; up to 25 MB and 5 minutes. - `language`: The language spoken: ha (the default), dje or fr. It is not detected: send the one you expect. Returns: { model, text, language, audio_seconds } ```bash curl https://api.namuai-lab.com /v1/transcribe \ -H "Authorization: Bearer $NAMU_API_KEY" \ -F file=@labarai.wav ``` ### Speech translation: POST /v1/translate Hausa to French or French to Hausa, from speech or from text. For text, send JSON instead of audio. - `file`: The spoken audio, as for /v1/transcribe. - `text`: Or, in JSON, the text to translate: up to 2,000 characters. It counts as the time it takes to say (about 15 characters a second). - `target`: fr (default) or ha. - `source`: ha or fr, the language of the input. Optional: without it, the other language from target. - `include_audio`: true to also receive the translation spoken (base64 WAV). Returns: { model, source, target, source_text, text, audio_seconds | characters, audio? } ```bash curl https://api.namuai-lab.com /v1/translate \ -H "Authorization: Bearer $NAMU_API_KEY" \ -F file=@question.wav -F target=fr ``` Text: ```bash curl https://api.namuai-lab.com /v1/translate \ -H "Authorization: Bearer $NAMU_API_KEY" \ -H "Content-Type: application/json" \ -d '{"text": "Bonjour à tous.", "source": "fr", "target": "ha"}' ``` ### Voice conversation (research): POST /v1/converse One spoken turn with a Hausa voice agent. Each call stands alone: the agent answers this turn only and remembers nothing from earlier calls. Namu keeps no conversation: its database holds only metadata about the call (duration, status, timing), and the words heard are sent to the language model provider, Google Gemini through OpenRouter, to write the reply. In research: behaviour may change. New keys cannot call it: tick Voice agent when you create the key, or the answer is 403 insufficient_scope. - `file`: The user’s spoken turn. - `persona`: nadia (the default and, for now, the only value). - `session_id`: Optional, up to 100 characters, returned as sent. It is not stored and does not carry memory between calls. Returns: { model, persona, session_id, heard, reply, audio, sample_rate, audio_seconds } ```bash curl https://api.namuai-lab.com /v1/converse \ -H "Authorization: Bearer $NAMU_API_KEY" \ -F file=@turn.wav -F persona=nadia ``` ## Errors Errors are JSON: { "error": { "type", "message", "request_id" } }; every response also carries X-Request-Id. Retry 429 after the Retry-After header, and 502 or 504 after a short wait. A request that fails counts nothing against your allowance. - 400 invalid_json · invalid_request · missing_text · missing_file · empty_audio · unknown_voice · unsupported_language · unsupported_pair · unknown_persona: The request is incomplete, or names a voice, language or persona the model does not offer. - 401 missing_api_key · invalid_api_key · key_revoked: No key, an unknown key, or a revoked one. - 403 account_paused · insufficient_scope: The account is paused, or the key may not call this model. - 413 payload_too_large · audio_too_long · text_too_long: Over a request limit (below). - 404 not_found: No such endpoint. - 405 method_not_allowed: The endpoint does not take that method. - 415 unsupported_audio: The audio is not WAV, MP3, M4A, AAC, OGG, WebM or FLAC, or could not be decoded. - 422 nothing_heard: Translate or converse heard no speech in the audio. - 429 rate_limited · quota_exceeded: Too many requests this minute (for this key, or with unknown keys from one address), or the monthly allowance is used up. - 500 internal_error · encode_failed: Something failed on our side, or the speech could not be encoded in that format. Safe to retry; if it persists, send us the request_id. - 502 upstream_error: A model service did not answer. Safe to retry. - 503 auth_unavailable: Keys could not be checked for a moment. Safe to retry. - 504 upstream_timeout: A model took too long, often while it was waking up. Safe to retry. - Other http_error: Any other HTTP error, with its status code. ## Limits - Audio per request: 25 MB and 5 minutes - Text per request: 2,000 characters - Requests: 60 per minute per key (can be raised) - Monthly audio: 30 minutes per account during the beta (can be raised) - Active keys: 10 per account - First request: slower while a model wakes up - Long requests: the API waits for the model, up to 14 minutes: keep your client's timeout generous - Text per speech request: 2000 characters