Rate limits and billing
Per-key request limits and how API usage is charged.
Rate limits
Limits are per key, counted separately for reads and writes, so a burst of uploads can't starve your polling loop.
| Bucket | Limit |
|---|---|
Reads (GET) | 300 requests/minute |
Writes (POST, PUT, PATCH) | 120 requests/minute |
Every response carries the remaining allowance:
X-Rate-Limit-Remaining: 287Exceeding a bucket returns 429 with a Retry-After header (in seconds):
async function withRetry(request, attempts = 5) {
for (let attempt = 0; attempt < attempts; attempt++) {
const res = await request();
if (res.status !== 429) return res;
const wait = Number(res.headers.get('Retry-After') ?? 2 ** attempt);
await new Promise((r) => setTimeout(r, wait * 1000));
}
throw new Error('rate limited');
}If you need a higher ceiling, get in touch — these are starting values, not hard architectural limits.
Billing
API usage draws on the same plan as the app. There's no separate API price and no per-request charge: you're billed for audio processed, by duration, against the organization's allowance plus any top-up hours.
Usage is recorded after transcription succeeds, so a failed upload doesn't consume allowance, and a
duplicate upload rejected with 409 isn't charged.
When the allowance runs out
Uploads are rejected with 402 Payment Required before the file is stored:
{ "message": "Audio allowance exhausted", "status": 402 }You'll also see 402 with "Trial period ended" or "No active plan". Reads keep working — only new
uploads are blocked. Top up or change plan in the app's billing page, and uploads resume immediately.
Usage is billed to the organization that owns the project, regardless of which key made the call, so keys never split or complicate an invoice.