Skip to main content
PDF tools

Every PDF tool.
Online & free.

Convert, merge, compress, split, sign and edit PDFs right in your browser. No install, no sign-up.

40+ tools that work on any device.

Trusted by 1,400+ happy customers

Works where you already build

For developers

Designed for developers.

Real, runnable samples straight from our open-source examples. Pick an endpoint and a language,
copy the whole file, and run it. That is the whole API.

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

/**
 * Document to PDF Converter using PDF4Me API
 * Converts various document formats (DOCX, XLSX, etc.) to PDF documents
 * Supports both synchronous and asynchronous processing with retry logic
 */

// API Configuration - PDF4Me service for converting documents to PDF
const API_KEY = "get the API key from https://dev.pdf4me.com/dashboard/#/api-keys/";
const BASE_URL = "https://api.pdf4me.com/";
const API_ENDPOINT = `${BASE_URL}api/v2/ConvertToPdf`;

// File paths configuration
const INPUT_DOC_PATH = "sample.docx";           // Path to input document file
const OUTPUT_PDF_PATH = "Document_to_PDF_output.pdf"; // Output PDF file name

// Retry configuration for async processing
const MAX_RETRIES = 10;
const RETRY_DELAY = 10000; // 10 seconds in milliseconds

/**
 * Main function that orchestrates the document to PDF conversion process
 * Handles file validation, conversion, and result processing
 */
async function convertDocumentToPdf() {
    console.log("Starting Document to PDF Conversion Process...");
    console.log("This converts various document formats (DOCX, XLSX, etc.) to PDF");
    console.log("Supports Word documents, Excel spreadsheets, and other formats");
    console.log("-".repeat(60));

    try {
        // Validate input file exists
        if (!fs.existsSync(INPUT_DOC_PATH)) {
            throw new Error(`Input document file not found: ${INPUT_DOC_PATH}`);
        }

        console.log(`Converting: ${INPUT_DOC_PATH} → ${OUTPUT_PDF_PATH}`);

        // Process the conversion
        const result = await processDocumentToPdfConversion();

        // Handle the result
        await handleConversionResult(result);

    } catch (error) {
        console.error("Conversion failed:", error.message);
        process.exit(1);
    }
}

/**
 * Core conversion logic - handles the API request and response processing
 * Supports both synchronous (200) and asynchronous (202) responses
 */
async function processDocumentToPdfConversion() {
    // Read and encode document file to base64
    console.log("Reading and encoding document file...");
    const docContent = fs.readFileSync(INPUT_DOC_PATH);
    const docBase64 = docContent.toString('base64');
    console.log("Document file successfully encoded to base64");

    // Prepare the conversion payload
    const payload = {
        docContent: docBase64,           // Base64 encoded document content
        docName: "output",               // Name for the output file
        async: true                      // Enable asynchronous processing
    };

    // Set up HTTP headers for authentication and content type
    const headers = {
        "Authorization": `Basic ${API_KEY}`,
        "Content-Type": "application/json"
    };

    console.log("Sending request to PDF4Me API...");

    // Make the initial API request
    const response = await fetch(API_ENDPOINT, {
        method: 'POST',
        headers: headers,
        body: JSON.stringify(payload)
    });

    console.log(`Status code: ${response.status}`);

    // Handle different response scenarios
    if (response.status === 202) {
        // Asynchronous processing - poll for completion
        console.log("Request accepted. PDF4Me is processing asynchronously...");
        
        const locationUrl = response.headers.get('Location');
        if (!locationUrl) {
            throw new Error("No 'Location' header found in the response for polling");
        }

        return await pollForCompletion(locationUrl, headers);

    } else if (response.status === 200) {
        // Synchronous processing - immediate result
        console.log("Document to PDF conversion completed immediately!");
        return await response.arrayBuffer();

    } else {
        // Error response
        const errorText = await response.text();
        throw new Error(`API request failed. Status: ${response.status}, Response: ${errorText}`);
    }
}

/**
 * Handles the conversion result and saves the PDF file
 * Supports both binary PDF data and base64 encoded responses
 */
async function handleConversionResult(result) {
    try {
        // Convert ArrayBuffer to Buffer for file operations
        const buffer = Buffer.from(result);
        
        // Validate that we have a PDF (check for PDF header)
        if (buffer.length > 4 && buffer.toString('ascii', 0, 4) === '%PDF') {
            console.log("Response is a valid PDF file");
            fs.writeFileSync(OUTPUT_PDF_PATH, buffer);
            console.log(`PDF saved successfully to: ${OUTPUT_PDF_PATH}`);
            console.log("Document has been converted to PDF format");
            return;
        }

        // Try to parse as JSON if not a direct PDF
        try {
            const jsonResponse = JSON.parse(buffer.toString());
            console.log("Successfully parsed JSON response");
            
            // Look for PDF data in different possible JSON locations
            let pdfBase64 = null;
            if (jsonResponse.document && jsonResponse.document.docData) {
                pdfBase64 = jsonResponse.document.docData;  // Common location 1
            } else if (jsonResponse.docData) {
                pdfBase64 = jsonResponse.docData;           // Common location 2
            } else if (jsonResponse.data) {
                pdfBase64 = jsonResponse.data;              // Alternative location
            }

            if (pdfBase64) {
                // Decode base64 PDF data and save to file
                const pdfBytes = Buffer.from(pdfBase64, 'base64');
                fs.writeFileSync(OUTPUT_PDF_PATH, pdfBytes);
                console.log(`PDF saved to ${OUTPUT_PDF_PATH}`);
                console.log("Document has been converted to PDF format");
            } else {
                console.log("No PDF data found in the response.");
                console.log("Full response:", JSON.stringify(jsonResponse, null, 2));
            }

        } catch (jsonError) {
            console.log("Failed to parse JSON response, treating as binary data");
            // If JSON parsing fails, try to save as binary anyway
            if (buffer.length > 1000) {
                fs.writeFileSync(OUTPUT_PDF_PATH, buffer);
                console.log(`PDF saved to ${OUTPUT_PDF_PATH} (as binary data)`);
                console.log("Document has been converted to PDF format");
            } else {
                console.log("Warning: Response doesn't appear to be a valid PDF");
                console.log(`First 100 bytes: ${buffer.toString('hex', 0, 100)}`);
            }
        }

    } catch (error) {
        throw new Error(`Error saving PDF: ${error.message}`);
    }
}

/**
 * Polls the API for async completion with retry logic
 * Handles 202 (processing) and 200 (completed) status codes
 */
async function pollForCompletion(locationUrl, headers) {
    console.log(`Polling URL: ${locationUrl}`);

    for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
        console.log(`Waiting for result... (Attempt ${attempt}/${MAX_RETRIES})`);
        
        // Wait before polling (except on first attempt)
        if (attempt > 1) {
            await new Promise(resolve => setTimeout(resolve, RETRY_DELAY));
        }

        try {
            const response = await fetch(locationUrl, {
                method: 'GET',
                headers: headers
            });

            if (response.status === 200) {
                // Conversion completed successfully
                console.log("Document to PDF conversion completed successfully!");
                return await response.arrayBuffer();

            } else if (response.status === 202) {
                // Still processing, continue polling
                console.log("Still processing...");
                continue;

            } else {
                // Error occurred during processing
                const errorText = await response.text();
                throw new Error(`Unexpected error during polling: ${response.status}, Response: ${errorText}`);
            }

        } catch (error) {
            if (attempt === MAX_RETRIES) {
                throw new Error(`Polling failed after ${MAX_RETRIES} attempts: ${error.message}`);
            }
            console.log(`Polling attempt ${attempt} failed: ${error.message}`);
        }
    }

    throw new Error(`Timeout: Document to PDF conversion did not complete after ${MAX_RETRIES} retries`);
}

// Main execution - Run the conversion when script is executed directly
if (require.main === module) {
    convertDocumentToPdf().catch(error => {
        console.error("Fatal error:", error.message);
        process.exit(1);
    });
}

module.exports = { convertDocumentToPdf, processDocumentToPdfConversion, handleConversionResult }; 
  • 100API endpoints
  • 15API categories
  • 4No-code platforms
  • 30+Free online tools
  • 4Extensions
For developers

From a single click
to a million API calls.

AI data extraction

Turn invoices and forms into clean data.

Point PDF4me at an invoice, receipt, bank statement or contract and get structured JSON back, ready to drop into your systems. No templates to maintain for these document types.

  • Ready-made parsers for invoices, receipts, bank statements, pay stubs, contracts and more
  • Fields like vendor, line items, totals, dates and tax, returned as JSON
  • Native actions in Power Automate, Make and n8n, plus the same engine on the REST API
Explore AI data extraction
Document generation

Generate documents from templates and data.

Merge Word or HTML templates with your JSON to produce PDF or Word files, one at a time or in bulk.

  • Word (.docx) and HTML templates with variables, tables and images
  • Single or bulk generation from JSON data records
  • The same generation actions on the REST API, Power Automate, Make, n8n and Zapier
Explore document generation
E-invoicing

Ship ZUGFeRD e-invoices in one call.

Generate ZUGFeRD hybrid e-invoices, one PDF/A-3 file with the invoice XML embedded, ready for Germany's B2B mandate and any EN 16931 ERP.

  • Hybrid PDF/A-3 + XML, EN 16931 and Factur-X aligned
  • BASIC, COMFORT and EXTENDED conformance, from XML, JSON or CSV data
  • Native actions in Power Automate, Make, n8n and Zapier, plus the REST API
Explore ZUGFeRD invoicing
Parse & classify

Build a parser for any document.

Define your own field schema and extract exactly what you need, or let PDF4me classify mixed batches automatically and route each document by its type.

  • Parse to your own JSON schema, or auto-classify by document type
  • Custom analyzer templates, built in the developer dashboard
  • Confidence scores to route mixed document batches
Explore parse & classify
Word & Excel automation

Automate Word and Excel at scale.

Convert Word and Excel to PDF and back, then merge, split, watermark and password-protect Office files, all from one API with no Office install required.

  • Word to PDF, Excel to PDF, and PDF back to Word or Excel
  • Merge, split and compare Word files; add, update and extract Excel rows
  • Watermark and password-protect Word and Excel files
Explore Word & Excel
Barcodes

Read, create and split by barcode.

Generate and embed QR, Code 128, Data Matrix and 50+ barcode types, read them back from PDFs and images, or split document batches on barcode separators.

  • Create and embed 50+ barcode types, including QR and Data Matrix
  • Read barcodes and Swiss QR codes from PDFs and images
  • Swiss QR and EPC/SEPA bills, plus split PDF by barcode
Explore barcodes
Trust & security

Your documents are in safe hands.

Privacy and security are built in, not bolted on. Swiss-owned PDF4me applies the same data-handling rules whether you convert one file in the browser or process millions through the API.

Files deleted after processing

Uploads are encrypted at rest on isolated cloud storage, then removed automatically within one hour on online tools, or within minutes once an API job completes. Share links expire after 14 days. We only keep what you explicitly save to My Docs.

Never used to train AI

Your document contents are never retained for model training, ours or anyone else's. AI extraction runs on schema you define at request time only. We do not mine, analyse, or resell the files you send us.

Data Processing Agreement

Need a DPA for procurement or GDPR reviews? Download the PDF4me agreement plus the processing and security annexes. Share them with legal without waiting on a sales thread.

Encrypted end to end

Every browser upload, API call, and download travels over HTTPS/TLS. While a file is held for processing it stays encrypted at rest, tenant-isolated, and kept in memory only for the duration of the job.

ISO 27001 underwayIn progress

We are implementing a formal ISO/IEC 27001 information-security management system: documented policies, role-based access, change control, incident response, and supplier oversight, with an independent audit targeted for 2026.

Built for production

One platform for everyday PDF tools and a production REST API with SDKs, automation connectors (Make, Zapier, Power Automate, n8n), and MCP. Ship document features in your product without building a PDF stack in-house.

PDF tools

Every PDF tool, one click away.

Convert, edit, merge, compress, sign and OCR, free in your browser. No install, no sign-up.

Browse all 33 tools Every tool here is also an API.
Pricing

Pay only for what you process.

Start free with the API, then top up with prepaid packs that never expire. One-time payment, no lock-in, and every pack stacks on a monthly plan.

For trying it out
$25one-time

500 API calls

About $0.050 per call. Credits never expire.

  • One-time payment
  • Stacks on any plan
  • 1 call per document
Get 500 pack
For small projects
$45one-time

1,000 API calls

About $0.045 per call. Credits never expire.

  • One-time payment
  • Stacks on any plan
  • 1 call per document
Get 1,000 pack
For light automation
$95one-time

2,500 API calls

About $0.038 per call. Credits never expire.

  • One-time payment
  • Stacks on any plan
  • 1 call per document
Get 2,500 pack
For scaling teams
$330one-time

10,000 API calls

About $0.033 per call. Credits never expire.

  • One-time payment
  • Stacks on any plan
  • 1 call per document
Get 10,000 pack
For high volume
$650one-time

25,000 API calls

About $0.026 per call. Credits never expire.

  • One-time payment
  • Stacks on any plan
  • 1 call per document
Get 25,000 pack
For high volume
Customcontact sales

25,000+ API calls

Need more than our largest prepaid pack? Contact sales for custom volume pricing, billing terms, and dedicated support.

  • Volume discounts available
  • Dedicated account support
  • Flexible billing terms
Talk to sales

One API call per document. High-quality conversions, OCR and AI features count as one call per page. Need a monthly plan or the free tier? It is all on the full pricing page.

See full pricing and API call costs

Get your documents done.

Build it into your product with the API, automate it with no code, or use the free tools in your browser. No credit card to begin.

Start with a single callcurl -X POST https://api.pdf4me.com/v1/ConvertToPdf

Free tier · No credit card required