Error Handling
Learn how to handle errors from the Pdflet API.
All errors return a consistent JSON format:
{
"error": "error_code",
"message": "Human-readable description",
"details": {}
}
HTTP Status Codes
| Code | Name | Description |
|---|
400 | Bad Request | Invalid request parameters |
401 | Unauthorized | Missing or invalid authentication |
402 | Payment Required | No credits remaining |
404 | Not Found | Resource doesn’t exist |
429 | Too Many Requests | Rate limit exceeded |
500 | Internal Server Error | Something went wrong on our end |
Common Errors
Authentication Errors (401)
Missing API Key
{
"error": "authentication_required",
"message": "Authentication credentials were not provided."
}
Invalid API Key
{
"error": "invalid_api_key",
"message": "Invalid API key provided."
}
Solution: Verify your API key is correct and included in the X-API-Key header.
Validation Errors (400)
Missing HTML
{
"error": "validation_error",
"message": "Either 'html' or 'url' is required.",
"details": {
"html": ["This field is required."]
}
}
Invalid Page Size
{
"error": "validation_error",
"message": "Invalid page size.",
"details": {
"page_size": ["Must be one of: A4, Letter, Legal, A3, A5"]
}
}
Solution: Check your request body matches the API specification.
Credit Errors (402)
No Credits
{
"error": "insufficient_credits",
"message": "You have no credits remaining. Please upgrade your plan."
}
Solution: Upgrade your plan or wait for credits to reset.
Rate Limit Errors (429)
Rate Limited
{
"error": "rate_limit_exceeded",
"message": "Rate limit exceeded. Please slow down.",
"details": {
"retry_after": 45
}
}
Solution: Wait for retry_after seconds before retrying. Implement exponential backoff.
Not Found Errors (404)
Conversion Not Found
{
"error": "not_found",
"message": "Conversion not found."
}
Solution: Verify the conversion ID is correct and belongs to your account.
Handling Errors in Code
Python
import requests
from requests.exceptions import HTTPError
def create_pdf_safe(html):
try:
response = requests.post(
"https://api.pdflet.dev/api/v1/pdf/",
headers={"X-API-Key": API_KEY},
json={"html": html}
)
response.raise_for_status()
return response.json()
except HTTPError as e:
error_data = e.response.json()
if e.response.status_code == 401:
raise AuthenticationError(error_data["message"])
elif e.response.status_code == 402:
raise InsufficientCreditsError(error_data["message"])
elif e.response.status_code == 429:
retry_after = error_data.get("details", {}).get("retry_after", 60)
time.sleep(retry_after)
return create_pdf_safe(html) # Retry
else:
raise ApiError(error_data["message"])
JavaScript
async function createPdfSafe(html) {
const response = await fetch('https://api.pdflet.dev/api/v1/pdf/', {
method: 'POST',
headers: {
'X-API-Key': API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({ html })
});
if (!response.ok) {
const error = await response.json();
switch (response.status) {
case 401:
throw new Error(`Authentication failed: ${error.message}`);
case 402:
throw new Error('No credits remaining');
case 429:
const retryAfter = error.details?.retry_after || 60;
await new Promise(r => setTimeout(r, retryAfter * 1000));
return createPdfSafe(html); // Retry
default:
throw new Error(error.message);
}
}
return response.json();
}
Retry Strategy
For transient errors (429, 500, 503), implement exponential backoff:
import time
import random
def retry_with_backoff(fn, max_retries=3):
for attempt in range(max_retries):
try:
return fn()
except (RateLimitError, ServerError) as e:
if attempt == max_retries - 1:
raise
# Exponential backoff with jitter
delay = (2 ** attempt) + random.uniform(0, 1)
time.sleep(delay)
Always implement retry logic for rate limits (429) and server errors (5xx). These are often transient and succeed on retry.