Rate limits
Per-minute throttles + monthly quotas, plus the headers we send so you can self-throttle.
The API enforces two limits in parallel: a per-minute rate limit (throttle) and a monthly conversion quota.
Per-plan limits #
| Plan | Conversions / month | Max file size | Requests / minute | Overage rate |
|---|---|---|---|---|
| Free | 1,000 | 25 MB | 10 | — (hard stop) |
| Hobby | 5,000 | 100 MB | 30 | $0.005 / conversion |
| Startup | 25,000 | 500 MB | 60 | $0.003 / conversion |
| Scale | 100,000 | 1 GB | 120 | $0.002 / conversion |
| Growth | 500,000 | 5 GB | 300 | $0.001 / conversion |
| Enterprise | Custom | Custom | Custom | Custom |
GET /v1/usage returns the live values for your account.
Headers #
Every response includes:
| Header | Description |
|---|---|
X-RateLimit-Limit | Requests permitted per minute on your plan. |
X-RateLimit-Remaining | Requests left in the current 60-second window. |
X-RateLimit-Reset | Unix timestamp (seconds) when the window resets. |
Retry-After | (429 only) Seconds to wait before retrying. |
Use these to self-throttle without ever hitting 429:
result = ctf.convert(file=f, source="png", target="jpg")
if result.rate_limit.remaining and result.rate_limit.remaining < 3:
time.sleep(60)What happens when you exceed a limit? #
Per-minute throttle #
HTTP/1.1 429 Too Many Requests
Retry-After: 28
X-RateLimit-Remaining: 0
{
"error": {
"code": "rate_limited",
"message": "Too many requests in the last 60 seconds.",
"details": { "retry_after": 28 }
}
}The SDKs surface this as RateLimitError, with the Retry-After value exposed as e.retry_after (Python) / e.retryAfter (TypeScript).
Monthly quota #
HTTP/1.1 429 Too Many Requests
{
"error": {
"code": "quota_exceeded",
"message": "Monthly conversion quota exceeded.",
"details": { "limit": 1000, "used": 1000 }
}
}- Free plan: hard-stops. Wait for the 1st of next calendar month UTC, or upgrade.
- Paid plans: by default, paid plans continue serving at the per-conversion overage rate. Disable overage from the dashboard if you'd rather hard-stop.
Best practices #
Read the headers — don't backoff blindly
Watching X-RateLimit-Remaining lets you smooth your traffic without wasting 429s. The SDK exposes them on every successful response.
Use jobs for bursty workloads
The 429 throttle is enforced on submitting requests, not on conversion completion. If you need to burst-submit 1000 conversions in 30 seconds, queue them as async jobs and let our worker pool drain at its own pace.
Respect Retry-After
Retry-After is the number of seconds until your window has fresh capacity. The SDKs don't auto-retry — that's an explicit choice so you control your retry policy. Sleep then retry.
Monitor /v1/usage
Surface monthly usage in your own dashboards. The free tier silently hard-stops at 1000/month — building this visibility upfront prevents "why are conversions failing on the 28th?" tickets.