Skip to content

Before you launch, make sure your API key stays private, your code handles errors and limits properly, and your API balance can't run dry unnoticed.

Keep your key on the server

Call MenaVoice from your backend, never from browser or mobile app code. A key shipped to a client can be extracted and used to spend your credit. The API also refuses cross-origin requests from other websites' browser code, so a front-end call fails with a CORS error anyway.

The usual pattern is a small endpoint on your server that your front end calls:

app.post("/api/speak", async (req, res) => {
  // Authenticate your own user here, and validate what they send
  const response = await fetch("https://api.menavoice.ai/api/tts", {
    method: "POST",
    headers: {
      "x-api-key": process.env.MENAVOICE_API_KEY,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ text: String(req.body.text).slice(0, 5000), voiceId: "layla" }),
  });
  const result = await response.json();
  if (!response.ok) return res.status(response.status).json({ error: result.error });

  res.type(result.mimeType).send(Buffer.from(result.audio, "base64"));
});

Put your own authentication and rate limiting in front of an endpoint like this. Otherwise anyone who finds it can spend your credit through it.

Use one key per app and environment

Create separate keys for development, staging and production, and for each app. The API Keys page shows when each key was last used, and the Developer Dashboard breaks down usage and cost by key.

If a key leaks, revoke it on the API Keys page and deploy a new one. Revoked keys stop working immediately.

Handle errors and retry safely

Every error response has the same shape, with a readable message:

{ "error": "Too many requests" }

Retry only the errors that can succeed on a second attempt:

StatusRetry?What to do
400NoFix the request. The message says what's wrong.
401NoCheck the API key.
402NoTop up your API credit, then retry.
413NoSend a smaller file or body.
429YesWait Retry-After seconds if present, otherwise back off.
500, 502YesRetry with exponential backoff.

Failed requests aren't charged, so retrying is safe. Here's a small wrapper that retries with backoff:

import os
import time

import requests

RETRYABLE = {429, 500, 502, 503, 504}


def synthesize(payload, attempts=5):
    for attempt in range(attempts):
        response = requests.post(
            "https://api.menavoice.ai/api/tts",
            headers={"x-api-key": os.environ["MENAVOICE_API_KEY"]},
            json=payload,
            timeout=120,
        )
        if response.status_code not in RETRYABLE or attempt == attempts - 1:
            response.raise_for_status()
            return response.json()
        # Honor Retry-After when it's sent, otherwise back off exponentially
        time.sleep(float(response.headers.get("Retry-After", 2**attempt)))

Stay within the limits

  • 30 requests per minute for each endpoint, shared by all your keys.
  • Concurrent requests: 5 at a time by default, 15 once your top-ups total $100, and 50 from $1,000. Queue work on your side instead of firing everything at once.
  • 5,000 characters per request. Split longer scripts at sentence boundaries and join the audio afterwards:
import re


def split_text(text, limit=5000):
    """Split text into pieces of at most `limit` characters, at sentence ends."""
    pieces, current = [], ""
    for sentence in re.split(r"(?<=[.!?؟\n])\s+", text.strip()):
        if len(current) + len(sentence) + 1 <= limit:
            current = f"{current} {sentence}" if current else sentence
            continue
        if current:
            pieces.append(current)
        while len(sentence) > limit:  # one sentence longer than the limit
            pieces.append(sentence[:limit])
            sentence = sentence[limit:]
        current = sentence
    if current:
        pieces.append(current)
    return pieces

See Rate Limits for the details.

Keep an eye on your balance

When your API credit can't cover a request, it fails with 402 Insufficient API balance. To avoid surprises:

  • Check your balance and top-up history under API Billing.
  • Watch usage and cost by service, model and key on the Developer Dashboard.
  • Alert on 402 responses in your own monitoring, and top up before a launch or campaign.

Cache what you can

The same text with the same voice, model and dialect doesn't need to be generated twice. Store the audio (for example in object storage, keyed by a hash of the request) and serve repeat requests from there. It's faster for your users, and cached audio costs nothing.

MenaVoice 2 varies between takes. If you want a take to stay the same, generate it once and keep it.

Set generous timeouts

Generation time grows with text length, and a multi-speaker dialogue renders every line. Allow up to two minutes for long texts and dialogues, and longer for large transcriptions, rather than relying on a short default timeout.

Launch checklist

  • The API key lives only on your server, in an environment variable or secret manager.
  • Each app and environment has its own key.
  • 429, 500 and 502 are retried with backoff. Other errors aren't.
  • Long scripts are split to 5,000 characters or fewer.
  • Repeated audio is cached.
  • Someone gets alerted on 402 responses, and the balance is topped up.

Was this page helpful?