These limits apply when you call https://pdfgorilla.io/api/v1/... (or the host your account uses). Exact numbers for your plan may also appear in the dashboard.
Request size limits
These apply to every generation request (sync and async):
| What | Limit | Error code if exceeded |
|---|
| Total request body | 512 KB (524,288 bytes) | REQUEST_BODY_TOO_LARGE |
| HTML template | 200 KB | HTML_TEMPLATE_TOO_LARGE |
| Custom CSS | 100 KB | CUSTOM_CSS_TOO_LARGE |
| Data JSON | 256 KB | DATA_PAYLOAD_TOO_LARGE |
| Data nesting depth | 12 levels | DATA_DEPTH_EXCEEDED |
| Array length (any array in data) | 1 000 items | ARRAY_LENGTH_EXCEEDED |
| Liquid tokens in template | 2 000 | LIQUID_COMPLEXITY_EXCEEDED |
| Inline base64 image bytes | 5 MB (5,242,880 bytes) | INLINE_ASSET_BYTES_EXCEEDED |
| External asset URLs in template | 100 | EXTERNAL_ASSET_COUNT_EXCEEDED |
| Header / footer field length | 512 characters | HEADER_FOOTER_FIELD_TOO_LARGE |
Public API error bodies return human-readable error text. The code names above are the internal validation identifiers.
Render limits
| What | Limit | Error code |
|---|
| Render timeout | 90 seconds (default; deployment-configurable) | RENDER_TIMEOUT |
| Max PDF size | 20 MB | PDF_SIZE_EXCEEDED |
| Max PDF pages | 200 pages | PDF_PAGE_LIMIT_EXCEEDED |
Rate limits
Rate limits depend on the request identity (session cookie vs API key):
| Request type | Limit |
|---|
Sync PDF generation (POST /templates/{id}/generate) with API key | 60 requests / minute |
Sync PDF generation (POST /templates/{id}/generate) with session | 20 requests / minute |
Async job creation (POST /templates/{id}/generate-async) per identity subject | 20 jobs / minute |
For API-key async requests, there is an additional generate-rate check of 60 requests/minute on that API key.
When a rate limit is exceeded, you receive HTTP 429 with these headers:
x-ratelimit-limit: 60
x-ratelimit-remaining: 0
x-ratelimit-reset: 1744000000000
x-ratelimit-reset is a millisecond Unix timestamp. Wait until after that time before retrying.
Plan quotas
Generated pages (PDFs produced via the API) and other resources count against your plan’s quota.
| Feature | Free | Pro |
|---|
| Generated PDF pages | 100 (one-time) | 10,000 / month |
| Preview pages | 500 (one-time) | 50,000 / month |
| Copilot calls | 25 (one-time) | 500 / month |
| Templates (max) | 3 | 50 |
| API keys | 1 | 10 |
| Uploaded assets (images) | 10 | 100 |
| Template import / export | No | Yes |
| Generation logs | No | Yes |
| Max asset file size | 2 MB | 2 MB |
Pro usage quotas reset every month on the same day your subscription period started (anniversary months), not on the 1st of the calendar month. On the free plan, generated pages, previews, and copilot calls are one-time lifetime allowances (they do not reset).
When a quota is exhausted, the response includes:
{
"error": "Generated page limit reached (100/100). ...",
"hint": "Your quota does not renew on the free plan. Upgrade for higher limits.",
"used": 100,
"limit": 100,
"remaining": 0,
"resetAt": null
}
Async job limits
| What | Limit |
|---|
| Active jobs per user account | 10 |
| Active jobs per API key | 20 |
| Job retention after completion | 7 days |
| Max retry attempts per job | 3 (default; deployment-configurable) |
| Download URL lifetime | 5 minutes |
“Active” means queued or processing. Completed, failed, canceled, and expired jobs do not count toward this limit.
Tips for staying within limits
Keep templates lean. Split very large templates into multiple smaller ones if you hit the 200 KB HTML limit.
Host images in the Assets library. Base64-encoded images count toward the 5 MB inline limit. Hosted images (with stable URLs) do not.
Use idempotencyKey on async jobs. This prevents duplicate jobs if your server retries a failed request, keeping your active job count low.
Paginate large data sets. Render separate PDFs for large batches rather than one massive document. This also reduces render time and stays under the 200-page limit.