PDF Hosting
Store and serve your generated PDFs with direct URLs
Host your generated PDFs on SyntaxDoc servers and get shareable URLs. Access them anytime without re-generating.
Plan Limits
| Plan | Hosted PDFs | Retention Period |
|---|---|---|
| Hobby | 10 | 1 day |
| Pro | 500 | 7 days |
| Enterprise | 10,000 | 30 days |
The hosted PDF limit is for concurrent PDFs. Expired PDFs are automatically deleted and free up space.
How It Works
When you generate a PDF with hosting enabled:
- Your PDF is generated from HTML as usual
- The PDF is stored on our secure servers
- You receive a unique PDF ID and direct URL
- The PDF remains accessible until it expires
- Each download is tracked for analytics
Enable Hosting
Add host: true to your generate request options:
const formData = new FormData();
formData.append('files', new Blob([htmlContent], { type: 'text/html' }), 'index.html');
formData.append('options', JSON.stringify({
fileName: 'invoice-1234',
format: 'A4',
host: true // Enable hosting
}));
const response = await fetch('https://api.syntaxdoc.com/pdf/generate', {
method: 'POST',
headers: { 'X-API-Key': 'sk_live_your_api_key' },
body: formData
});
const result = await response.json();
console.log(result.url); // "https://api.syntaxdoc.com/api/hosted-pdfs/abc123-uuid"
console.log(result.pdfId); // "abc123-uuid"
console.log(result.expiresAt); // "2024-12-12T14:32:00.000Z"import requests
import json
files = {
'files': ('index.html', html_content, 'text/html')
}
data = {
'options': json.dumps({
'fileName': 'invoice-1234',
'format': 'A4',
'host': True # Enable hosting
})
}
response = requests.post(
'https://api.syntaxdoc.com/pdf/generate',
headers={'X-API-Key': 'sk_live_your_api_key'},
files=files,
data=data
)
result = response.json()
print(result['url']) # "https://api.syntaxdoc.com/api/hosted-pdfs/abc123-uuid"
print(result['pdfId']) # "abc123-uuid"
print(result['expiresAt']) # "2024-12-12T14:32:00.000Z"curl -X POST https://api.syntaxdoc.com/pdf/generate \
-H "X-API-Key: sk_live_your_api_key" \
-F "files=@invoice.html" \
-F 'options={"fileName": "invoice-1234", "format": "A4", "host": true}'Response with Hosting
When hosting is enabled, you receive JSON instead of PDF binary:
{
"url": "https://api.syntaxdoc.com/api/hosted-pdfs/abc123-uuid",
"pdfId": "abc123-uuid",
"expiresAt": "2024-12-12T14:32:00.000Z"
}| Field | Type | Description |
|---|---|---|
url | string | Direct URL to access the PDF |
pdfId | string | Unique identifier for the PDF |
expiresAt | string | ISO 8601 expiration timestamp |
Access Hosted PDFs
View in Browser
Simply open the URL - no authentication required for public PDFs:
// Open in new tab
window.open('https://api.syntaxdoc.com/api/hosted-pdfs/abc123-uuid');
// Or embed in an iframe
<iframe src="https://api.syntaxdoc.com/api/hosted-pdfs/abc123-uuid" />Download Programmatically
const response = await fetch('https://api.syntaxdoc.com/api/hosted-pdfs/abc123-uuid');
const blob = await response.blob();
// Create download link
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'invoice.pdf';
a.click();Get PDF Metadata
Retrieve information about a hosted PDF without downloading it:
Endpoint: GET /api/hosted-pdfs/:pdfId/metadata
const response = await fetch('https://api.syntaxdoc.com/api/hosted-pdfs/abc123-uuid/metadata');
const metadata = await response.json();Response:
{
"success": true,
"data": {
"id": "mongodb-object-id",
"pdfId": "abc123-uuid",
"originalName": "invoice-1234.pdf",
"fileSize": 125000,
"url": "https://api.syntaxdoc.com/api/hosted-pdfs/abc123-uuid",
"expiresAt": "2024-12-12T14:32:00.000Z",
"isPublic": true,
"downloads": 15,
"createdAt": "2024-12-05T14:32:00.000Z"
}
}List Your Hosted PDFs
Get all PDFs you've hosted (requires login session):
Endpoint: GET /api/hosted-pdfs/list
const response = await fetch('https://api.syntaxdoc.com/api/hosted-pdfs/list?page=1&limit=20', {
credentials: 'include' // Include session cookie
});
const { data, pagination } = await response.json();
console.log(data.pdfs); // Array of hosted PDFs
console.log(data.total); // Total countResponse:
{
"success": true,
"data": {
"pdfs": [
{
"id": "mongodb-id",
"pdfId": "abc123-uuid",
"originalName": "invoice-1234.pdf",
"fileSize": 125000,
"url": "https://api.syntaxdoc.com/api/hosted-pdfs/abc123-uuid",
"expiresAt": "2024-12-12T14:32:00.000Z",
"isPublic": true,
"downloads": 15,
"createdAt": "2024-12-05T14:32:00.000Z"
}
],
"total": 45
},
"pagination": {
"page": 1,
"limit": 20,
"total": 45,
"totalPages": 3
}
}Get Hosting Stats
View your hosted PDF usage statistics:
Endpoint: GET /api/hosted-pdfs/stats
const response = await fetch('https://api.syntaxdoc.com/api/hosted-pdfs/stats', {
credentials: 'include'
});
const { data } = await response.json();Response:
{
"success": true,
"data": {
"totalHosted": 25,
"totalDownloads": 150,
"totalSize": 52428800
}
}Delete a Hosted PDF
Remove a PDF before it expires to free up space:
Endpoint: DELETE /api/hosted-pdfs/:pdfId
const response = await fetch('https://api.syntaxdoc.com/api/hosted-pdfs/abc123-uuid', {
method: 'DELETE',
credentials: 'include'
});Response:
{
"success": true,
"message": "PDF deleted successfully"
}Deleting a PDF immediately frees up one slot in your hosted PDF limit.
Batch Hosting (ZIP Files)
When using batch generation, you can host the entire ZIP file for later download:
const response = await fetch('https://api.syntaxdoc.com/pdf/generate-batch', {
method: 'POST',
headers: {
'X-API-Key': 'sk_live_your_api_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
documents: [
{ fileName: 'certificate-1', htmlContent: '<html>...</html>' },
{ fileName: 'certificate-2', htmlContent: '<html>...</html>' },
// ... up to 100+ documents
],
batchName: 'certificates-batch',
host: true // Store ZIP file on our servers
})
});
const result = await response.json();Response:
{
"success": true,
"message": "Batch generation completed",
"documentsGenerated": 50,
"downloadUrl": "https://api.syntaxdoc.com/api/hosted-pdfs/zip-abc123-uuid",
"zipId": "zip-abc123-uuid",
"expiresAt": "2024-12-12T14:32:00.000Z"
}With Real-Time Streaming
Combine host: true with stream: true for progress tracking:
// Start batch with hosting
const startResponse = await fetch('https://api.syntaxdoc.com/pdf/generate-batch', {
method: 'POST',
headers: {
'X-API-Key': 'sk_live_your_api_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
documents: [...],
stream: true,
host: true
})
});
const { batchId } = await startResponse.json();
// Stream progress
const eventSource = new EventSource(
`https://api.syntaxdoc.com/pdf/progress/${batchId}/stream`
);
eventSource.addEventListener('complete', (event) => {
const data = JSON.parse(event.data);
const result = JSON.parse(data.message);
console.log('ZIP hosted at:', result.downloadUrl);
console.log('ZIP ID:', result.zipId);
console.log('Expires:', result.expiresAt);
eventSource.close();
});Storage Count: Hosted ZIP files count as 1 hosted PDF against your limit, regardless of how many PDFs are inside the ZIP.
Caching with Appointment IDs
Use appointmentId to cache PDFs and avoid regenerating the same document:
formData.append('options', JSON.stringify({
fileName: 'certificate-john-doe',
host: true,
appointmentId: 'cert-john-doe-2024' // Custom ID for caching
}));
const response = await fetch('https://api.syntaxdoc.com/pdf/generate', {
method: 'POST',
headers: { 'X-API-Key': 'sk_live_your_api_key' },
body: formData
});If a PDF with this appointmentId already exists and hasn't expired, the existing URL is returned without generating a new PDF (saving your conversion quota).
To force regeneration:
formData.append('options', JSON.stringify({
fileName: 'certificate-john-doe',
host: true,
appointmentId: 'cert-john-doe-2024',
regenerate: true // Force new generation
}));Handling Storage Limits
When you reach your hosted PDF limit, the API returns:
{
"statusCode": 429,
"code": "HOSTED_PDF_LIMIT_REACHED",
"message": "Hosted PDF limit reached. Please upgrade your plan or delete existing PDFs."
}Solutions:
- Delete expired or unused PDFs via the API or dashboard
- Upgrade your plan for higher limits
- Wait for PDFs to expire automatically
Use Cases
Invoice Links for Customers
Generate invoices and share direct links:
const { url } = await generatePdf({
html: invoiceTemplate,
options: { host: true, fileName: `invoice-${orderId}` }
});
// Send to customer
await sendEmail(customer.email, {
subject: `Invoice #${orderId}`,
body: `Download your invoice: ${url}`
});Certificate Distribution
Host certificates for event attendees:
const certificates = await Promise.all(
attendees.map(async (attendee) => {
const { url, pdfId } = await generatePdf({
html: certificateTemplate(attendee),
options: {
host: true,
fileName: `certificate-${attendee.name}`,
appointmentId: `cert-${attendee.id}` // Cache for repeat access
}
});
return { attendee, url, pdfId };
})
);
// Email each attendee their certificate URLEmbedded PDF Viewer
Embed hosted PDFs in your application:
<!-- Direct embed -->
<iframe
src="https://api.syntaxdoc.com/api/hosted-pdfs/abc123-uuid"
width="100%"
height="600px"
></iframe>
<!-- With PDF.js viewer -->
<iframe
src="https://mozilla.github.io/pdf.js/web/viewer.html?file=https://api.syntaxdoc.com/api/hosted-pdfs/abc123-uuid"
width="100%"
height="600px"
></iframe>