blog
How to Generate PDF Receipts from Stripe Webhooks
When your PDF pipeline cracks at 2 AM and customers are waiting on invoices, debugging headless Chromium is the last thing you want to do. This guide cuts to what actually matters for HTML to PDF API in production: templates that render the same way every time, render jobs that survive queue spikes, and an API surface with clear failure modes so on-call is boring.
Updated 2026-02-24
Problem
A backend worker needs to render documents idempotently from queue events and avoid duplicate PDFs during retries.
Treat rendering as a backend job pipeline: idempotent requests, queue control, and deterministic templates.
Typst playground
A backend worker needs to render documents idempotently from queue events and avoid duplicate PDFs during retries.
Queue receipt Typst template
Sample JSON payload
#set page(paper: "a4", margin: 18mm)
#set text(font: "Inter", size: 10pt)
#let data = sys.inputs
#text(size: 22pt, weight: "bold")[#data.title]
#v(4pt)
#text(fill: rgb("#64748b"))[#data.reference + " - " + data.date]
#v(12pt)
#block(
fill: rgb("#f8fafc"),
stroke: 0.5pt + rgb("#e2e8f0"),
inset: 12pt,
radius: 4pt,
)[
#text(weight: "semibold")[#data.customer]
#linebreak()
#text(fill: rgb("#64748b"))[#data.status]
]
#v(12pt)
#table(
columns: (1fr, auto, auto),
inset: 7pt,
stroke: 0.5pt + rgb("#e2e8f0"),
[*Item*], [*Qty*], [*Amount*],
..data.line_items.map(item => (
item.name,
str(item.qty),
"$" + str(item.amount),
)).flatten(),
)Queue render receipt
Idempotent
Queue render receipt
Idempotent
Solution & copyable API code
Feed render jobs through queues partitioned by document type or priority. This prevents a noisy workload from starving critical documents. Attach stable idempotency keys per business document event so retries do not create duplicate outputs.
const response = await fetch(`${process.env.DOCUFORGE_API_URL}/v1/render`, {
method: "POST",
headers: {
"X-API-Key": process.env.DOCUFORGE_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({ template_id: "tpl_how_to_generate_pdf_receipts_from_stripe_webhooks", data: payload }),
});
const pdf = Buffer.from(await response.arrayBuffer());Customization tips
- Attach an idempotency key to each business event before rendering.
- Keep retry metadata outside the PDF payload so document output stays deterministic.
- Keep brand colors, spacing, and repeated footer copy in shared template variables.
- Pass customer-specific values through JSON data instead of forking the template.
- Store one approved sample payload per template so preview regressions are easy to catch.
Puntos clave
- Queue partitioning and idempotency are mandatory at scale.
- Template version IDs should be explicit in production render events.
- Monitor usage and quotas by plan and document family.
- Keep failure handling deterministic with typed error branches.
Why teams choose DocuForge for this workflow
- Render API is queue-friendly with predictable request/response envelopes.
- Usage and billing endpoints support operational visibility.
- No headless Chrome dependency in the main render engine path.
Recursos relacionados
FAQ
How do we avoid duplicate documents on retries?
Use business-event idempotency keys and persist render outcomes before acknowledging queue completion.
What should we put in dead-letter queues?
Jobs with non-retryable schema/template failures and jobs that exceeded bounded retry policy.
Recursos relacionados
Entrega mas rapido con una API orientada a plantillas
Prueba plantillas en el playground y reutiliza la misma solicitud en produccion.
