Documentation

OffloadPDF

Convert HTML to PDF documents via a simple, powerful API. Built for developers who need reliable, scalable PDF generation without the hassle of managing browser infrastructure.

Table of Contents

Quick Start

Get your first PDF in under 5 minutes:

1. Sign up and subscribe

Visit the dashboard and choose a plan (7-day free trial included).

2. Create an API token

Navigate to the API Tokens page in your dashboard and create a new token. Save it securely – you won’t be able to see it again.

3. Make your first API call

curl -X POST https://your-app.com/api/v1/pdf/create \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<h1>Hello World</h1><p>My first PDF!</p>"
  }'

4. Success!

You’ll receive a JSON response with your base64-encoded PDF:

{
  "pdf_content": "JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PC9UeXBlL..."
}

Decode the base64 string to get your PDF file.

Authentication

Creating API Tokens

API tokens are created in your dashboard:

  1. Log into your account
  2. Navigate to API Tokens
  3. Click “Create New Token”
  4. Give your token a descriptive name
  5. Copy the token immediately – it’s only shown once

Using API Tokens

Include your API token in the Authorization header of every request:

Authorization: Bearer YOUR_API_TOKEN

Security Best Practices

  • Never commit tokens to version control – Use environment variables instead
  • Rotate tokens periodically – Delete unused tokens
  • Use HTTPS – Always make requests over secure connections
  • Store securely – Treat tokens like passwords

Subscription Requirement

All API requests require an active subscription. New accounts receive a 7-day free trial to test the service. Requests will fail with a 402 Payment Required error if your subscription is inactive or expired.

Note: API quotas are account-level. Multiple tokens share the same monthly request limit.

API Reference

Endpoint

POST https://your-app.com/api/v1/pdf

Request Parameters

ParameterTypeRequiredDescription
htmlstringYesThe HTML content to convert to PDF

Request Headers

HeaderRequiredValueDescription
AuthorizationYesBearer {token}Your API token
Content-TypeYesapplication/jsonRequest format
AcceptNoapplication/pdf or application/jsonResponse format (default: application/json)

Request Example

{
  "html": "<h1>Document Title</h1><p>Your content here</p>"
}

Response Formats

JSON Response (default)

Returns a JSON object with the PDF content encoded as base64:

{
  "pdf_content": "JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PC9UeXBlL0NhdGFsb2cvUGFnZXMgMi..."
}

Decode the pdf_content field to get the binary PDF data.

Binary PDF Response

Set the Accept header to application/pdf to receive the PDF file directly:

Accept: application/pdf

The response will be a binary PDF file with Content-Type: application/pdf.

HTTP Status Codes

CodeStatusDescription
200SuccessPDF generated successfully
401UnauthorizedInvalid or missing API token
402Payment RequiredNo active subscription
422Validation ErrorInvalid request (missing or invalid html)
429Too Many RequestsRate limit exceeded (monthly quota reached)
500Server ErrorPDF generation failed

Code Examples

cURL

Basic Request (JSON Response)

curl -X POST https://your-app.com/api/v1/pdf \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<h1>Hello World</h1><p>This is a PDF</p>"
  }'

Download Binary PDF

curl -X POST https://your-app.com/api/v1/pdf \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Accept: application/pdf" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<h1>Invoice</h1><p>Total: $100</p>"
  }' \
  --output invoice.pdf

Complex HTML with Styling

curl -X POST https://your-app.com/api/v1/pdf \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<!DOCTYPE html><html><head><style>body{font-family:Arial;margin:40px;}h1{color:#333;}</style></head><body><h1>Styled Document</h1><p>This PDF includes custom CSS styling.</p></body></html>"
  }'

JavaScript / Node.js

Using Fetch API (Browser or Node.js 18+)

const response = await fetch('https://your-app.com/api/v1/pdf', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    html: '<h1>Hello World</h1><p>Generated from JavaScript</p>'
  })
});

const data = await response.json();
const pdfContent = data.pdf_content; // Base64-encoded PDF

// Decode base64 to binary
const pdfBinary = atob(pdfContent);

Download Binary PDF (Browser)

const response = await fetch('https://your-app.com/api/v1/pdf', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_TOKEN',
    'Accept': 'application/pdf',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    html: '<h1>Invoice #12345</h1><p>Amount due: $500</p>'
  })
});

// Create download link
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'invoice.pdf';
a.click();
window.URL.revokeObjectURL(url);

Node.js with Axios

const axios = require('axios');
const fs = require('fs');

async function generatePDF() {
  try {
    const response = await axios.post(
      'https://your-app.com/api/v1/pdf',
      {
        html: '<h1>Report</h1><p>Generated from Node.js</p>'
      },
      {
        headers: {
          'Authorization': 'Bearer YOUR_API_TOKEN',
          'Content-Type': 'application/json'
        }
      }
    );

    // Decode base64 and save to file
    const pdfBuffer = Buffer.from(response.data.pdf_content, 'base64');
    fs.writeFileSync('output.pdf', pdfBuffer);
    console.log('PDF saved successfully!');
  } catch (error) {
    console.error('Error:', error.response?.data || error.message);
  }
}

generatePDF();

Node.js with Axios (Binary Download)

const axios = require('axios');
const fs = require('fs');

async function downloadPDF() {
  const response = await axios.post(
    'https://your-app.com/api/v1/pdf',
    {
      html: '<h1>Document</h1><p>Content here</p>'
    },
    {
      headers: {
        'Authorization': 'Bearer YOUR_API_TOKEN',
        'Accept': 'application/pdf',
        'Content-Type': 'application/json'
      },
      responseType: 'arraybuffer'
    }
  );

  fs.writeFileSync('document.pdf', response.data);
  console.log('PDF downloaded successfully!');
}

downloadPDF();

PHP

Using Guzzle (Recommended)

<?php
require 'vendor/autoload.php';

use GuzzleHttp\Client;

$client = new Client([
    'base_uri' => 'https://your-app.com',
    'headers' => [
        'Authorization' => 'Bearer YOUR_API_TOKEN',
        'Content-Type' => 'application/json',
    ]
]);

$response = $client->post('/api/v1/pdf', [
    'json' => [
        'html' => '<h1>Hello from PHP</h1><p>This is a test document.</p>'
    ]
]);

$data = json_decode($response->getBody(), true);
$pdfContent = base64_decode($data['pdf_content']);

file_put_contents('output.pdf', $pdfContent);
echo "PDF generated successfully!";

Download Binary PDF with Guzzle

<?php
use GuzzleHttp\Client;

$client = new Client([
    'base_uri' => 'https://your-app.com',
    'headers' => [
        'Authorization' => 'Bearer YOUR_API_TOKEN',
    ]
]);

$response = $client->post('/api/v1/pdf', [
    'headers' => [
        'Accept' => 'application/pdf',
    ],
    'json' => [
        'html' => '<h1>Invoice</h1><p>Order #12345</p>'
    ]
]);

file_put_contents('invoice.pdf', $response->getBody());
echo "PDF saved!";

Using PHP cURL Extension

<?php
$ch = curl_init('https://your-app.com/api/v1/pdf');

curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer YOUR_API_TOKEN',
    'Content-Type: application/json',
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'html' => '<h1>Document Title</h1><p>Content here</p>'
]));

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

if ($httpCode === 200) {
    $data = json_decode($response, true);
    $pdf = base64_decode($data['pdf_content']);
    file_put_contents('document.pdf', $pdf);
    echo "Success!";
} else {
    echo "Error: " . $response;
}

Using Laravel HTTP Client

<?php
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Storage;

$response = Http::withToken('YOUR_API_TOKEN')
    ->post('https://your-app.com/api/v1/pdf', [
        'html' => '<h1>Laravel Example</h1><p>PDF generation from Laravel</p>'
    ]);

if ($response->successful()) {
    $pdfContent = base64_decode($response->json('pdf_content'));
    Storage::put('generated.pdf', $pdfContent);
    return response()->download(storage_path('app/generated.pdf'));
}

Error Handling

Common Error Responses

401 Unauthorized

Missing or invalid API token.

{
  "message": "Unauthenticated."
}

Cause: Authorization header is missing or the token is invalid.

Solution: Verify your Authorization header is properly formatted: Authorization: Bearer YOUR_TOKEN

402 Payment Required

No active subscription.

{
  "message": "Subscription required."
}

Cause: Your trial has expired or you don’t have an active subscription.

Solution: Subscribe to a plan at the billing portal.

422 Validation Error

Invalid or missing request data.

{
  "message": "The html field is required.",
  "errors": {
    "html": [
      "The html field is required."
    ]
  }
}

Cause: The html parameter is missing or not a string.

Solution: Ensure your request includes the html field with valid HTML content.

Error Handling Examples

JavaScript

try {
  const response = await fetch('https://your-app.com/api/v1/pdf/create', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_TOKEN',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ html: '<h1>Test</h1>' })
  });

  if (!response.ok) {
    const error = await response.json();
    console.error('API Error:', error.message);
    return;
  }

  const data = await response.json();
  // Process PDF...
} catch (error) {
  console.error('Request failed:', error);
}

PHP

<?php
try {
    $response = $client->post('/api/v1/pdf/create', [
        'json' => ['html' => '<h1>Test</h1>']
    ]);

    $data = json_decode($response->getBody(), true);
    // Process PDF...

} catch (\GuzzleHttp\Exception\ClientException $e) {
    $statusCode = $e->getResponse()->getStatusCode();
    $error = json_decode($e->getResponse()->getBody(), true);

    if ($statusCode === 401) {
        echo "Authentication failed: Check your API token";
    } elseif ($statusCode === 402) {
        echo "Subscription required: Please subscribe at /billing";
    } elseif ($statusCode === 422) {
        echo "Validation error: " . $error['message'];
    }
}

Subscription Plans & Rate Limits

Plans

All plans include a 7-day free trial.

PlanMonthly RequestsFeatures
Starter1,000Unlimited API keys, Unlimited watermarked PDFs (testing), Email support
Growth5,000Unlimited API keys, Unlimited watermarked PDFs (testing), Email support
Business10,000Unlimited API keys, Unlimited watermarked PDFs (testing), Priority email support

Rate Limits

  • Monthly quotas reset on the first day of each billing period
  • Account-level limits – All API tokens share the same quota
  • Overage handling – Requests over your limit return 429 Too Many Requests

Managing Your Subscription

  • View usage and current plan at the billing portal
  • Upgrade or downgrade anytime (prorated billing)
  • Create unlimited API tokens (they share your account quota)

Common Use Cases

Invoice Generation

<!DOCTYPE html>
<html>
<head>
  <style>
    body {
      font-family: Arial, sans-serif;
      margin: 40px;
    }
    .header {
      text-align: center;
      margin-bottom: 40px;
    }
    .invoice-details {
      margin: 20px 0;
    }
    table {
      width: 100%;
      border-collapse: collapse;
      margin: 20px 0;
    }
    th, td {
      padding: 10px;
      text-align: left;
      border-bottom: 1px solid #ddd;
    }
    .total {
      text-align: right;
      font-size: 18px;
      font-weight: bold;
      margin-top: 20px;
    }
  </style>
</head>
<body>
  <div class="header">
    <h1>INVOICE</h1>
    <p>Invoice #12345 | Date: January 15, 2025</p>
  </div>

  <div class="invoice-details">
    <p><strong>Bill To:</strong><br>
    John Doe<br>
    123 Main St<br>
    Anytown, USA 12345</p>
  </div>

  <table>
    <thead>
      <tr>
        <th>Description</th>
        <th>Quantity</th>
        <th>Price</th>
        <th>Total</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>Professional Services</td>
        <td>10 hours</td>
        <td>$150/hr</td>
        <td>$1,500.00</td>
      </tr>
      <tr>
        <td>Consulting</td>
        <td>5 hours</td>
        <td>$200/hr</td>
        <td>$1,000.00</td>
      </tr>
    </tbody>
  </table>

  <div class="total">
    Total: $2,500.00
  </div>
</body>
</html>

Report with Tables and Charts

For best results:

  • Use inline CSS or <style> tags in the <head> section
  • Embed images as base64 data URIs or use absolute URLs
  • Keep HTML valid – Use proper DOCTYPE and structure
  • Test complex layouts using watermarked PDFs (unlimited, free)

Best Practices

  1. CSS Styling: Use inline styles or <style> tags. External stylesheets must use absolute URLs.
  2. Images:
    • Use base64-encoded data URIs: <img src="data:image/png;base64,...">
    • Or absolute URLs: <img src="https://example.com/image.png">
    • Relative paths won’t work
  3. Fonts:
    • Stick to web-safe fonts (Arial, Times New Roman, etc.)
    • Or use @import with Google Fonts URLs
  4. Page Size:
    • Current format: Letter (8.5″ × 11″)
    • Design your HTML accordingly

Troubleshooting

Common Issues

PDF is blank or incomplete

Possible causes:

  • Invalid HTML structure
  • External resources failing to load
  • JavaScript errors (JavaScript is supported but may not execute as expected)

Solutions:

  • Validate your HTML
  • Embed images as base64
  • Use inline CSS instead of external stylesheets

CSS styles not rendering

Possible causes:

  • External stylesheet URLs not accessible
  • CSS syntax errors

Solutions:

  • Use inline styles: <p style="color: red;">Text</p>
  • Or use <style> tags in the HTML <head>
  • Ensure external stylesheets use HTTPS URLs

Images not displaying

Possible causes:

  • Relative image paths
  • External images not loading
  • Image URLs using HTTP instead of HTTPS

Solutions:

  • Convert images to base64 data URIs
  • Use absolute HTTPS URLs for images
  • Verify image URLs are publicly accessible

Request timeout

Possible causes:

  • HTML is too complex
  • Too many external resources
  • Large images

Solutions:

  • Simplify your HTML structure
  • Reduce number of images or compress them
  • Embed resources as base64 to reduce external requests
  • Note: Maximum timeout is 5 minutes

Technical Limitations

  • Timeout: Maximum 5 minutes (300 seconds) per request
  • Memory: 2GB allocation for PDF generation
  • Storage: 512MB temporary storage
  • Page Format: Currently Letter (8.5″ × 11″)
  • Processing: Rendered using Chromium via AWS Lambda

Best Practices for Reliable PDFs

  1. Keep HTML structure simple and valid
  2. Use inline CSS when possible
  3. Embed images as base64 or use absolute HTTPS URLs
  4. Test with watermarked PDFs first (unlimited, doesn’t count toward quota)
  5. Handle API errors gracefully in your application
  6. Implement retry logic for network failures
  7. Monitor your quota usage in the billing portal

Support

Getting Help

  • Email Support: Available on all plans (Starter, Growth)
  • Priority Email Support: Available on Business plan
  • Response Time:
    • Standard: Within 24-48 hours
    • Priority: Within 12 hours

Useful Links

Feedback & Feature Requests

We’re constantly improving OffloadPDF. If you have suggestions or feature requests, please reach out.