PDFSpark API Documentation

Convert HTML and URLs to pixel-perfect PDFs using Chromium with full JavaScript, CSS3, and web font rendering. The API is completely free — no API keys, no authentication, no signup.

Base URL: https://pdfspark.dev/api/v1

Authentication

No authentication is required. Simply make HTTP requests to the endpoints below. All responses return the PDF binary directly (application/pdf).

POST /pdf/from-html

POST /api/v1/pdf/from-html

Convert raw HTML content to PDF. Supports inline CSS, JavaScript, images via data URIs or external URLs, and web fonts.

Request Body (JSON)

FieldTypeRequiredDescription
html string required The HTML content to convert (max 5MB)
options object optional PDF generation options (see Options)

Example Request

cURL
curl -X POST "https://pdfspark.dev/api/v1/pdf/from-html" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<h1>Hello World</h1><p>Generated by PDFSpark</p>",
    "options": {
      "format": "A4",
      "margin": { "top": "20mm", "bottom": "20mm" }
    }
  }' \
  -o document.pdf

Response

Returns the PDF file directly as application/pdf binary. Use -o filename.pdf in cURL to save it.

POST /pdf/from-url

POST /api/v1/pdf/from-url

Convert a public webpage to PDF. The URL is loaded in Chromium with full JavaScript execution, just like a real browser.

Request Body (JSON)

FieldTypeRequiredDescription
url string required The URL to convert (must be http/https, no private IPs)
options object optional PDF generation and navigation options (see Options)

Example Request

cURL
curl -X POST "https://pdfspark.dev/api/v1/pdf/from-url" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "options": {
      "format": "A4",
      "printBackground": true,
      "waitUntil": "networkidle"
    }
  }' \
  -o example.pdf

POST /pdf/merge

POST /api/v1/pdf/merge

Merge multiple PDF documents into a single PDF. Accepts an array of base64-encoded PDF strings and returns the combined document with all pages preserved in order.

Request Body (JSON)

FieldTypeRequiredDescription
pdfs string[] required Array of base64-encoded PDF strings (min 2, max 20, total max 50MB)

Example Request

JavaScript
const pdf1 = btoa(await (await fetch('/api/v1/pdf/from-html', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ html: '<h1>Cover Page</h1>' })
})).text());

const pdf2 = btoa(await (await fetch('/api/v1/pdf/from-html', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ html: '<h1>Chapter 1</h1><p>Content...</p>' })
})).text());

const merged = await fetch('/api/v1/pdf/merge', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ pdfs: [pdf1, pdf2] })
});

const blob = await merged.blob();
// merged PDF with all pages from both documents

Response

Returns the merged PDF as application/pdf binary with metadata headers.

POST /pdf/split

POST /api/v1/pdf/split

Extract specific pages from a PDF document. Accepts a base64-encoded PDF and a page range string, returns a new PDF containing only the specified pages.

Request Body (JSON)

FieldTypeRequiredDescription
pdf string required Base64-encoded PDF string (max 50MB)
pages string required Page range to extract, e.g. "1-3,5,8-10". Pages are 1-indexed.

Page Range Syntax

ExampleDescription
"1"Extract only page 1
"1-3"Extract pages 1 through 3
"1,3,5"Extract pages 1, 3, and 5
"1-3,7-9"Extract pages 1-3 and 7-9
"2-4,1"Extract pages 1-4 (duplicates removed, sorted)

Example Request

cURL
curl -X POST https://pdfspark.dev/api/v1/pdf/split \
  -H "Content-Type: application/json" \
  -d '{
    "pdf": "<base64-encoded-pdf>",
    "pages": "1-3,5"
  }' \
  --output extracted.pdf

Response

Returns the extracted pages as application/pdf binary with metadata headers.

POST /pdf/info

POST /api/v1/pdf/info

Extract metadata, page count, page dimensions, and file size from an existing PDF document. No browser required — fast, lightweight parsing using pdf-lib.

Request Body (JSON)

FieldTypeRequiredDescription
pdf string required Base64-encoded PDF string (max 50MB)

Example Request

cURL
curl -X POST https://pdfspark.dev/api/v1/pdf/info \
  -H "Content-Type: application/json" \
  -d '{
    "pdf": "<base64-encoded-pdf>"
  }'

Response (JSON)

JSON Response
{
  "pages": 3,
  "size": 45210,
  "metadata": {
    "title": "My Document",
    "author": "John Doe",
    "subject": "Example",
    "keywords": "pdf, test",
    "creator": "PDFSpark",
    "producer": "pdf-lib",
    "creationDate": "2026-01-15T10:30:00.000Z",
    "modificationDate": "2026-03-01T14:00:00.000Z"
  },
  "pageDimensions": [
    { "page": 1, "width": 595.28, "height": 841.89 },
    { "page": 2, "width": 595.28, "height": 841.89 },
    { "page": 3, "width": 841.89, "height": 595.28 }
  ],
  "processingDurationMs": 12
}
This endpoint does not require a browser instance — it parses the PDF directly, making it very fast. Use it to inspect PDFs before merging, splitting, or applying watermarks.

Response Metadata Headers

All PDF endpoints (/pdf/from-html, /pdf/from-url, /pdf/merge, /pdf/split) include these metadata headers in successful responses for observability and integration with monitoring tools:

HeaderTypeDescription
X-Render-Duration-MsnumberTime taken to generate or merge the PDF in milliseconds
X-Page-CountnumberTotal number of pages in the resulting PDF
X-Pdf-Size-BytesnumberSize of the PDF file in bytes
These headers enable integration with monitoring tools (Datadog, Grafana, etc.) without client-side timing. Use X-Render-Duration-Ms to track performance and X-Page-Count to verify document completeness.

GET /status

GET /api/v1/status

Returns service status and available endpoints.

Response
{
  "service": "PDFSpark",
  "version": "1.0.0",
  "status": "operational",
  "endpoints": [
    { "method": "POST", "path": "/api/v1/pdf/from-html" },
    { "method": "POST", "path": "/api/v1/pdf/from-url" },
    { "method": "POST", "path": "/api/v1/pdf/merge" },
    { "method": "POST", "path": "/api/v1/pdf/split" },
    { "method": "POST", "path": "/api/v1/pdf/info" },
    { "method": "GET", "path": "/api/v1/status" }
  ]
}

Page Format Options

OptionTypeDefaultDescription
formatstring"A4"Page format: A3, A4, A5, Letter, Legal, Tabloid
widthstringCustom page width (e.g. "8.5in"). Overrides format.
heightstringCustom page height (e.g. "11in"). Overrides format.
landscapebooleanfalseLandscape orientation
printBackgroundbooleantruePrint background graphics and colors
scalenumber1Scale factor (0.1 to 2.0)
pageRangesstring""Page ranges to print (e.g. "1-3, 5")
preferCSSPageSizebooleanfalseUse CSS @page size instead of format

Margin Options

OptionTypeDefaultDescription
margin.topstring"10mm"Top margin (CSS units: mm, in, px, cm)
margin.rightstring"10mm"Right margin
margin.bottomstring"10mm"Bottom margin
margin.leftstring"10mm"Left margin
OptionTypeDefaultDescription
displayHeaderFooterbooleanfalseEnable header and footer
headerTemplatestring""HTML template for header. Supports: date, title, url, pageNumber, totalPages
footerTemplatestring""HTML template for footer (same classes as header)
Header/footer templates use special CSS classes: <span class="pageNumber"></span>, <span class="totalPages"></span>, <span class="date"></span>, <span class="title"></span>, <span class="url"></span>.
OptionTypeDefaultDescription
waitUntilstring"domcontentloaded"load, domcontentloaded, or networkidle
waitForSelectorstringWait for a CSS selector to appear before PDF generation
delaynumber0Additional delay in ms after page load (max 10000)
timeoutnumber30000Navigation timeout in ms (max 60000)
cssstringCustom CSS to inject before PDF generation
javascriptbooleantrueEnable/disable JavaScript execution
viewport.widthnumber1280Viewport width in pixels
viewport.heightnumber720Viewport height in pixels

Custom HTTP Headers (URL mode)

Pass custom HTTP headers to the target URL when using /pdf/from-url. Useful for accessing authenticated pages or passing API tokens.

OptionTypeDefaultDescription
headersobject{}Key-value pairs of HTTP headers sent with the page request. Max 20 headers.
Blocked headers (cannot be overridden): Host, Cookie, Set-Cookie, Origin, Referer, Proxy-Authorization, Transfer-Encoding, Content-Length.

Example: Authenticated URL

cURL
curl -X POST "https://pdfspark.dev/api/v1/pdf/from-url" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://app.example.com/dashboard",
    "options": {
      "headers": {
        "Authorization": "Bearer eyJhbGci...",
        "X-Custom-Header": "my-value"
      },
      "waitUntil": "networkidle"
    }
  }' \
  -o dashboard.pdf

Media Type Emulation

Control which CSS @media rules apply during PDF generation. Use "print" to activate print stylesheets for cleaner, ink-friendly PDFs, or "screen" to force screen styles.

OptionTypeDefaultDescription
emulateMediaTypestring"print" or "screen". When set, triggers the corresponding CSS @media rules.
Many websites include @media print stylesheets that hide navigation, ads, and non-essential elements. Use "print" to generate cleaner PDFs automatically.

Example: Print-optimized PDF

cURL
curl -X POST "https://pdfspark.dev/api/v1/pdf/from-url" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://en.wikipedia.org/wiki/PDF",
    "options": {
      "emulateMediaType": "print",
      "format": "A4"
    }
  }' \
  -o article.pdf

PDF Metadata

Set document properties (title, author, subject, keywords) that appear in PDF reader info panels. PDFs without metadata show as “Untitled” in most readers.

OptionTypeMax LengthDescription
metadata.titlestring500 charsDocument title shown in PDF reader title bar
metadata.authorstring200 charsDocument author
metadata.subjectstring500 charsDocument subject/description
metadata.keywordsstring[]20 itemsArray of keyword strings for document discovery
metadata.creatorstring200 charsApplication that created the content
metadata.producerstring200 charsApplication that produced the PDF

Example: Invoice with metadata

cURL
curl -X POST "https://pdfspark.dev/api/v1/pdf/from-html" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<h1>Invoice #1234</h1><p>Total: $99.00</p>",
    "options": {
      "format": "A4",
      "metadata": {
        "title": "Invoice #1234",
        "author": "Acme Corp",
        "subject": "Monthly invoice for March 2026",
        "keywords": ["invoice", "acme", "march-2026"],
        "creator": "Acme Billing System"
      }
    }
  }' \
  -o invoice.pdf

Text Watermark

Add a diagonal text watermark across every page of the generated PDF. Useful for marking documents as “DRAFT”, “CONFIDENTIAL”, “COPY”, or “PAID”.

OptionTypeDefaultDescription
watermark.textstringWatermark text (required, max 200 chars)
watermark.fontSizenumber48Font size in points (8–200)
watermark.opacitynumber0.3Opacity (0.01–1.0)
watermark.rotationnumber-45Rotation angle in degrees (-360 to 360)
watermark.colorobject{r:0.5, g:0.5, b:0.5}RGB color with values 0–1 (e.g. {r:1, g:0, b:0} for red)

Example: Draft watermark

cURL
curl -X POST "https://pdfspark.dev/api/v1/pdf/from-html" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<h1>Invoice #1234</h1><p>Total: $99.00</p>",
    "options": {
      "format": "A4",
      "watermark": {
        "text": "DRAFT",
        "fontSize": 72,
        "opacity": 0.15,
        "rotation": -45,
        "color": { "r": 1, "g": 0, "b": 0 }
      }
    }
  }' \
  -o draft-invoice.pdf
The watermark is rendered as centered text on every page. It uses Helvetica font and is applied after PDF generation, so it appears on top of the content.

Image Watermark

Overlay a PNG or JPEG image on every page of the generated PDF. Ideal for company logos, approval stamps, “CONFIDENTIAL” badges, or branding marks.

OptionTypeDefaultDescription
imageWatermark.imagestringBase64-encoded PNG or JPEG image data (required, max 2MB)
imageWatermark.typestring"png"Image format: "png" or "jpg"
imageWatermark.opacitynumber0.3Opacity (0.01–1.0)
imageWatermark.scalenumber0.5Scale factor (0.1–5.0). 1.0 = original image size.
imageWatermark.positionstring"center"Placement on page: "center", "top-left", "top-right", "bottom-left", "bottom-right"

Example: Logo watermark

cURL
curl -X POST "https://pdfspark.dev/api/v1/pdf/from-html" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<h1>Quarterly Report</h1><p>Company results...</p>",
    "options": {
      "format": "A4",
      "imageWatermark": {
        "image": "<base64-encoded-png>",
        "type": "png",
        "opacity": 0.15,
        "scale": 0.3,
        "position": "bottom-right"
      }
    }
  }' \
  -o branded-report.pdf
The image watermark is drawn on top of page content. Use low opacity (0.1–0.3) for subtle branding. Supports transparent PNGs for best results. Can be combined with text watermark — both will be applied.

Password Protection

Encrypt the generated PDF with a password. Recipients must enter the password to open the document. Supports AES-256 (recommended) and RC4 128-bit (legacy readers) encryption.

OptionTypeDefaultDescription
password.userPasswordstringPassword required to open the PDF (required, max 128 chars)
password.ownerPasswordstringsame as userPassword for managing permissions (editing restrictions)
password.algorithmstring"AES-256""AES-256" (PDF 2.0, recommended) or "RC4" (128-bit, legacy readers)
password.permissions.printingbooleantrueAllow printing the document
password.permissions.copyingbooleantrueAllow copying text and images
password.permissions.modifyingbooleantrueAllow modifying content
password.permissions.annotatingbooleantrueAllow adding annotations
password.permissions.fillingFormsbooleantrueAllow filling in forms
password.permissions.extractionbooleantrueAllow accessibility text extraction
password.permissions.assemblybooleantrueAllow document assembly

Example: Password-protected PDF

cURL
curl -X POST "https://pdfspark.dev/api/v1/pdf/from-html" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<h1>Confidential Report</h1><p>Q1 Financial Summary</p>",
    "options": {
      "format": "A4",
      "password": {
        "userPassword": "secret123",
        "ownerPassword": "admin456",
        "algorithm": "AES-256",
        "permissions": {
          "printing": true,
          "copying": false,
          "modifying": false
        }
      }
    }
  }' \
  -o confidential-report.pdf
The password protection works on /pdf/from-html and /pdf/from-url endpoints. Use "AES-256" for maximum security (PDF 2.0 standard). Use "RC4" only if recipients use older PDF readers that don’t support AES.

Output Options

Control the output filename and response format for all PDF endpoints.

OptionTypeDefaultDescription
filenamestring"document.pdf"Custom filename for Content-Disposition header (max 255 chars). Auto-appends .pdf if missing. Unsafe characters are sanitized.
responseFormatstring"binary""binary" returns PDF as application/pdf. "base64" returns a JSON object with the PDF encoded as a base64 string.

Base64 Response Format

When responseFormat is set to "base64", the response is a JSON object instead of binary PDF:

Base64 JSON Response
{
  "data": "JVBERi0xLjcK...",
  "filename": "invoice.pdf",
  "pages": 1,
  "size": 24576,
  "renderDurationMs": 320
}
The base64 format is ideal for no-code/low-code platforms (Zapier, Make, Retool), serverless functions, and any client that cannot handle binary streams. The filename and responseFormat options work on all PDF endpoints: /pdf/from-html, /pdf/from-url, /pdf/merge, and /pdf/split.

Example: Custom filename with base64

cURL
curl -X POST "https://pdfspark.dev/api/v1/pdf/from-html" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<h1>Invoice #1234</h1><p>Total: $99.00</p>",
    "options": {
      "format": "A4",
      "filename": "invoice-1234.pdf",
      "responseFormat": "base64"
    }
  }'

Error Codes

StatusMeaning
400Bad Request — Missing or invalid input (HTML, URL, or options)
404Not Found — Endpoint does not exist
413Payload Too Large — HTML exceeds 5MB, or merged/split PDFs exceed 50MB
422Unprocessable Entity — PDFs in merge/split request could not be parsed, or invalid page range
429Too Many Requests — Rate limit exceeded (20/min)
500Internal Server Error — PDF generation failed
503Service Unavailable — Server busy (too many concurrent requests)

Error responses are JSON:

Error Response
{
  "error": "Missing HTML",
  "message": "Provide an \"html\" field in the request body"
}

Rate Limits

LimitValue
Requests per minute20 per IP address
Max concurrent PDFs5 server-wide
Max HTML size5MB
Navigation timeout60s max
Rate limit headers are included in every response: RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset.

cURL Examples

terminal
# Convert HTML to PDF
curl -X POST "https://pdfspark.dev/api/v1/pdf/from-html" \
  -H "Content-Type: application/json" \
  -d '{"html": "<h1>Invoice #1234</h1><p>Total: $99.00</p>"}' \
  -o invoice.pdf

# Convert URL to PDF (landscape A3)
curl -X POST "https://pdfspark.dev/api/v1/pdf/from-url" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://github.com",
    "options": { "format": "A3", "landscape": true }
  }' \
  -o github.pdf

JavaScript Example

app.js
// Convert HTML to PDF
const response = await fetch('https://pdfspark.dev/api/v1/pdf/from-html', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    html: '<h1>Hello World</h1><p>From PDFSpark</p>',
    options: { format: 'A4', margin: { top: '20mm', bottom: '20mm' } }
  })
});

const blob = await response.blob();
const url = URL.createObjectURL(blob);
window.open(url); // or save with a download link

// Convert URL to PDF
const urlResponse = await fetch('https://pdfspark.dev/api/v1/pdf/from-url', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ url: 'https://example.com' })
});

const pdfBlob = await urlResponse.blob();
// Use pdfBlob as needed...

Python Example

main.py
import requests

# Convert HTML to PDF
response = requests.post(
    'https://pdfspark.dev/api/v1/pdf/from-html',
    json={
        'html': '<h1>Invoice #1234</h1><p>Total: $99.00</p>',
        'options': {'format': 'A4', 'printBackground': True}
    }
)

with open('invoice.pdf', 'wb') as f:
    f.write(response.content)

# Convert URL to PDF
response = requests.post(
    'https://pdfspark.dev/api/v1/pdf/from-url',
    json={'url': 'https://example.com'}
)

with open('example.pdf', 'wb') as f:
    f.write(response.content)

MCP Integration

PDFSpark ships with a built-in Model Context Protocol (MCP) server. Connect PDFSpark directly to Claude, VS Code, Cursor, or any MCP-compatible AI client to generate PDFs from your assistant.

Installation

Add the following to your MCP client configuration:

claude_desktop_config.json
{
  "mcpServers": {
    "pdfspark": {
      "command": "npx",
      "args": ["-y", "pdfspark-api"]
    }
  }
}

Available Tools

ToolDescriptionParameters
html_to_pdf Convert raw HTML content to a PDF document html (string, required), format, landscape, margin, printBackground, scale, pageRanges, displayHeaderFooter, headerTemplate, footerTemplate
url_to_pdf Convert a public webpage URL to a PDF document url (string, required), format, landscape, margin, printBackground, scale, pageRanges, waitUntil, delay, timeout

Environment Variables

VariableDefaultDescription
PDFSPARK_BASE_URL https://pdfspark.dev Override the base URL for API requests (e.g., for self-hosted instances)
Part of the SoftVoyagers Ecosystem