March 26, 2026

How to Automate Invoice PDF Generation with a REST API

invoicesautomationREST APItutorial

Still creating invoices manually in Excel? Copying data between spreadsheets and praying you didn't mistype an amount? There's a better way.

With a PDF generation API, you can turn invoice data into professionally formatted PDFs — and email them to customers — with a single API call. This guide walks you through the implementation with real code examples.

Why Automate with an API?

The Manual Process Problem

  • Slow: Create in Excel → export to PDF → attach to email → send
  • Error-prone: Manual data entry leads to typos in amounts and addresses
  • Doesn't scale: 10 invoices per month is fine. 1,000 is a nightmare.

The API Approach

  • Seconds, not hours: Generate from database values instantly
  • Zero errors: Code handles calculations and formatting
  • Scales infinitely: Same code handles 10 or 10,000 invoices

Architecture Overview

Order data → HTML template → PDF Generation API → Email delivery

You need three things:

  1. An HTML template — the invoice layout
  2. Data — customer name, line items, amounts
  3. One API call — generates the PDF and sends the email

Step 1: Create an HTML Template

Create an invoice template using HTML and CSS. With FUNBREW PDF's template engine, use {{variable_name}} placeholders for dynamic values.

<div style="font-family: -apple-system, sans-serif; max-width: 800px; margin: 0 auto; padding: 40px;">
  <div style="display: flex; justify-content: space-between; margin-bottom: 40px;">
    <div>
      <h1 style="font-size: 28px; margin: 0;">Invoice</h1>
      <p style="color: #6b7280;">Invoice #: {{invoice_number}}</p>
      <p style="color: #6b7280;">Date: {{issue_date}}</p>
    </div>
    <div style="text-align: right;">
      <p style="font-weight: 700;">Your Company Inc.</p>
      <p style="color: #6b7280; font-size: 13px;">123 Business St, Suite 100</p>
    </div>
  </div>

  <div style="margin-bottom: 32px;">
    <p style="font-size: 18px; font-weight: 700;">Bill to: {{customer_name}}</p>
  </div>

  <table style="width: 100%; border-collapse: collapse; margin-bottom: 32px;">
    <thead>
      <tr style="background: #f8fafc;">
        <th style="text-align: left; padding: 12px; border-bottom: 2px solid #e5e7eb;">Item</th>
        <th style="text-align: right; padding: 12px; border-bottom: 2px solid #e5e7eb;">Qty</th>
        <th style="text-align: right; padding: 12px; border-bottom: 2px solid #e5e7eb;">Price</th>
        <th style="text-align: right; padding: 12px; border-bottom: 2px solid #e5e7eb;">Total</th>
      </tr>
    </thead>
    <tbody>{{line_items}}</tbody>
  </table>

  <div style="text-align: right; margin-bottom: 32px;">
    <p>Subtotal: ${{subtotal}}</p>
    <p>Tax: ${{tax}}</p>
    <p style="font-size: 20px; font-weight: 700;">Total: ${{total}}</p>
  </div>

  <div style="border-top: 1px solid #e5e7eb; padding-top: 16px; color: #9ca3af; font-size: 12px;">
    <p>Due date: {{due_date}}</p>
    <p>Payment: Wire transfer to Account #1234567</p>
  </div>
</div>

Register this template in the FUNBREW PDF dashboard.

Step 2: Generate an Invoice PDF via API

JavaScript (Node.js)

const response = await fetch("https://pdf.funbrew.cloud/api/pdf/generate-from-template", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sk-your-api-key",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    template: "invoice",
    variables: {
      invoice_number: "INV-2026-0042",
      issue_date: "March 26, 2026",
      customer_name: "Acme Corp",
      line_items: buildLineItemsHtml(items),
      subtotal: "1,500.00",
      tax: "150.00",
      total: "1,650.00",
      due_date: "April 30, 2026",
    },
    email: {
      to: "billing@acme.com",
      subject: "Invoice INV-2026-0042 from Your Company",
    },
    options: { engine: "quality" },
  }),
});

const result = await response.json();
console.log("PDF URL:", result.data.download_url);

Python

import requests

response = requests.post(
    "https://pdf.funbrew.cloud/api/pdf/generate-from-template",
    headers={"Authorization": "Bearer sk-your-api-key"},
    json={
        "template": "invoice",
        "variables": {
            "invoice_number": "INV-2026-0042",
            "issue_date": "March 26, 2026",
            "customer_name": "Acme Corp",
            "line_items": build_line_items_html(items),
            "subtotal": "1,500.00",
            "tax": "150.00",
            "total": "1,650.00",
            "due_date": "April 30, 2026",
        },
        "email": {
            "to": "billing@acme.com",
            "subject": "Invoice INV-2026-0042 from Your Company",
        },
        "options": {"engine": "quality"},
    },
)

print("PDF URL:", response.json()["data"]["download_url"])

PHP (Laravel)

$response = Http::withToken('sk-your-api-key')
    ->post('https://pdf.funbrew.cloud/api/pdf/generate-from-template', [
        'template' => 'invoice',
        'variables' => [
            'invoice_number' => 'INV-2026-0042',
            'issue_date' => 'March 26, 2026',
            'customer_name' => 'Acme Corp',
            'line_items' => $this->buildLineItemsHtml($items),
            'subtotal' => '1,500.00',
            'tax' => '150.00',
            'total' => '1,650.00',
            'due_date' => 'April 30, 2026',
        ],
        'email' => [
            'to' => 'billing@acme.com',
            'subject' => 'Invoice INV-2026-0042 from Your Company',
        ],
        'options' => ['engine' => 'quality'],
    ]);

$downloadUrl = $response->json('data.download_url');

Step 3: Tax Calculation Logic

Accurate tax calculation is essential for invoice automation. Here's a pattern for handling multiple tax rates and rounding correctly.

Multi-Rate Tax Calculation

function calculateInvoice(items) {
  // Group by tax rate
  const grouped = {};
  for (const item of items) {
    const rate = item.taxRate || 10;
    if (!grouped[rate]) grouped[rate] = [];
    grouped[rate].push(item);
  }

  let grandTotal = 0;
  const breakdown = [];

  for (const [rate, groupItems] of Object.entries(grouped)) {
    const subtotal = groupItems.reduce((sum, i) => sum + i.price * i.qty, 0);
    const tax = Math.floor(subtotal * (rate / 100)); // Round down per rate
    grandTotal += subtotal + tax;
    breakdown.push({ rate: Number(rate), subtotal, tax });
  }

  return { breakdown, grandTotal };
}

Template Integration

<div style="margin-top: 24px; border-top: 1px solid #e5e7eb; padding-top: 16px;">
  <table style="width: 100%; margin-top: 8px;">
    <tr>
      <td>Subtotal (10% tax)</td>
      <td style="text-align: right;">${{standard_subtotal}}</td>
    </tr>
    <tr>
      <td>Tax (10%)</td>
      <td style="text-align: right;">${{standard_tax}}</td>
    </tr>
  </table>
</div>

Always apply rounding once per tax rate per invoice, not per line item. Rounding per line item can cause discrepancies between the sum of line totals and the invoice total.

Step 4: Schedule Monthly Invoice Runs

Automate your billing cycle with cron jobs or task schedulers instead of running batch processing manually.

Node.js (node-cron)

const cron = require('node-cron');

// Run on the last day of each month at 9:00 AM
cron.schedule('0 9 28-31 * *', async () => {
  const today = new Date();
  const lastDay = new Date(today.getFullYear(), today.getMonth() + 1, 0).getDate();
  if (today.getDate() !== lastDay) return;

  const customers = await fetchBillableCustomers();
  const result = await generateInvoiceBatch(customers);
  console.log(`Done: ${result.success} succeeded, ${result.failed} failed`);
});

GitHub Actions

name: Monthly Invoice Generation
on:
  schedule:
    - cron: '0 0 28 * *'
jobs:
  generate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: node scripts/generate-invoices.js
        env:
          FUNBREW_PDF_API_KEY: ${{ secrets.FUNBREW_PDF_API_KEY }}

Step 5: Batch Processing for Monthly Billing

For end-of-month billing runs, use the batch API to generate all invoices at once. For advanced patterns, see the PDF API Batch Processing Guide.

const response = await fetch("https://pdf.funbrew.cloud/api/pdf/batch", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sk-your-api-key",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    items: customers.map(c => ({
      type: "template",
      template: "invoice",
      variables: buildInvoiceVars(c),
      filename: `invoice-${c.id}-202603.pdf`,
      email: {
        to: c.email,
        subject: `Invoice for ${c.name} - March 2026`,
      },
    })),
  }),
});

const { data } = await response.json();
console.log(`Generated ${data.results.length} invoices`);

Get Notified with Webhooks

Want a Slack notification when invoices are generated? Set up a webhook URL in the dashboard. You'll receive a POST request like this:

{
  "event": "pdf.generated",
  "data": {
    "filename": "invoice-42-202603.pdf",
    "file_size": 48210,
    "download_url": "https://pdf.funbrew.cloud/dl/abc123..."
  }
}

Frequently Asked Questions

How do I manage templates?

Create and edit templates in the FUNBREW PDF dashboard using HTML and CSS. Use {{variable_name}} placeholders for dynamic values. For advanced techniques like loops and conditionals, see the PDF Template Engine Guide.

Does it support CJK fonts?

Yes. Noto Sans JP and other CJK fonts are pre-installed — no additional configuration needed. See our HTML to PDF API comparison for how this compares to other tools.

Is it secure for financial documents?

Invoices contain sensitive business data. FUNBREW PDF uses SSL/TLS encryption, API key authentication, and automatic file expiration to keep your data safe.

What's the typical file size of an invoice PDF?

A standard invoice (text and tables, no images) is typically 30–80 KB. With a company logo, expect 100–200 KB. Well within email attachment limits.

Can I integrate with accounting software?

Yes. Since it's API-based, you can use exported data from QuickBooks, Xero, FreshBooks, or any accounting system. Read the CSV or JSON export, map fields to template variables, and generate PDFs.

Error Handling and Retry

Batch processing at month-end may encounter transient failures. Implement retry logic with exponential backoff.

async function generateWithRetry(customer, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await generateInvoice(customer);
    } catch (error) {
      if (attempt === maxRetries) throw error;
      const delay = error.status === 429 ? 5000 * attempt : 1000 * attempt;
      await new Promise(r => setTimeout(r, delay));
    }
  }
}

For comprehensive error handling patterns, see the PDF API Error Handling Guide.

Summary

Automating invoice PDF generation with an API eliminates manual work and errors:

  1. Create a template once, reuse forever
  2. One API call = PDF + email delivery
  3. Batch API for monthly billing runs
  4. Webhooks for completion notifications

Get started with the free plan (30 PDFs/month). Build your invoice template in the editor and test it in the Playground.

Related

Powered by FUNBREW PDF