Build custom Stripe PDF Invoices with Shadcn, Hono and cloudflare workers
In this article, we will build a basic system that allow to generate custom PDF invoice using Stripe and Cloudflare Workers.
Prerequisites
- A Stripe account
- A Cloudflare account (optional if you want to deploy to an another provider)
- A Printerz account (quick start guide here)
Create your invoice template
Let's start by creating our invoice template, here we will be using React and Vitejs but you can use any framework and even plain HTML (see details documentation here).
- Clone our basic example template
npx degit https://github.com/printerz-app/stripe-custom-invoice-tutorial
- Install dependencies
npm install
- Start the development server
npm run dev
You can explore the project, remix it and customize it to your needs. Or you can build your own template (check documentation here).
Build your project
Run the following command in order to build your project
npm run build
Upload our template to Printerz 🚀
Our last step is to create a zip file containing file inside your dist
folder.
And now we can upload our zip file to printerz !
Create our cloudflare worker
Let's start by scaffold a new Hono/Cloudflare worker project
npx create-hono@latest
Register a R2 binding in your wrangler.toml file
[[r2_buckets]]
binding = "BUCKET"
bucket_name = "my-bucket"
Add secret environment variables in a .dev.vars
file
STRIPE_SECRET_KEY=sk_xxxxxx # Gab yours here https://dashboard.stripe.com/apikeys
PRINTERZ_API_KEY=sk_xxxxxx # Grab yours here https://printerz.dev/dashboard/api-keys
Install stripe sdk
npm install stripe
Create a invoice list route
app.get('/invoices', async (c) => {
const stripeClient = new Stripe(c.env.STRIPE_SECRET_KEY);
const invoices = await stripeClient.invoices.list({
limit: 10,
});
return c.html(
<html style={{ fontFamily: "sans-serif" }}>
<body>
<h1>Invoices</h1>
<div style={{ display: "flex", flexDirection: "column", gap: "5px" }}>
{invoices.data.map((invoice) => (
<div style={{ border: "1px solid black", padding: "5px", borderRadius: "5px" }}>
<h2>{invoice.number}</h2>
<p>Due: {invoice.due_date ? new Date(invoice.due_date * 1000).toLocaleDateString("en-US") : "N/A"}</p>
<p>Total: {invoice.amount_paid / 100}</p>
<a target="_blank" href={`/invoices/${invoice.id}/pdf`}>Download PDF</a>
</div>
))}
</div>
</body>
</html>
)
})
Create a invoice pdf route
app.get("/invoices/:invoiceId/pdf", async (c) => {
const stripeClient = new Stripe(c.env.STRIPE_SECRET_KEY);
const invoice = await stripeClient.invoices.retrieve(c.req.param("invoiceId"));
const storageKey = `invoices/${invoice.id}.pdf`;
const storedPDF = await c.env.BUCKET.get(storageKey);
if (storedPDF) {
return new Response(storedPDF.body, {
headers: {
"Content-Type": "application/pdf",
}
})
}
const renderedPDF = await fetch("https://api.printerz.dev/templates/02c1e66a-6d39-4a1d-b934-8ae646b9419c/render", {
method: "POST",
headers: {
"x-api-key": c.env.PRINTERZ_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
variables: {
invoiceNumber: invoice.number,
company: {
name: invoice.account_name,
address: "123 Main St, Anytown, USA",
email: "[email protected]",
phone: "555-555-5555",
},
client: {
name: invoice.customer_name,
address: invoice.customer_address,
email: invoice.customer_email,
},
date: new Date(invoice.created * 1000).toLocaleDateString("en-US"),
dueDate: invoice.due_date ? new Date(invoice.due_date * 1000).toLocaleDateString("en-US") : "N/A",
items: invoice.lines.data.map((line) => ({
description: line.description,
quantity: line.quantity,
price: line.amount / 100,
total: (line.amount / 100) * (line.quantity ?? 1),
})),
subtotal: invoice.subtotal / 100,
tax: invoice.tax ? invoice.tax / 100 : 0,
total: invoice.amount_paid
},
})
});
const pdfBuffer = await renderedPDF.arrayBuffer();
await c.env.BUCKET.put(storageKey, pdfBuffer);
return new Response(pdfBuffer, {
headers: {
"Content-Type": "application/pdf",
}
})
});
Results
Conclusion
In this guide, we’ve walked through the process of creating custom Stripe PDF invoices using Shadcn, Hono, and Cloudflare Workers. By leveraging Printerz for template rendering and Cloudflare for deployment, you can streamline the generation of dynamic PDFs tailored to your business needs. This setup not only simplifies your workflow but also ensures scalability and efficiency in managing invoices. With these tools, you’re equipped to handle PDF generation effortlessly, allowing you to focus more on growing your application and providing value to your users.
MIT 2025 © Printerz.