SyntaxdocSyntaxdoc

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

PlanHosted PDFsRetention Period
Hobby101 day
Pro5007 days
Enterprise10,00030 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:

  1. Your PDF is generated from HTML as usual
  2. The PDF is stored on our secure servers
  3. You receive a unique PDF ID and direct URL
  4. The PDF remains accessible until it expires
  5. 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"
}
FieldTypeDescription
urlstringDirect URL to access the PDF
pdfIdstringUnique identifier for the PDF
expiresAtstringISO 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 count

Response:

{
  "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:

  1. Delete expired or unused PDFs via the API or dashboard
  2. Upgrade your plan for higher limits
  3. Wait for PDFs to expire automatically

Use Cases

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 URL

Embedded 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>

On this page