Skip to content

Rate limits keep the API fast and reliable for everyone. They apply per account and are shared by all of your API keys.

Limits

LimitValueScope
Requests per minute30Per account, counted separately for /tts and /stt/transcribe
Concurrent requests5, 15 or 50Per account, across both endpoints
Characters per request5,000Per text to speech request, all dialogue lines together
Lines per dialogue40Per text to speech request
Upload size25 MBPer speech-to-text file
JSON body size10 MBPer request

Requests per minute

Each endpoint accepts 30 requests per minute from an account, counting every key and the requests the web app makes for you. A window opens with your first request. Once 30 requests have arrived within it, further requests get 429 Too many requests until the window ends, with a Retry-After header giving the seconds left:

HTTP/1.1 429 Too Many Requests
Retry-After: 18
Content-Type: application/json

{"error":"Too many requests"}

Concurrent requests

Concurrency is how many requests you can have in progress at the same moment. It grows with the total amount of API credit you've bought:

Total top-upsConcurrent requests
Any (default)5
$100 or more15
$1,000 or more50
CustomContact sales

A request beyond your limit gets 429 straight away, without a Retry-After header:

{
  "error": "Too many concurrent API requests (max 5). Wait for current requests to finish, or top up to unlock more.",
  "limit": 5
}

Your current concurrency and total top-ups are shown on the Developer Dashboard and under API Billing.

Staying within the limits

Run requests through a queue that never exceeds your concurrency, and retry 429 responses after a pause:

import asyncio
import os

import httpx

MAX_CONCURRENT = 5  # your concurrency limit
semaphore = asyncio.Semaphore(MAX_CONCURRENT)


async def synthesize(client, text):
    async with semaphore:
        for attempt in range(5):
            response = await client.post(
                "https://api.menavoice.ai/api/tts",
                headers={"x-api-key": os.environ["MENAVOICE_API_KEY"]},
                json={"text": text, "voiceId": "layla"},
            )
            if response.status_code != 429:
                response.raise_for_status()
                return response.json()
            await asyncio.sleep(float(response.headers.get("Retry-After", 2**attempt)))
        response.raise_for_status()


async def main(texts):
    async with httpx.AsyncClient(timeout=120) as client:
        return await asyncio.gather(*(synthesize(client, t) for t in texts))
  • The per-minute limit applies even when you have concurrency to spare: quick requests can reach 30 a minute before they reach your concurrency limit.
  • Combine short texts into one request where it makes sense. One request of 3,000 characters counts once against the per-minute limit; thirty requests of 100 characters count thirty times.
  • Cache audio you generate more than once.

Need higher limits? Contact sales for custom concurrency and volume pricing.

Web app limits

Text to speech in the web app follows your plan's limits instead: generations per day, characters per generation and per day, and generations at once. See Pricing & Rate Limits.

Was this page helpful?