PDF Generator API: Complete Developer Guide 2025
Building applications that generate PDFs programmatically opens up powerful automation possibilities. Instead of manual document creation, APIs let you generate thousands of PDFs automatically from your data.
I've integrated PDF generation APIs into dozens of applications over the past two years. The time savings are massive—what used to require manual work now happens automatically in the background.
What is a PDF Generator API?
A PDF Generator API is a REST API that creates PDFs programmatically. You send data via HTTP requests, and the API returns generated PDFs.
Traditional vs API Approach
Traditional: API Approach:
─────────────────────────────────────────────────
1. Open software 1. Send API request
2. Create template 2. API processes data
3. Fill in data 3. Receive PDF URL
4. Save PDF 4. Use PDF in app
5. Upload to system
Time: 5-10 min/form Time: 1-3 sec/form
API Architecture Overview
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Your App │ ───> │ PDF API │ ───> │ Generated │
│ │ │ │ │ PDF │
│ Send Request │ │ Process Data │ │ Return URL │
└──────────────┘ └──────────────┘ └──────────────┘
Common API Operations
1. Create PDF from Template
Generate PDFs using pre-defined templates with your data.
2. Fill Existing PDF Forms
Populate form fields in existing PDFs programmatically.
3. Convert Documents to PDF
Transform Word, Excel, HTML, or images into PDF format.
4. Merge Multiple PDFs
Combine several PDFs into a single document.
5. Add Watermarks/Annotations
Programmatically add watermarks, stamps, or annotations.
API Request Structure
Basic Request Format
POST /api/v1/generate-pdf
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
{
"template_id": "invoice-template",
"data": {
"invoice_number": "INV-001",
"amount": 500,
"customer": "Acme Corp"
}
}
Response Format
{
"success": true,
"pdf_id": "pdf-12345",
"download_url": "https://cdn.example.com/pdfs/pdf-12345.pdf",
"expires_at": "2025-01-24T12:00:00Z",
"file_size": 245678,
"processing_time": "1.2s"
}
Code Examples
Python
import requests
def generate_pdf(template_id, data):
response = requests.post(
'https://api.autofillpdf.com/v1/generate-pdf',
headers={
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={
'template_id': template_id,
'data': data
}
)
if response.status_code == 200:
result = response.json()
return result['download_url']
else:
raise Exception(f"API Error: {response.text}")
# Usage
pdf_url = generate_pdf('invoice-template', {
'invoice_number': 'INV-001',
'amount': 500,
'customer': 'Acme Corp'
})
print(f"PDF generated: {pdf_url}")
JavaScript/Node.js
async function generatePDF(templateId, data) {
const response = await fetch('https://api.autofillpdf.com/v1/generate-pdf', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
template_id: templateId,
data: data
})
});
if (!response.ok) {
throw new Error(`API Error: ${response.statusText}`);
}
const result = await response.json();
return result.download_url;
}
// Usage
const pdfUrl = await generatePDF('invoice-template', {
invoice_number: 'INV-001',
amount: 500,
customer: 'Acme Corp'
});
console.log(`PDF generated: ${pdfUrl}`);
PHP
<?php
function generatePDF($templateId, $data) {
$ch = curl_init('https://api.autofillpdf.com/v1/generate-pdf');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer YOUR_API_KEY',
'Content-Type: application/json'
],
CURLOPT_POSTFIELDS => json_encode([
'template_id' => $templateId,
'data' => $data
])
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200) {
$result = json_decode($response, true);
return $result['download_url'];
} else {
throw new Exception("API Error: $response");
}
}
// Usage
$pdfUrl = generatePDF('invoice-template', [
'invoice_number' => 'INV-001',
'amount' => 500,
'customer' => 'Acme Corp'
]);
echo "PDF generated: $pdfUrl";
?>
API Endpoints Reference
Generate PDF from Template
POST /api/v1/generate-pdf
Request Body:
{
"template_id": "string",
"data": {
"field1": "value1",
"field2": "value2"
},
"options": {
"format": "pdf",
"quality": "high"
}
}
Fill PDF Form
POST /api/v1/fill-pdf
Request Body:
{
"pdf_id": "string",
"fields": {
"field_name": "value"
}
}
Convert to PDF
POST /api/v1/convert
Request: Multipart form data with file
Batch Processing
POST /api/v1/batch-generate
Request Body:
{
"template_id": "string",
"data_array": [
{"field1": "value1"},
{"field1": "value2"},
{"field1": "value3"}
]
}
Authentication
API Key Setup
1. Sign up for API account
2. Generate API key in dashboard
3. Store key securely (environment variable)
4. Include in request headers
Header Format
Authorization: Bearer YOUR_API_KEY
Security Best Practices
- ✅ Store API keys in environment variables
- ✅ Never commit keys to version control
- ✅ Use different keys for dev/prod
- ✅ Rotate keys regularly
- ✅ Monitor API usage
Error Handling
Common Error Codes
| Code | Meaning | Solution |
|---|---|---|
| 400 | Bad Request | Check request format |
| 401 | Unauthorized | Verify API key |
| 404 | Not Found | Check template/PDF ID |
| 429 | Rate Limited | Implement retry logic |
| 500 | Server Error | Retry with exponential backoff |
Error Response Format
{
"error": {
"code": "INVALID_TEMPLATE",
"message": "Template not found",
"details": {
"template_id": "invalid-id"
}
}
}
Retry Logic Example
import time
import requests
def generate_pdf_with_retry(template_id, data, max_retries=3):
for attempt in range(max_retries):
try:
response = requests.post(...)
if response.status_code == 200:
return response.json()
elif response.status_code == 429:
wait_time = 2 ** attempt # Exponential backoff
time.sleep(wait_time)
continue
else:
raise Exception(f"API Error: {response.text}")
except requests.exceptions.RequestException as e:
if attempt == max_retries - 1:
raise
time.sleep(2 ** attempt)
raise Exception("Max retries exceeded")
Rate Limits and Quotas
Typical Limits
| Plan | Requests/Minute | Monthly Quota |
|---|---|---|
| Free | 10 | 100 PDFs |
| Basic | 60 | 1,000 PDFs |
| Pro | 300 | 10,000 PDFs |
| Enterprise | Unlimited | Unlimited |
Handling Rate Limits
import time
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
session = requests.Session()
retry_strategy = Retry(
total=3,
backoff_factor=1,
status_forcelist=[429, 500, 502, 503, 504]
)
adapter = HTTPAdapter(max_retries=retry_strategy)
session.mount("https://", adapter)
Webhooks
Setting Up Webhooks
Receive notifications when PDFs are ready:
{
"event": "pdf.generated",
"pdf_id": "pdf-12345",
"status": "completed",
"download_url": "https://...",
"timestamp": "2025-01-17T12:00:00Z"
}
Webhook Handler Example
from flask import Flask, request
app = Flask(__name__)
@app.route('/webhook/pdf-ready', methods=['POST'])
def handle_webhook():
data = request.json
if data['event'] == 'pdf.generated':
pdf_url = data['download_url']
# Process PDF URL
process_pdf(pdf_url)
return {'status': 'ok'}, 200
Use Cases
1. Invoice Generation
def generate_invoice(order):
return generate_pdf('invoice-template', {
'invoice_number': order.invoice_number,
'date': order.date.isoformat(),
'customer_name': order.customer.name,
'items': [{'name': item.name, 'price': item.price}
for item in order.items],
'total': order.total
})
2. Report Generation
def generate_monthly_report(data):
return generate_pdf('report-template', {
'month': data['month'],
'revenue': data['revenue'],
'expenses': data['expenses'],
'charts': data['chart_urls']
})
3. Document Automation
def process_documents(customers):
pdfs = []
for customer in customers:
pdf_url = generate_pdf('welcome-letter', {
'name': customer.name,
'email': customer.email
})
pdfs.append(pdf_url)
return pdfs
Performance Optimization
Caching Templates
# Cache template data to avoid repeated API calls
template_cache = {}
def get_template(template_id):
if template_id not in template_cache:
# Fetch template metadata
template_cache[template_id] = fetch_template(template_id)
return template_cache[template_id]
Async Processing
import asyncio
import aiohttp
async def generate_pdf_async(session, template_id, data):
async with session.post(
'https://api.autofillpdf.com/v1/generate-pdf',
headers={'Authorization': 'Bearer YOUR_API_KEY'},
json={'template_id': template_id, 'data': data}
) as response:
return await response.json()
# Generate multiple PDFs concurrently
async def generate_multiple_pdfs(tasks):
async with aiohttp.ClientSession() as session:
results = await asyncio.gather(*[
generate_pdf_async(session, t['template'], t['data'])
for t in tasks
])
return results
Testing
Unit Tests
import unittest
from unittest.mock import patch, Mock
class TestPDFGeneration(unittest.TestCase):
@patch('requests.post')
def test_generate_pdf_success(self, mock_post):
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {
'download_url': 'https://example.com/pdf.pdf'
}
mock_post.return_value = mock_response
result = generate_pdf('template', {'data': 'value'})
self.assertEqual(result, 'https://example.com/pdf.pdf')
Best Practices
1. Error Handling
Always handle errors gracefully:
try:
pdf_url = generate_pdf(template_id, data)
except APIError as e:
logger.error(f"PDF generation failed: {e}")
# Fallback or retry logic
2. Timeout Configuration
Set appropriate timeouts:
response = requests.post(
url,
json=data,
timeout=(5, 30) # 5s connect, 30s read
)
3. Logging
Log API calls for debugging:
import logging
logger = logging.getLogger(__name__)
def generate_pdf(template_id, data):
logger.info(f"Generating PDF for template: {template_id}")
# ... API call
logger.info(f"PDF generated: {pdf_url}")
Conclusion
PDF Generator APIs enable powerful document automation. Whether you're generating invoices, reports, or custom documents, APIs provide the flexibility and scalability needed for modern applications.
The key to success is choosing the right API for your needs, implementing proper error handling, and optimizing for performance. Start with simple use cases and scale as your requirements grow.
Ready to integrate PDF generation into your application? Get started with AutoFillPDF's API and transform your document workflows.


