Categories and free-tier limits
| Category | Endpoints | Free tier | Scales to (Business+) |
|---|---|---|---|
| Render | POST /facade/generate | 10 / min | 200+ / min |
| Job status | GET /facade/render-jobs/{id} | 60 / min | 600+ / min |
| Signed images | GET /api/v1/generate/{template} | 30 / min | 300+ / min |
| Billing | /facade/billing/* | 10 / min | 50+ / min |
| Default | everything else | 60 / min | 600+ / min |
Need higher limits? Email support@kynva.ai with your use case. We routinely lift limits for production workloads.
Response headers
Every response includes:| Header | Meaning |
|---|---|
X-RateLimit-Limit | Cap for this category in the current window. |
X-RateLimit-Remaining | Calls left in the current window. |
X-RateLimit-Reset | Unix timestamp (seconds) when the window resets. |
Retry-After header.
Hitting the limit
Backoff that works
A robust retry loop:- On
429, readRetry-After. Wait at least that long. - On
5xx, exponential backoff: 1s, 2s, 4s, 8s, with ±20% jitter. - Cap retries at 5. After that, surface the failure.
- Always reuse the same
Idempotency-Keyacross retries — see idempotency.
Tips for staying under the limit
- Batch when you can. Use
POST /facade/render-jobswith multiple briefs instead of N synchronous renders. - Cache aggressively. GET responses include strong ETags; respect them.
- Use the async path. Render jobs don’t block on your client connection — fire-and-subscribe-to-webhook is cheaper for both sides.
- Pre-resolve brands. List brands once on app boot, not per render.