PDFStack API Docs

Production docs for customer-facing PDFStack API endpoints.

Base URL
/api/v1
Auth model
Bearer → API Key
Core ops
5
Production
pdfstack.dev

Base URL

https://pdfstack.dev/api/v1

Authentication flow

Required: sign up → verify email → log in → create API key → call processing endpoints with X-API-Key.
  1. Sign up: POST /auth/signup
  2. Verify email (link in inbox)
  3. Log in: POST /auth/login
  4. Create key: POST /auth/create-key with Authorization: Bearer ...
  5. Call endpoints below with X-API-Key: YOUR_API_KEY

Error codes & troubleshooting

StatusCodeMeaning / fix
400INVALID_REQUEST, MISSING_FILEValidate required fields/body format.
401MISSING_API_KEY, INVALID_API_KEYProvide a valid X-API-Key.
403EMAIL_NOT_VERIFIEDVerify account before key creation/regeneration.
413FILE_TOO_LARGEReduce file size or upgrade plan.
429USAGE_LIMIT_EXCEEDEDMonthly quota reached; upgrade/wait for monthly reset.
500INTERNAL_ERRORRetry; contact support with request details.

Limits, quotas, and plans

PlanMonthly PDFsMax file sizeSupport
Free505MBBasic
Starter50025MBPriority
Pro5,000100MB24/7

Delivery modes

File-producing endpoints support delivery=inline|url|auto. Default is inline when omitted.

Inline response example

{
  "success": true,
  "data": {
    "file": "data:application/pdf;base64,JVBERi0xLjQK...",
    "filename": "output.pdf",
    "contentType": "application/pdf",
    "size": 120344
  }
}

URL response example

{
  "success": true,
  "data": {
    "url": "https://pdfstack.dev/api/v1/delivery/<token>",
    "expiresAt": "2026-03-24T06:00:00.000Z",
    "filename": "output.pdf",
    "contentType": "application/pdf",
    "size": 120344
  }
}

Auth endpoint reference

POST/auth/signup

Create account.

POST/auth/login

Receive session Bearer token.

POST/auth/create-key

Create first API key for verified account.

POST/auth/regenerate-key

Rotate API key.

DELETE/auth/revoke-key

Revoke current key.

GET/auth/me

Current user + API key metadata.

GET/auth/my-keys

List account keys.

GET/auth/verify

Validate API key by query.

Endpoint Reference

PDF Convert

Extract text from PDF or convert to DOCX.

POST /api/v1/pdf/convert

Request Body (multipart/form-data)

Field Type Required Default Description
file binary Yes - PDF file to convert
format string Yes - Output format: text or docx
delivery string No inline Output delivery mode: inline, url, or auto

Supported Formats

FormatDescriptionUse Case
text Plain text extraction Extract readable text from PDF (no formatting)
docx Microsoft Word document Convert PDF to editable Word format

Code Examples

import fs from "node:fs";

const apiKey = process.env.PDFSTACK_API_KEY;
const form = new FormData();
form.append("file", new Blob([fs.readFileSync("./document.pdf")], { type: "application/pdf" }), "document.pdf");
form.append("format", "text");

const res = await fetch("https://pdfstack.dev/api/v1/pdf/convert", {
  method: "POST",
  headers: { "X-API-Key": apiKey },
  body: form
});

const payload = await res.json();
if (!res.ok) throw new Error(`convert failed: ${res.status} ${payload?.error?.code || "UNKNOWN"}`);
console.log(payload.data.text.slice(0, 200));

Response Format

This endpoint returns a JSON response with the converted data. The structure varies based on the selected format:

For format=text:

{
  "success": true,
  "data": {
    "text": "Full extracted text from all pages...",
    "pages": [
      { "pageNumber": 1, "text": "Page 1 text..." },
      { "pageNumber": 2, "text": "Page 2 text..." }
    ],
    "info": {
      "numPages": 5,
      "pageCount": 5,
      "fileSize": 123456
    }
  }
}

For format=docx:

{
  "success": true,
  "data": {
    "file": "data:application/vnd.openxmlformats-officedocument.wordprocessingml.document;base64,UEsDBBQABgAI...",
    "filename": "converted_xxx.docx",
    "info": {
      "numPages": 5,
      "pageCount": 5,
      "fileSize": 123456
    }
  }
}

Decoding the file (format=docx):

JavaScript example:

const base64Data = response.data.file.split(',')[1];
const buffer = Buffer.from(base64Data, 'base64');
fs.writeFileSync('output.docx', buffer);

Delivery modes: inline returns file data URL payload, url returns temporary url + expiresAt, and auto selects based on payload size (default when omitted: inline).

File size limits: Maximum response size is approximately 4MB when using inline. Use delivery=url or delivery=auto for larger outputs.

Limitations

  • Scanned PDFs: PDFs without a text layer (scanned images) are not supported — OCR is not implemented
  • Encrypted PDFs: Password-protected or encrypted PDFs are not supported
  • Text extraction quality: Quality depends on PDF structure; complex layouts may have degraded extraction
  • DOCX conversion: Preserves basic formatting only (no complex layouts, tables, or embedded media)
  • File size: Maximum input file size is 10MB (Vercel serverless limit)
  • Timeout: Processing timeout is 30 seconds by default

Common Errors

Error CodeCauseSolution
MISSING_FILE No file provided in request Ensure file is included in multipart/form-data body
INVALID_FORMAT Unsupported format parameter Use text or docx only
FILE_TOO_LARGE File exceeds 10MB size limit Compress PDF or split into smaller files
PROCESSING_TIMEOUT Processing took longer than 30 seconds Reduce file size or complexity
INVALID_PDF Corrupted or invalid PDF file Verify file is a valid PDF, try re-saving from source

For authentication and billing errors, see the Errors section.

See Also:

PDF Merge

Combine multiple PDFs into one file.

POST /api/v1/pdf/merge

Request Body (multipart/form-data)

Field Type Required Default Description
files binary[] Yes - Array of 2-10 PDF files to merge in order
delivery string No inline Output delivery mode: inline, url, or auto

Code Examples

import fs from "node:fs";

const apiKey = process.env.PDFSTACK_API_KEY;
const form = new FormData();
form.append("files", new Blob([fs.readFileSync("./a.pdf")], { type: "application/pdf" }), "a.pdf");
form.append("files", new Blob([fs.readFileSync("./b.pdf")], { type: "application/pdf" }), "b.pdf");

const res = await fetch("https://pdfstack.dev/api/v1/pdf/merge", {
  method: "POST",
  headers: { "X-API-Key": apiKey },
  body: form
});
const payload = await res.json();
if (!res.ok) throw new Error(`merge failed: ${res.status} ${payload?.error?.code || "UNKNOWN"}`);
console.log(payload.data.filename || "Merged successfully");

Response Format

This endpoint returns a JSON response with the merged PDF encoded as base64:

{
  "success": true,
  "data": {
    "file": "data:application/pdf;base64,JVBERi0xLjQK...",
    "filename": "merged_xxx.pdf",
    "pageCount": 2
  }
}

Decoding the file:

JavaScript example:

const base64Data = response.data.file.split(',')[1];
const buffer = Buffer.from(base64Data, 'base64');
fs.writeFileSync('merged.pdf', buffer);

File size limits: Maximum response size is approximately 4MB due to JSON payload limits. For larger files, consider compressing individual PDFs before merging.

Limitations

  • File count: Minimum 2 files, maximum 10 files per request
  • Format: All files must be valid PDFs (no mixed formats)
  • Encrypted PDFs: Password-protected or encrypted PDFs are not supported
  • Total size: Combined file size limit is 25MB
  • Metadata: Only metadata from the first PDF is preserved in the merged output
  • Timeout: Processing timeout is 30 seconds by default

Common Errors

Error CodeCauseSolution
INSUFFICIENT_FILES No files provided in request Ensure at least 2 PDF files are included in multipart/form-data body
INSUFFICIENT_FILES Fewer than 2 or more than 10 files Provide between 2 and 10 PDF files
FILE_TOO_LARGE Combined file size exceeds 25MB limit Reduce individual file sizes or merge fewer files
INVALID_PDF Corrupted or invalid PDF file Verify all files are valid PDFs, try re-saving from source

For authentication and billing errors, see the Errors section.

See Also:

PDF Split

Extract specific pages from a PDF.

POST /api/v1/pdf/split

Request Body (multipart/form-data)

Field Type Required Default Description
file binary Yes - PDF file to split
pages string Yes - Comma-separated page numbers to extract (e.g., "1,3,5")
delivery string No inline Output delivery mode: inline, url, or auto

Code Examples

import fs from "node:fs";

const apiKey = process.env.PDFSTACK_API_KEY;
const form = new FormData();
form.append("file", new Blob([fs.readFileSync("./document.pdf")], { type: "application/pdf" }), "document.pdf");
form.append("pages", "1,3,5");

const res = await fetch("https://pdfstack.dev/api/v1/pdf/split", {
  method: "POST",
  headers: { "X-API-Key": apiKey },
  body: form
});
const payload = await res.json();
if (!res.ok) throw new Error(`split failed: ${res.status} ${payload?.error?.code || "UNKNOWN"}`);
console.log(payload.data.files.length);

Response Format

This endpoint returns a JSON response with an array of base64-encoded PDF files (one per requested page):

{
  "success": true,
  "data": {
    "files": [
      {
        "page": "1",
        "file": "data:application/pdf;base64,JVBERi0xLjQK..."
      },
      {
        "page": "3",
        "file": "data:application/pdf;base64,JVBERi0xLjQK..."
      }
    ]
  }
}

Decoding the files:

JavaScript example:

response.data.files.forEach(item => {
  const base64Data = item.file.split(',')[1];
  const buffer = Buffer.from(base64Data, 'base64');
  fs.writeFileSync(`page_${item.page}.pdf`, buffer);
});

File size limits: Maximum response size is approximately 4MB due to JSON payload limits. For large PDFs with many pages, consider splitting into smaller batches.

Limitations

  • Input: Single PDF input only (use merge for multi-file operations)
  • Page ranges: Must be valid format (e.g., "1,3,5" or "1-5"); invalid ranges return errors
  • Encrypted PDFs: Password-protected or encrypted PDFs cannot be split
  • File size: Maximum input file size is 10MB
  • Timeout: Processing timeout is 30 seconds by default

Common Errors

Error CodeCauseSolution
MISSING_FILE No file provided in request Ensure file is included in multipart/form-data body
MISSING_PAGES Pages parameter not provided Provide comma-separated page numbers (e.g., "1,3,5")
INVALID_PAGES Invalid page numbers or format Use comma-separated integers; page numbers must exist in document
FILE_TOO_LARGE File exceeds 10MB size limit Compress PDF or split into smaller files first
INVALID_PDF Corrupted or invalid PDF file Verify file is a valid PDF, try re-saving from source

For authentication and billing errors, see the Errors section.

See Also:

Screenshot

Capture webpage screenshots as PNG, JPEG, or PDF.

POST /api/v1/screenshot

Request Body (application/json)

Field Type Required Default Description
url string No* - Website URL to capture (required if html not provided)
html string No* - Raw HTML to render (required if url not provided)
format string No png Output format: png, jpeg, or pdf
viewport object No { width: 1280, height: 720 } Viewport dimensions
fullPage boolean No false Capture full scrollable page
waitFor string No - CSS selector to wait for before capturing
delivery string No inline Output delivery mode: inline, url, or auto

* Either url or html is required (mutually exclusive)

Supported Formats

FormatDescriptionUse Case
png PNG image (lossless) High-quality screenshots with transparency support
jpeg JPEG image (lossy) Smaller file sizes for photos/complex content
pdf PDF document Print-ready format (uses A4 page size)

Advanced Options

The following optional parameters provide fine-grained control over screenshot capture. These are supported by the underlying Puppeteer library:

Parameter Type Default Description Validation
quality number 80 Image quality (JPEG only) Range: 0–100. Higher = better quality, larger file size.
clip object undefined Capture specific region: {x, y, width, height} Coordinates in pixels. Overrides fullPage.
omitBackground boolean false Transparent background (PNG only) Useful for overlaying images or transparent designs
timeout number 30000 Navigation timeout in milliseconds Min: 0 (no timeout), Max: 60000 (60s recommended)
waitUntil string networkidle0 When to consider navigation done Allowed: load, domcontentloaded, networkidle0, networkidle2
captureBeyondViewport boolean true Capture content outside viewport when fullPage=true Set false to only capture visible viewport area

Advanced Example: High-quality JPEG screenshot of specific region:

{
  "url": "https://example.com",
  "format": "jpeg",
  "quality": 95,
  "clip": {
    "x": 0,
    "y": 0,
    "width": 800,
    "height": 600
  },
  "waitUntil": "networkidle2"
}

Transparent PNG Example:

{
  "html": "<div style='background: transparent;'>Hello World</div>",
  "format": "png",
  "omitBackground": true,
  "viewport": { "width": 400, "height": 300 }
}

Code Examples

const apiKey = process.env.PDFSTACK_API_KEY;

const res = await fetch("https://pdfstack.dev/api/v1/screenshot", {
  method: "POST",
  headers: { "X-API-Key": apiKey, "Content-Type": "application/json" },
  body: JSON.stringify({ url: "https://example.com", format: "png", fullPage: true })
});

const payload = await res.json();
if (!res.ok) throw new Error(`screenshot failed: ${res.status} ${payload?.error?.code || "UNKNOWN"}`);
console.log(payload.data.file?.slice(0, 32));

Response Format

This endpoint returns a JSON response with the screenshot encoded as base64. The format depends on the requested output type:

{
  "success": true,
  "data": {
    "file": "data:image/png;base64,iVBORw0KGgoAAAANSU...",
    "filename": "screenshot_xxx.png",
    "format": "png",
    "viewport": {
      "width": 1280,
      "height": 720
    },
    "url": "https://example.com"
  }
}

Decoding the file:

JavaScript example:

const base64Data = response.data.file.split(',')[1];
const buffer = Buffer.from(base64Data, 'base64');
fs.writeFileSync(`screenshot.${response.data.format}`, buffer);

File size limits: Maximum response size is approximately 4MB due to JSON payload limits. For very large full-page screenshots, consider using a smaller viewport or capturing specific sections.

Limitations

  • JavaScript-heavy sites: Sites with heavy client-side rendering may require longer timeout or may not render correctly
  • Headless browser blocking: Some sites detect and block headless browser access
  • Authentication: Login flows are not supported; use pre-authenticated URLs or pass cookies
  • Viewport: Maximum viewport dimensions are 3840×2160 (4K)
  • Timeout: Navigation timeout is 30 seconds by default (configurable up to 60s)
  • File size: Large full-page screenshots may exceed 4MB response limit

Common Errors

Error CodeCauseSolution
MISSING_INPUT Neither url nor html provided Provide either url or html (mutually exclusive)
NAVIGATION_TIMEOUT Page took too long to load Increase timeout parameter or check URL accessibility
INVALID_URL URL format is invalid or unreachable Verify URL is accessible and properly formatted
INVALID_FORMAT Unsupported output format Use png, jpeg, or pdf

For authentication and billing errors, see the Errors section.

See Also:

HTML to PDF

Convert HTML content or URLs to PDF documents.

POST /api/v1/html-to-pdf

Request Body (application/json)

Field Type Required Default Description
html string No* - Raw HTML content to convert (required if url not provided)
url string No* - URL to convert to PDF (required if html not provided)
options object No - PDF generation options (see below)
delivery string No inline Output delivery mode: inline, url, or auto

* Either html or url is required (mutually exclusive)

Options Object

Field Type Default Description
format string A4 Paper size: A4, Letter, or Legal
landscape boolean false Page orientation
printBackground boolean true Include background graphics
margin object { top: "20px", right: "20px", bottom: "20px", left: "20px" } Page margins (CSS units)

Supported Paper Formats

FormatDimensionsUse Case
A4 210mm × 297mm International standard (most common)
Letter 8.5in × 11in US standard
Legal 8.5in × 14in US legal documents

Advanced Options

The following optional parameters provide fine-grained control over PDF generation. These are supported by the underlying Puppeteer library and can be included in the options object:

Parameter Type Default Description Validation
scale number 1.0 Zoom factor for webpage rendering Range: 0.1–2.0. Values >1 increase size, <1 decrease.
displayHeaderFooter boolean false Display header and footer on each page Requires headerTemplate or footerTemplate
headerTemplate string '' HTML template for page header Only applies when displayHeaderFooter: true
footerTemplate string '' HTML template for page footer Only applies when displayHeaderFooter: true
pageRanges string '' Paper ranges to print (e.g., "1-5, 8, 11-13") Empty string prints all pages
preferCSSPageSize boolean false Give CSS @page size priority over format Set true to honor CSS page size declarations
omitBackground boolean false Transparent background (hides default white) Useful for overlaying PDFs or transparent designs
timeout number 30000 Navigation timeout in milliseconds Min: 0 (no timeout), Max: 60000 (60s recommended)
waitUntil string networkidle0 When to consider navigation done Allowed: load, domcontentloaded, networkidle0, networkidle2

Advanced Example: PDF with custom header/footer and scale:

{
  "html": "<h1>Invoice #2026-001</h1>",
  "options": {
    "format": "A4",
    "scale": 0.8,
    "displayHeaderFooter": true,
    "headerTemplate": "<div style='font-size:10px; text-align:center; width:100%;'>Company Name</div>",
    "footerTemplate": "<div style='font-size:10px; text-align:center; width:100%;'>Page <span class='pageNumber'></span> of <span class='totalPages'></span></div>",
    "margin": { "top": "50px", "bottom": "50px", "left": "20px", "right": "20px" }
  }
}

Code Examples

const apiKey = process.env.PDFSTACK_API_KEY;

const res = await fetch("https://pdfstack.dev/api/v1/html-to-pdf", {
  method: "POST",
  headers: { "X-API-Key": apiKey, "Content-Type": "application/json" },
  body: JSON.stringify({
    html: "<h1>Hello PDFStack</h1><p>Invoice #2026-001</p>",
    options: { format: "A4", printBackground: true }
  })
});

const payload = await res.json();
if (!res.ok) throw new Error(`html-to-pdf failed: ${res.status} ${payload?.error?.code || "UNKNOWN"}`);
console.log(payload.data.file?.slice(0, 32));

Response Format

This endpoint returns a JSON response with the generated PDF encoded as base64:

{
  "success": true,
  "data": {
    "file": "data:application/pdf;base64,JVBERi0xLjQK...",
    "filename": "html_xxx.pdf",
    "format": "A4",
    "landscape": false,
    "size": 123456
  }
}

Decoding the file:

JavaScript example:

const base64Data = response.data.file.split(',')[1];
const buffer = Buffer.from(base64Data, 'base64');
fs.writeFileSync('output.pdf', buffer);

File size limits: Maximum response size is approximately 4MB due to JSON payload limits. For very large HTML documents, consider splitting into multiple requests or using external assets via URLs.

Limitations

  • CSS complexity: Complex CSS layouts (flexbox, grid, complex floats) may not render perfectly
  • External resources: Images, fonts, and other assets must be accessible (CORS restrictions apply)
  • JavaScript: Execution limited to page load; no async operations or dynamic content after render
  • HTML size: Maximum HTML input size is 1MB
  • Timeout: Navigation timeout is 30 seconds by default (configurable up to 60s)
  • File size: Large HTML documents may exceed 4MB response limit

Common Errors

Error CodeCauseSolution
MISSING_INPUT Neither html nor url provided Provide either html or url (mutually exclusive)
NAVIGATION_TIMEOUT Page took too long to render Increase timeout parameter or simplify HTML content
INVALID_URL URL format is invalid or unreachable Verify URL is accessible and properly formatted
HTML_TOO_LARGE HTML input exceeds 1MB limit Reduce HTML size or use URL-based conversion
INVALID_OPTIONS Invalid PDF generation options Check options object format and parameter values

For authentication and billing errors, see the Errors section.

See Also: