Vendure PDF Invoices plugin

Delight your customers with beautiful customizable PDF invoices with this Vendure plugin.

Made by a Vendure Silver Partner!
You might be applicable for a free license if you are already using this plugin! Contact us at

99 /year



  • Send beautiful PDF invoices to your customers
  • Easily customize your invoice with HTML per channel
  • Store invoices on Google Cloud Storage, Amazon S3 or implement your own storage
  • Incremental invoice numbers
  • Customize invoice numbering to your own liking


yarn install vendure-plugin-invoices
  1. Add the following config to your vendure-config.ts:
plugins: [
     * This plugins requires a license for commercial use.
     * Visit
     * for more information
    licenseKey: processs.env.LICENSE,
    // Used for generating download URLS for the admin ui
    vendureHost: 'http://localhost:3106',
  // Add the invoices page to the admin ui
    port: 3002,
    route: 'admin',
    app: compileUiExtensions({
      outputPath: path.join(__dirname, '__admin-ui'),
      extensions: [InvoicePlugin.ui],
  1. Run a migration, to add the Invoice and InvoiceConfig entities to the database.
  2. Start Vendure and login to the admin dashboard
  3. Make sure you have the permission AllowInvoicesPermission
  4. Go to Sales > Invoices.
  5. Unfold the Settings accordion.
  6. Check the checkbox to Enable invoice generation for the current channel on order placement.
  7. A default HTML template is set for you. Click the Preview button to view a sample PDF invoice.

If you are using Docker with node:16 or higher as base, you need to add this to your Dockerfile:

# PhantomJS fix

Adding invoices to your order-confirmation email

Add the following link to your email template:

https://<your server>/invoices/e2e-default-channel/C7YH7WME4LTQNFRZ?

When the customer clicks the link, the server will check if the ordercode, channelCode and customer emailaddress match with the requested order. If so, it will return the invoice.

Google Storage strategy

This plugin also includes a strategy for storing invoices in Google Storage:

yarn add @google-cloud/storage

// In vendure-config.ts
  vendureHost: 'http://localhost:3050',
  storageStrategy: new GoogleStorageInvoiceStrategy({
    bucketName: 'bucketname',

The strategy will use the projectId and credentials in from your environment, which is useful for Google Cloud Run or Cloud Functions.

However, if you want to run it locally or on a custom environment, you need to pass a keyFile to the plugin. This is needed to generate signedUrls, which are used to give customers temporary access to a file on Storage. More info about locally using signedUrls:

import {
} from 'vendure-plugin-invoices';

  vendureHost: 'http://localhost:3050',
  storageStrategy: new GoogleStorageInvoiceStrategy({
    bucketName: 'bucketname',
    storageOptions: {
      keyFilename: 'key.json',

Amazon S3 Storage strategy

This plugin also includes a strategy for storing invoices on Amazon S3.

yarn add aws-sdk

import { InvoicePlugin, S3StorageStrategy } from 'vendure-plugin-invoices';

  vendureHost: 'http://localhost:3050',
  storageStrategy: new S3StorageStrategy({
    expiresInSeconds: 360,
     * Config here will be passed directly to `new AWS.S3()`
     * See for more info

Custom file storage

Implement your own strategy for storing invoices by implementing one of these interfaces:

Remote storage strategy

RemoteStorageStrategy for storing PDF files on an external platform like Google Cloud or S3. It redirects the user to a public/authorized URL for the user to download the invoice PDF.

import { RemoteStorageStrategy, zipFiles } from 'vendure-plugin-invoices';

export class YourRemoteStrategy implements RemoteStorageStrategy {
  async save(
    tmpFile: string,
    invoiceNumber: number,
    channelToken: string
  ): Promise<string> {
    // Save the invoice in your favorite cloud storage. The string you return will be saved as unique reference to your invoice.
    // You should be able to retrieve the file later with just the unique reference
    return 'unique-reference';

  async getPublicUrl(invoice: InvoiceEntity): Promise<string> {
    // Most cloud based storages have the ability to generate a signed URL, which is available for X amount of time.
    // This way the downloading of invoices does not go through the vendure service
    return 'https://your-signed-url/invoice.pdf';

  async streamMultiple(
    invoices: InvoiceEntity[],
    res: Response
  ): Promise<ReadStream> {
    // zip files and return stream
    const zipped = zipFiles(files);
    return createReadStream(zipped);

Local file storage

LocalFileStrategy streams the invoice through the Vendure service to the user.

import { LocalStorageStrategy, zipFiles } from 'vendure-plugin-invoices';

export class YourLocalStrategy implements LocalStorageStrategy {
  async save(tmpFile: string, invoiceNumber: number, channelToken: string) {
    // save the tmpFile somewhere
    return 'new/path.pdf';

  async streamMultiple(
    invoices: InvoiceEntity[],
    res: Response
  ): Promise<ReadStream> {
    // make a zip of your files
    const zipFile = await zipFiles(files);
    return createReadStream(zipFile);

  async streamFile(invoice: InvoiceEntity, res: Response): Promise<ReadStream> {
    // stream a single PDF to the user
    return createReadStream(invoice.storageReference);

Custom invoice numbering and custom data

Implement the DataStrategy to pass custom data to your template or generate custom invoice numbers:

export class DefaultDataStrategy implements DataStrategy {
  async getData({
  }: DataFnInput): Promise<InvoiceData> {
    // Do something with the data
    return {
      invoiceNumber: String(Math.floor(Math.random() * 90000) + 10000),
      customerEmail: 'just used for admin display',
      someCustomField: '2022',

You can access this data in your HTML template using Handlebars.js:

<h1>{{ someCustomField }}</h1>