PDFPipe

Billing and receivables / A4

Proforma invoice HTML template

A document shaped like an invoice that is deliberately not one: it commits nobody to pay and exists so the buyer can raise an order, open a credit, or clear an import.

When this document is the right one

A buyer needs a formal price in writing before a sale exists. Common before an export, before a letter of credit, or where a purchasing process requires a document with a number on it before a purchase order can be raised.

Why each part is there

The fields are visible in the markup. What is not visible is why they are present, which is the part that gets removed first when someone adapts a template for their own use.

  • A banner saying this is not a tax invoice, first and unmissable. Everything else on the page follows from that one statement.
  • A validity date, because a price with no expiry is a price you are still holding a year later.
  • The same line detail as a real invoice, so the buyer's system can consume it, with an estimated total rather than an amount due.
  • Conditions that name what could still change: quantity tolerance, material cost, lead time.
  • A signature area, because the usual next step is that this document comes back signed and becomes a purchase order.

The template

A complete file. Doctype, stylesheet, body: paste it into a renderer unchanged and it produces a finished A4 page. Replace the sample data and the styling holds.

html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Proforma invoice PF-2026-0330</title>
<style>
  @page { size: A4; margin: 18mm 16mm; }
  * { box-sizing: border-box; }
  body { margin: 0; font: 10pt/1.5 Georgia, "Times New Roman", serif; color: #1a1a1a; }

  /* The banner is the entire reason this document is not an invoice. Anyone
     who files it as one has a tax problem, so it is stated first and loudly. */
  .not-a-tax-invoice { border: 2px solid #1a1a1a; padding: 3mm 4mm; text-align: center;
                       font: 700 9pt/1.4 Arial, sans-serif; letter-spacing: 0.08em;
                       text-transform: uppercase; }

  header { margin-top: 8mm; display: flex; justify-content: space-between;
           align-items: baseline; }
  h1 { margin: 0; font-size: 19pt; font-weight: 400; }
  .ref { text-align: right; font: 9pt/1.5 Arial, sans-serif; }

  .intro { margin: 8mm 0; }
  .parties { display: grid; grid-template-columns: 1fr 1fr; gap: 10mm; margin-bottom: 8mm; }
  .parties h2 { margin: 0 0 2mm; font: 700 8pt/1 Arial, sans-serif;
                letter-spacing: 0.08em; text-transform: uppercase; color: #555; }
  address { font-style: normal; }

  table { width: 100%; border-collapse: collapse; }
  thead { display: table-header-group; }
  th { text-align: left; font: 700 8pt/1 Arial, sans-serif; letter-spacing: 0.06em;
       text-transform: uppercase; color: #555; border-bottom: 1.5px solid #1a1a1a;
       padding-bottom: 2mm; }
  td { padding: 3mm 0; border-bottom: 1px solid #ddd; vertical-align: top; }
  tr { break-inside: avoid; }
  .num { text-align: right; font-variant-numeric: tabular-nums; }

  .totals { width: 80mm; margin: 6mm 0 0 auto; break-inside: avoid; }
  .totals div { display: flex; justify-content: space-between; padding: 1.5mm 0; }
  .totals .grand { border-top: 1.5px solid #1a1a1a; margin-top: 2mm; padding-top: 2.5mm;
                   font-size: 12pt; font-weight: 700; }

  .validity { margin-top: 10mm; break-inside: avoid; }
  .validity h2 { font: 700 9pt/1 Arial, sans-serif; margin: 0 0 2mm; }
  .validity ul { margin: 0; padding-left: 5mm; }
  .validity li { margin-bottom: 1.5mm; }

  .accept { margin-top: 12mm; border-top: 1px solid #ddd; padding-top: 6mm;
            display: grid; grid-template-columns: 1fr 1fr; gap: 12mm;
            break-inside: avoid; }
  .accept div { border-bottom: 1px solid #1a1a1a; height: 16mm; position: relative; }
  .accept span { position: absolute; bottom: -6mm; font: 8pt Arial, sans-serif; color: #555; }
</style>
</head>
<body>
  <p class="not-a-tax-invoice">
    Proforma invoice &middot; this is not a tax invoice and no payment is due against it
  </p>

  <header>
    <h1>Harbour &amp; Vane</h1>
    <div class="ref">
      PF-2026-0330<br>Issued 14 May 2026<br>Valid until 13 June 2026
    </div>
  </header>

  <p class="intro">
    Prepared at your request for import documentation and internal approval. A tax
    invoice with the same reference will be issued on despatch, and it is that
    document, not this one, that carries a payment obligation.
  </p>

  <section class="parties">
    <div>
      <h2>From</h2>
      <address>Harbour &amp; Vane Ltd<br>3 Quayside, Falmouth TR11 3AA<br>United Kingdom</address>
    </div>
    <div>
      <h2>Prepared for</h2>
      <address>Sagres Comercio Lda<br>Rua do Alecrim 88<br>1200-018 Lisboa, Portugal</address>
    </div>
  </section>

  <table>
    <thead>
      <tr><th>Item</th><th class="num">Qty</th><th class="num">Unit</th><th class="num">Amount</th></tr>
    </thead>
    <tbody>
      <tr><td>Cast bronze cleat, 200mm, polished</td><td class="num">40</td>
          <td class="num">62.00</td><td class="num">2,480.00</td></tr>
      <tr><td>Bronze fairlead, 150mm</td><td class="num">25</td>
          <td class="num">48.50</td><td class="num">1,212.50</td></tr>
      <tr><td>Export crating and palletisation</td><td class="num">1</td>
          <td class="num">180.00</td><td class="num">180.00</td></tr>
    </tbody>
  </table>

  <div class="totals">
    <div><span>Estimated goods value</span><span>3,872.50</span></div>
    <div><span>VAT (zero rated, export)</span><span>0.00</span></div>
    <div class="grand"><span>Estimated total</span><span>GBP 3,872.50</span></div>
  </div>

  <section class="validity">
    <h2>Conditions</h2>
    <ul>
      <li>Prices hold until 13 June 2026 and are subject to metal cost at the date of order.</li>
      <li>Lead time is six weeks from receipt of a confirmed purchase order.</li>
      <li>Quantities may vary by up to 3% on a cast production run; the invoice will follow the quantity actually shipped.</li>
      <li>Incoterms 2020: FCA Falmouth.</li>
    </ul>
  </section>

  <div class="accept">
    <div><span>Authorised signature</span></div>
    <div><span>Date and purchase order number</span></div>
  </div>
</body>
</html>

The layout decision worth understanding

The disclaimer is set as a bordered band at the very top rather than as small print at the bottom. A proforma filed as a payable is a real accounting problem for the recipient, and the placement is the only defence the document has against being skimmed.

The mistake people make adapting it

Numbering proformas in the same sequence as invoices. The sequences then interleave, the invoice sequence has gaps in it, and in several jurisdictions an invoice sequence with gaps is itself a compliance problem.

Rendering it

The page box is declared in the template's own CSS as A4, so the size travels with the markup rather than living in the code that calls the renderer. A4 is also one of the six named formats the API accepts, so it can be passed in the request options instead if that suits your setup better.

bash
curl -X POST https://api.pdfpipe.xyz/v1/pdf \
  -H "Authorization: Bearer $PDFPIPE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<!doctype html>...",
    "options": { "format": "A4" }
  }' \
  --output proforma-invoice.pdf

Frequently asked

Can I use this template commercially?

Yes. Copy it, change it, ship it. It is sample markup written to be taken, and the sample data in it is invented, so replace the names and the numbers before anyone sees it.

Why is the page size in the CSS rather than in the API call?

Because a proforma invoice is a A4 document, and that is a property of the document rather than of the code that renders it. Declaring it in the page box means the size cannot be lost between the template and the call, which is the usual way a document ends up on the wrong paper.

Will it look the same in every renderer?

The layout will, because it uses ordinary CSS. The page break behaviour will not: break-inside and break-after are implemented differently by browser engines and by dedicated print engines, and some of the paged media specification is not implemented in browser renders at all. That difference is documented per property in the paged CSS reference.

Other templates

Documents from the same part of a business, and one from each of the other groups.

Paste the template into the playground and get the PDF back. No signup, no key.