POST
/v1/pdf/generateGenerate a PDF from HTML, URL, or Markdown
Quick Example
curl -X POST https://api.speedstein.com/v1/pdf/generate \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"html": "<html><body><h1>Hello World</h1></body></html>",
"format": "A4",
"margin": "1cm"
}' \
--output document.pdfRequest
Headers
| Header | Value | Required |
|---|---|---|
Authorization | Bearer YOUR_API_KEY | Required |
Content-Type | application/json | Required |
Body Parameters
html
string
Required*
The HTML content to convert to PDF. Must be valid HTML5. Use this OR url (not both).
"html": "<html><body><h1>Title</h1><p>Content</p></body></html>"url
string
Required*
URL to convert to PDF. Must be publicly accessible. Use this OR html (not both).
"url": "https://example.com/page-to-convert"format
string
Optional
Page format. Default: A4
A4
A3
A5
Letter
Legal
Tabloid
"format": "A4"margin
string | object
Optional
Page margins. Can be a single value (all sides) or an object with top, right, bottom, left.
"margin": "1cm" // All sides"margin": {
"top": "2cm",
"right": "1.5cm",
"bottom": "2cm",
"left": "1.5cm"
}orientation
string
Optional
Page orientation. Default: portrait
portrait
landscape
"orientation": "landscape"print_background
boolean
Optional
Print background graphics. Default: true
"print_background": truescale
number
Optional
Scale of the webpage rendering. Range: 0.1 to 2. Default: 1
"scale": 1.2wait_for
string
Optional
Wait condition before generating PDF:
load
domcontentloaded
networkidle0
networkidle2
"wait_for": "networkidle0"header_html
string
Optional
HTML template for page header. Supports variables: {{pageNumber}}, {{totalPages}}, {{date}}
"header_html": "<div style='font-size:10px;text-align:center'>Page {{pageNumber}}</div>"footer_html
string
Optional
HTML template for page footer. Supports same variables as header.
"footer_html": "<div style='font-size:9px;text-align:right'>{{pageNumber}} of {{totalPages}}</div>"Response
200
Success
PDF generated successfully
{
"id": "pdf_1a2b3c4d5e6f",
"url": "https://storage.speedstein.com/pdfs/1a2b3c4d5e6f.pdf",
"size": 45234,
"pages": 3,
"format": "A4",
"generation_time_ms": 1847,
"created_at": "2025-10-28T12:34:56Z",
"expires_at": "2025-11-04T12:34:56Z"
}Response Fields
id- Unique identifier for the PDFurl- Download URL (valid until expiration)size- File size in bytespages- Number of pages in the PDFformat- Page format usedgeneration_time_ms- Time taken to generate PDF in millisecondscreated_at- ISO 8601 timestamp of creationexpires_at- ISO 8601 timestamp when URL expires (7-365 days based on tier)
Error Responses
400
Bad Request
{
"error": {
"code": "invalid_request",
"message": "Either 'html' or 'url' parameter is required"
}
}401
Unauthorized
{
"error": {
"code": "unauthorized",
"message": "Invalid or missing API key"
}
}429
Rate Limit Exceeded
{
"error": {
"code": "rate_limit_exceeded",
"message": "Too many requests. Please retry after 60 seconds.",
"retry_after": 60
}
}402
Quota Exceeded
{
"error": {
"code": "quota_exceeded",
"message": "Monthly quota exceeded. Upgrade your plan or wait for reset.",
"quota_reset_at": "2025-11-01T00:00:00Z"
}
}Complete Examples
Performance Tip
For best performance (<2s generation time), keep your HTML under 1MB and avoid loading external resources that may cause network delays.
Node.js with async/await
const fetch = require('node-fetch');
const fs = require('fs').promises;
async function generatePDF() {
try {
const response = await fetch('https://api.speedstein.com/v1/pdf/generate', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.SPEEDSTEIN_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
html: '<html><body><h1>Invoice #12345</h1></body></html>',
format: 'A4',
margin: '1cm',
print_background: true,
footer_html: '<div style="font-size:9px;text-align:center">{{pageNumber}}</div>'
})
});
if (!response.ok) {
const error = await response.json();
throw new Error(`API Error: ${error.error.message}`);
}
const metadata = await response.json();
console.log('PDF generated:', metadata);
// Download the PDF
const pdfResponse = await fetch(metadata.url);
const buffer = await pdfResponse.buffer();
await fs.writeFile('invoice.pdf', buffer);
console.log(`Saved as invoice.pdf (${metadata.size} bytes, ${metadata.pages} pages)`);
} catch (error) {
console.error('Error generating PDF:', error.message);
}
}
generatePDF();Python with requests
import os
import requests
def generate_pdf():
response = requests.post(
'https://api.speedstein.com/v1/pdf/generate',
headers={
'Authorization': f'Bearer {os.environ["SPEEDSTEIN_API_KEY"]}',
'Content-Type': 'application/json'
},
json={
'html': '<html><body><h1>Report</h1></body></html>',
'format': 'A4',
'margin': '2cm',
'orientation': 'portrait',
'print_background': True
}
)
if response.status_code != 200:
print(f"Error: {response.json()['error']['message']}")
return
metadata = response.json()
print(f"PDF generated: {metadata['id']}")
# Download the PDF
pdf_response = requests.get(metadata['url'])
with open('report.pdf', 'wb') as f:
f.write(pdf_response.content)
print(f"Saved as report.pdf ({metadata['size']} bytes)")
if __name__ == '__main__':
generate_pdf()