https://api.echonova.aiDevelopers
Rate limits
How many requests one API key can make per minute, the headers that report the count, what a 429 looks like, and how to back off.
The API limits how many requests one key can make to one endpoint per 60
seconds.
This page gives the numbers, the headers that report where you stand, and the
exact 429 response so you can handle it in code.
Limit
| Fact | Value |
|---|---|
| Requests allowed | 100 |
| Window | 60 seconds. Each request counts against the limit for 60 seconds after it is made. |
| Scope | One API key on one endpoint. Two keys have separate counts, and one key's calls to /v1/text-to-speech do not count against its calls to /v1/speech-to-text/jobs. |
| Block | Once a key exceeds 100 requests on an endpoint, that endpoint rejects the key for 60 seconds. Rejected requests are not counted. When the block ends the count starts again from zero. |
| Applies to | All fifteen /v1 endpoints. |
POST /v1/sound-cleaning is also bounded by its upload, not only by the
request count: audio of 10 minutes or less, 150 MB or less, in MP3, WAV, FLAC
or OGG/Opus. See Sound Cleaning quickstart.
The count is per key, not per workspace. If several systems share a workspace, give each its own key so a busy one does not block the others.
Response headers
An accepted request returns three headers that tell you where the key stands
on that endpoint. A rejected request returns Retry-After instead.
| Header | When | Meaning |
|---|---|---|
X-RateLimit-Limit |
Accepted request | The limit, 100. |
X-RateLimit-Remaining |
Accepted request | Requests left in the window, 0 at the lowest. |
X-RateLimit-Reset |
Accepted request | Seconds until the window resets. |
Retry-After |
Rejected request | Seconds until the block ends. |
The 429 response
The rejected request gets HTTP 429 with this body:
{
"data": null,
"statusCode": 429,
"success": false,
"errorMessage": "ThrottlerException: Too Many Requests"
}A different 429 exists. When a call would take the key past
its credit limit, the body says Monthly spending limit exhausted and no
Retry-After header is sent. Waiting does not clear it; see
Credits. Check errorMessage before you retry.
What to do
- Read
Retry-After, wait that many seconds, then retry. Do not retry sooner; requests made during the block are rejected and the block does not shorten. - If you retry on other errors as well, use exponential backoff with jitter so a burst of failures does not turn into a burst of requests.
- Watch
X-RateLimit-Remainingand slow down before it reaches0. - Use one key per system. The limit is per key, so separate keys give separate windows.
Stay under the limit while waiting for jobs
Polling is the usual way to hit the limit. Every poll is a request against
the job endpoint, whatever the jobId, so let the result come to you where
you can.
Recommended
- A webhook on
job.completedandjob.failed, which costs no requests, with one poll after 15 minutes of silence as a fallback.
Less effective
- A loop that polls
/v1/text-to-speech/jobs/{jobId}every 500 milliseconds for every job in flight.
If you must poll, use a fixed interval of at least 3 seconds for Text to Speech and 5 seconds for Speech to Text. See Retry requests safely for the loop.
A second limit of the same size, 100 requests per 60 seconds per endpoint,
is counted per client IP address. It counts only requests that the API key
check rejects: a missing or invalid key (401), a key with no access to
the service (403), or a workspace plan that is inactive or not found
(403). A request with a valid key is never blocked by it. Valid keys are
limited per key only. A blocked IP gets the 429 body above with
Retry-After, even when it sends a bad key.
FAQ
Is the limit per workspace or per key?
Per key, and per endpoint. Two keys in one workspace have separate counts,
and one key's calls to /v1/text-to-speech do not count against its calls
to /v1/speech-to-text/jobs.
Do rejected requests extend the block?
No. Rejected requests are not counted, and the block ends when
Retry-After says it does. They do not shorten it either.
Do polls count?
Yes. Every GET on a job endpoint is a request against that endpoint's
limit.
How do I tell this 429 from the spending-limit 429?
By errorMessage. This one says ThrottlerException: Too Many Requests and
carries Retry-After; the spending one says Monthly spending limit exhausted and carries no header.