Skip to main content

POST /quickjob

Generate PDFs instantly (< 30 seconds) - Perfect for simple documents (up to 25 pages maximum).

When to Use​

✅ Use QuickJob when:

  • Document is simple and small (up to 25 pages maximum)
  • Need PDF immediately
  • Synchronous workflow
  • Converting images to PDF (up to 25 images maximum)
  • Converting a publicly accessible URL to PDF

❌ Use LongJob instead when:

  • Document is large (more than 25 pages)
  • Can use async processing
  • Want webhook notifications
Input Support

QuickJob supports HTML, Markdown, URL, and image-to-PDF conversion. Pass a public HTTPS URL and the API will fetch and convert it automatically. Images process fast (~0.5-2s per image).

Quick Example​

curl -X POST https://api.podpdf.com/quickjob \
-H "X-API-Key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"input_type": "html",
"html": "<h1>Invoice</h1><p>Amount: $100</p>"
}' \
--output invoice.pdf

# Or convert a URL directly
curl -X POST https://api.podpdf.com/quickjob \
-H "X-API-Key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"input_type": "url",
"url": "https://example.com/"
}' \
--output invoice.pdf

Authentication​

Required. Send either an API key or a dashboard (Cognito) ID token:

X-API-Key: your_api_key_here
Authorization: Bearer <cognito_id_token>

Learn about authentication →

Request​

Endpoint​

POST https://api.podpdf.com/quickjob

Request Body​

{
"input_type": "html",
"html": "<!DOCTYPE html><html><head><title>Invoice</title></head><body><h1>Invoice</h1><p>Thank you!</p></body></html>",
"options": {
"format": "A4",
"margin": {
"top": "20mm",
"right": "20mm",
"bottom": "20mm",
"left": "20mm"
},
"printBackground": true
}
}

Request Fields​

For HTML/Markdown/URL (JSON):

FieldTypeRequiredDescription
input_typestring✅"html", "markdown", "url", or "image". Must be enabled for your plan (see enabled_conversion_types in plan details).
htmlstring✅*HTML content (*required if input_type is "html")
markdownstring✅*Markdown content (*required if input_type is "markdown")
urlstring✅*Publicly accessible HTTPS URL (*required if input_type is "url"). HTTP URLs and private/internal IPs are rejected. See URL fetching below.
optionsobject❌PDF generation options
options.formatstring❌Paper format: "A4", "Letter", etc. (default: "A4")
options.marginobject❌Margins for the PDF
options.margin.topstring❌Top margin (e.g., "20mm")
options.margin.rightstring❌Right margin
options.margin.bottomstring❌Bottom margin
options.margin.leftstring❌Left margin
options.printBackgroundboolean❌Print background graphics (default: true)
options.scalenumber❌Scale of rendering (default: 1.0)
options.landscapeboolean❌Landscape orientation (default: false)
options.preferCSSPageSizeboolean❌Use page size from CSS instead of format (default: false)
options.width, options.heightstring❌Custom paper size, e.g. "100mm" and "150mm". Send "format": null with them: format defaults to "A4" and wins over width/height
options.pageRangesstring❌Pages to keep, e.g. "1-3, 5" (default: all)
options.displayHeaderFooterboolean❌Print headerTemplate and footerTemplate on every page (default: false)
options.headerTemplate, options.footerTemplatestring❌HTML for the header and footer. Elements with the classes pageNumber, totalPages, date, title and url are filled in. Give them an explicit font-size, and leave room with margin.top / margin.bottom
storeboolean❌When true, upload the PDF to S3 and return a JSON response with a signed download URL instead of binary. URL expires after 1 hour. (default: false)

For Images (Multipart form-data):

FieldTypeRequiredDescription
input_typestring✅Must be "image"
imagesfile(s)✅One or more PNG or JPEG image files (repeat field for multiple)
optionsstring❌JSON string with options
options.formatstring❌Page size (default: "A4")
options.marginobject❌Margins (default: 10mm all sides)
options.fitstring❌How to fit image: "contain" (default), "cover", "fill", "none"
options.landscapeboolean❌Landscape orientation (default: false)
storestring❌Send "true" to store the PDF and get a JSON response with a download URL, exactly as in the JSON API

Image Limits:

  • Maximum 5MB per image
  • Maximum request size of about 4.5 MB of image data in total: the API accepts request bodies up to 6 MB, and uploads are base64-encoded on the way in. Larger requests are rejected with 413 before they are processed
  • Maximum 10000×10000 pixels per image
  • Each image = 1 page in the PDF
  • Maximum 25 images per request (each image is a page, so the page limit applies)

Images that fail validation are skipped rather than failing the whole request: if at least one image is usable you still get a PDF, and the X-PDF-Pages header tells you how many were included.

URL fetching​

With input_type: "url", PodPDF fetches the URL server-side and converts whatever comes back — it does not open the page in a browser at your address, so relative assets on the remote page are not resolved. Inline or absolute-URL assets work; relative <img src="logo.png"> will not.

RuleValue
SchemeHTTPS only — HTTP is rejected
Blocked targetslocalhost, private and link-local IPs, .local / .internal / .localhost hosts
RedirectsUp to 5, re-checked for SSRF at each hop
Timeout10 seconds
Max download5 MB

The response's Content-Type decides how the content is treated:

Content-TypeTreated as
text/html, application/xhtml+xmlHTML
text/markdown, text/x-markdownMarkdown
image/png, image/jpeg, image/jpgImage

If the type is generic (for example text/plain), the file extension of the final URL is used instead: .html/.htm, .md/.markdown, .png, .jpg/.jpeg. When neither identifies a supported type, the request fails with 422 URL_CONTENT_TYPE_NOT_SUPPORTED.

Page size, headers and footers​

A 100 × 150 mm label with a page-numbered footer:

curl -X POST https://api.podpdf.com/quickjob \
-H "X-API-Key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"input_type": "html",
"html": "<h1>Shipping label</h1><p>Order 1042</p>",
"options": {
"format": null,
"width": "100mm",
"height": "150mm",
"margin": { "top": "10mm", "bottom": "15mm", "left": "8mm", "right": "8mm" },
"displayHeaderFooter": true,
"headerTemplate": "<span></span>",
"footerTemplate": "<div style=\"font-size:8px;width:100%;text-align:center\">Page <span class=\"pageNumber\"></span> of <span class=\"totalPages\"></span></div>"
}
}' \
--output label.pdf

displayHeaderFooter prints a default header (date and title) unless you pass headerTemplate; send an empty element, as above, to print only a footer.

Response​

Success — Binary (default)​

Without store, you receive the PDF file directly as binary data.

Headers:

Content-Type: application/pdf
Content-Disposition: inline; filename="document.pdf"
X-PDF-Pages: 5
X-PDF-Truncated: false
X-Job-Id: 9f0a4b78-2c0c-4d14-9b8b-123456789abc
Page Count

The X-PDF-Pages header tells you how many pages were generated.

Success — Stored (store: true)​

When you pass "store": true, the PDF is uploaded to S3 and you receive a JSON response instead of binary. Use this when you need to share or download the PDF later rather than streaming it directly.

{
"job_id": "9f0a4b78-2c0c-4d14-9b8b-123456789abc",
"pages": 5,
"truncated": false,
"download_url": "https://podpdf-prod-pdfs.s3.eu-central-1.amazonaws.com/9f0a4b78...pdf?X-Amz-Signature=...",
"download_url_expires_at": "2025-12-21T11:30:00.000Z"
}
URL Expiry

The signed download_url expires after 1 hour. After that the file is inaccessible and deleted after 30 days. Download or share it before it expires.

If the S3 upload fails, download_url and download_url_expires_at will be null.

Timeout (408 Request Timeout)​

If generation takes longer than 30 seconds:

{
"error": {
"code": "QUICKJOB_TIMEOUT",
"message": "Job processing exceeded 30-second timeout. Please use /longjob endpoint for larger documents.",
"details": {
"job_id": "9f0a4b78-2c0c-4d14-9b8b-123456789abc",
"timeout_seconds": 30,
"suggestion": "use_longjob_endpoint"
}
}
}
Timeout? Use LongJob

If you hit the timeout, your document is too large for QuickJob.
Use the LongJob endpoint instead →

Error Responses​

StatusCodeMeaningSolution
400MISSING_INPUT_TYPENo input_type in the requestSend input_type
400INVALID_INPUT_TYPEInvalid input_typeUse "html", "markdown", "url", or "image"
400MISSING_CONTENT_FIELDThe field matching input_type is absentProvide content
400EMPTY_CONTENT_FIELDThe content field is emptyProvide content
400CONFLICTING_FIELDSBoth html and markdown were sentSend only the field matching input_type
400INPUT_SIZE_EXCEEDEDContent is over 5 MBSplit the document
400MISSING_URLurl field absent or empty when input_type is "url"Include the url field
400INVALID_URLNot a valid URL, not HTTPS, or resolves to a private IPUse a public HTTPS URL
400PAGE_LIMIT_EXCEEDEDPDF exceeds max pagesReduce content or use LongJob
400INVALID_IMAGE_FORMATImage is not PNG or JPEGUse PNG or JPEG only
400INVALID_IMAGE_DATAImage is corrupted or invalidCheck image file
400IMAGE_TOO_LARGEImage exceeds 5MB or 10000×10000pxResize or compress image
400MISSING_IMAGESNo image files providedInclude at least one image
400INVALID_MULTIPARTMalformed multipart requestCheck Content-Type and form data
400INVALID_OPTIONS_JSONoptions is not valid JSONFix the JSON string
401UNAUTHORIZEDInvalid or missing credentialsCheck your API key or token
402UPGRADE_REQUIREDThe account has no paid planBuy credits or subscribe to activate the account
403ACCOUNT_NOT_FOUNDAccount doesn't existCreate an account
403CONVERSION_TYPE_NOT_ENABLEDConversion type not enabled for planCheck plan's enabled_conversion_types
403RATE_LIMIT_EXCEEDEDYour plan's per-minute limit was hitWait details.retry_after seconds (only plans that set a limit)
403INSUFFICIENT_CREDITSNot enough allowance or creditsBuy credits or upgrade your plan in the dashboard
408QUICKJOB_TIMEOUTTook too longUse /longjob instead
422URL_FETCH_FAILEDDNS failure or connection refused when fetching URLCheck the URL is reachable
422URL_FETCH_TIMEOUTRemote server did not respond within 10 secondsEnsure the URL responds quickly
422URL_FETCH_HTTP_ERRORRemote server returned a non-2xx statusCheck the URL returns 200
422URL_CONTENT_TYPE_NOT_SUPPORTEDRemote Content-Type is not HTML, Markdown, or PNG/JPEGUse a supported content type
429TOO_MANY_REQUESTSPlatform throttling from API Gateway (not your plan's limit)Back off and retry with jitter
500PDF_GENERATION_FAILEDThe renderer failed on this documentCheck the HTML/CSS renders in a browser, then retry
500INTERNAL_SERVER_ERRORServer errorTry again later

Complete Examples​

Store PDF to S3 (cURL)​

curl -X POST https://api.podpdf.com/quickjob \
-H "X-API-Key: $PODPDF_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input_type": "html",
"html": "<h1>Invoice</h1><p>Amount: $100</p>",
"store": true
}'
# Returns JSON with download_url (expires in 1 hour)

Store PDF to S3 (JavaScript)​

const response = await fetch('https://api.podpdf.com/quickjob', {
method: 'POST',
headers: {
'X-API-Key': process.env.PODPDF_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
input_type: 'html',
html: '<h1>Invoice</h1>',
store: true
})
});

const { job_id, download_url, download_url_expires_at } = await response.json();
console.log('Download:', download_url); // valid for 1 hour

Store PDF to S3 (Python)​

import requests, os

response = requests.post(
'https://api.podpdf.com/quickjob',
headers={
'X-API-Key': os.getenv('PODPDF_API_KEY'),
'Content-Type': 'application/json'
},
json={
'input_type': 'html',
'html': '<h1>Invoice</h1>',
'store': True
}
)

data = response.json()
print('Download URL:', data['download_url']) # expires in 1 hour

URL to PDF (cURL)​

curl -X POST https://api.podpdf.com/quickjob \
-H "X-API-Key: $PODPDF_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input_type": "url",
"url": "https://example.com/",
"options": { "format": "A4", "printBackground": true }
}' \
--output report.pdf

URL to PDF (JavaScript)​

import fs from 'node:fs';

const response = await fetch('https://api.podpdf.com/quickjob', {
method: 'POST',
headers: {
'X-API-Key': process.env.PODPDF_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
input_type: 'url',
url: 'https://example.com/',
options: { format: 'A4', printBackground: true }
})
});

if (response.ok) {
const buffer = await response.arrayBuffer();
fs.writeFileSync('report.pdf', Buffer.from(buffer));
}

URL to PDF (Python)​

import requests, os

response = requests.post(
'https://api.podpdf.com/quickjob',
headers={
'X-API-Key': os.getenv('PODPDF_API_KEY'),
'Content-Type': 'application/json'
},
json={
'input_type': 'url',
'url': 'https://example.com/',
'options': {'format': 'A4', 'printBackground': True}
}
)

if response.status_code == 200:
with open('report.pdf', 'wb') as f:
f.write(response.content)

Images to PDF (cURL)​

# Single image
curl -X POST https://api.podpdf.com/quickjob \
-H "X-API-Key: $PODPDF_API_KEY" \
-F "input_type=image" \
-F "images=@photo.jpg" \
-F 'options={"format":"A4","fit":"contain"}' \
--output photo.pdf

# Multiple images (photo album)
curl -X POST https://api.podpdf.com/quickjob \
-H "X-API-Key: $PODPDF_API_KEY" \
-F "input_type=image" \
-F "images=@photo1.jpg" \
-F "images=@photo2.jpg" \
-F "images=@photo3.jpg" \
-F 'options={"format":"A4","margin":{"top":"5mm","right":"5mm","bottom":"5mm","left":"5mm"}}' \
--output album.pdf

Images to PDF (JavaScript)​

const FormData = require('form-data');
const fs = require('fs');
const fetch = require('node-fetch');

async function imagesToPDF() {
const formData = new FormData();
formData.append('input_type', 'image');
formData.append('images', fs.createReadStream('photo1.jpg'));
formData.append('images', fs.createReadStream('photo2.jpg'));
formData.append('options', JSON.stringify({
format: 'A4',
fit: 'contain',
margin: { top: '10mm', right: '10mm', bottom: '10mm', left: '10mm' }
}));

const response = await fetch('https://api.podpdf.com/quickjob', {
method: 'POST',
headers: {
'X-API-Key': process.env.PODPDF_API_KEY,
},
body: formData
});

if (response.ok) {
const buffer = await response.buffer();
fs.writeFileSync('output.pdf', buffer);
console.log('PDF created successfully!');
}
}

imagesToPDF();

Images to PDF (Python)​

import requests
import os

def images_to_pdf():
api_key = os.getenv('PODPDF_API_KEY')

files = [
('images', ('photo1.jpg', open('photo1.jpg', 'rb'), 'image/jpeg')),
('images', ('photo2.jpg', open('photo2.jpg', 'rb'), 'image/jpeg')),
]

data = {
'input_type': 'image',
'options': '{"format":"A4","fit":"contain"}'
}

response = requests.post(
'https://api.podpdf.com/quickjob',
headers={'X-API-Key': api_key},
files=files,
data=data
)

if response.status_code == 200:
with open('output.pdf', 'wb') as f:
f.write(response.content)
print('PDF created successfully!')

images_to_pdf()

JavaScript (Node.js)​

const fetch = require('node-fetch');
const fs = require('fs');

async function generatePDF() {
const response = await fetch('https://api.podpdf.com/quickjob', {
method: 'POST',
headers: {
'X-API-Key': process.env.PODPDF_API_KEY, // Use environment variable
'Content-Type': 'application/json'
},
body: JSON.stringify({
input_type: 'html',
html: '<h1>Hello World</h1><p>My first PDF!</p>'
})
});

if (response.ok) {
const buffer = await response.buffer();
fs.writeFileSync('output.pdf', buffer);
console.log('PDF created successfully!');
} else {
console.error('Error:', await response.json());
}
}

generatePDF();

Python​

import requests
import os

def generate_pdf():
api_key = os.getenv('PODPDF_API_KEY') # Use environment variable

response = requests.post(
'https://api.podpdf.com/quickjob',
headers={
'X-API-Key': api_key,
'Content-Type': 'application/json'
},
json={
'input_type': 'html',
'html': '<h1>Hello World</h1><p>My first PDF!</p>'
}
)

if response.status_code == 200:
with open('output.pdf', 'wb') as f:
f.write(response.content)
print('PDF created successfully!')
else:
print('Error:', response.json())

generate_pdf()

cURL​

curl -X POST https://api.podpdf.com/quickjob \
-H "X-API-Key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"input_type": "html",
"html": "<h1>Hello World</h1><p>My first PDF!</p>"
}' \
--output output.pdf

PHP​

<?php
$apiKey = getenv('PODPDF_API_KEY');

$data = array(
'input_type' => 'html',
'html' => '<h1>Hello World</h1><p>My first PDF!</p>'
);

$ch = curl_init('https://api.podpdf.com/quickjob');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'X-API-Key: ' . $apiKey,
'Content-Type: application/json'
));
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($httpCode == 200) {
file_put_contents('output.pdf', $response);
echo "PDF created successfully!";
} else {
echo "Error: " . $response;
}
?>

Tips & Best Practices​

✅ DO:​

  • Use store: true when you need to share the PDF or download it later rather than streaming it
  • Download the stored PDF before the 1-hour expiry — after that it's gone
  • Keep HTML under 5MB for best performance
  • Include all CSS inline in your HTML
  • Test with small documents first
  • Use quickjob for simple documents (up to 25 pages or 25 images maximum)
  • Handle timeout errors gracefully
  • Store API keys in environment variables
  • URL: Use https:// URLs only — public, fast-responding pages
  • URL: Handle 422 URL fetch errors (the remote server may be down or slow)
  • Images: Use PNG or JPEG format, keep under 5MB each
  • Images: Each image becomes one page (great for photo albums)

❌ DON'T:​

  • Don't rely on a stored download_url after 1 hour — it will be expired and the file deleted after 30 days
  • Don't use external CSS/JS links (they won't load)
  • Don't generate large reports with quickjob
  • Don't forget to check the X-PDF-Pages header
  • Don't ignore timeout responses
  • Don't hardcode API keys in your code
  • URL: Don't use http:// URLs or private/internal addresses — they are rejected
  • URL: Don't point to URLs that return PDF or other unsupported content types
  • Images: Don't use unsupported formats (GIF, WebP, etc.)
  • Images: Don't exceed 10000×10000 pixel dimensions

Image Fit Options​

When converting images to PDF, you can control how images fit on the page:

  • contain (default) - Fit entire image on page, maintain aspect ratio
  • cover - Fill entire page, may crop image
  • fill - Stretch to fill (may distort)
  • none - Use natural image size

Example:

curl -X POST https://api.podpdf.com/quickjob \
-H "X-API-Key: $PODPDF_API_KEY" \
-F "input_type=image" \
-F "images=@photo.jpg" \
-F 'options={"fit":"cover"}' \
--output photo.pdf

Limits​

LimitValue
Max pages25 per PDF
Max images25 per request (each image is a page)
Max input size5 MB
Timeout30 seconds
Rate limitNone per account on the standard paid plan; API Gateway still throttles (429)
Billing$0.01 per successful PDF, deducted from your subscription allowance first, then your credits (Plans & Billing)
Larger documents

Over 25 pages, use /longjob (up to 100 pages). For many documents at once, use /bulkjob (up to 200 pages per job).

See Limits for every limit across the API.

Next Steps​