# Event ticket PDF generator Generate event ticket PDFs from HTML with a clean ticket layout, server-side or JavaScript QR codes, one ticket per page, and email delivery. Concerts, meetups, conferences and workshops all need the same thing after checkout. Attendees need a ticket they can print or show on a phone, with a code you can scan at the door. A PDF is the most portable format for that. It opens on any device, prints cleanly and attaches to an email. Here's how to generate ticket PDFs from an HTML template. **Quick answer.** Build one `.ticket` block per attendee with `break-after: page`, embed each QR code as a data URI, and send the HTML to the API: ```bash curl -X POST https://html-pdf.com/v1/pdf \ -H "Authorization: Bearer $HTML_PDF_KEY" \ -H "Content-Type: application/json" \ -d '{"html": "

Frontend Night 2026

TKT-8F3K2Q

", "prefer_css_page_size": true}' \ -o tickets.pdf ``` ## Ticket layout This section gives you a ticket template with a clear hierarchy. A ticket needs these parts. - **Event name, date, time and venue**: the largest text. - **Attendee name and ticket type** (General, VIP, Day 2). - **A scannable code**, usually a QR code holding a unique ticket ID or a signed token. - **The ticket ID in plain text**, so staff can type it in if a scan fails. - **Small print**: refund policy, entry rules. A6 landscape or a half-page layout fits a phone screen well. Use A4 if attendees are likely to print it. ```html ``` `break-after: page` gives each ticket its own page. A group order becomes one PDF with one ticket per page, and you can still split it later if needed. ## QR codes: server-side (recommended) Generating QR codes on your server is the simplest and most reliable approach. Embed each code as inline SVG or a PNG data URI, and the page needs no JavaScript and no external requests. In Node.js, the `qrcode` package does both. ```js import fs from "node:fs"; import QRCode from "qrcode"; const esc = s => String(s).replace(/[&<>"']/g, c => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c])); const head = fs.readFileSync("ticket-head.html", "utf8"); // the and styles above const tickets = [ { id: "TKT-8F3K2Q", name: "Ana García", type: "General" }, { id: "TKT-9P1Z7M", name: "Tom Becker", type: "VIP" }, ]; const blocks = await Promise.all(tickets.map(async t => { const qr = await QRCode.toDataURL(t.id, { errorCorrectionLevel: "M", margin: 1, width: 400 }); return `

Frontend Night 2026

Thu 12 Nov 2026 · 19:00
The Warehouse, 5 River St

${esc(t.name)}
${esc(t.type)}

Non-transferable. Show this ticket at the entrance.

QR code
${t.id}
`; })); const html = `${head}${blocks.join("")}`; const res = await fetch("https://html-pdf.com/v1/pdf", { method: "POST", headers: { Authorization: `Bearer ${process.env.HTML_PDF_KEY}`, "Content-Type": "application/json" }, body: JSON.stringify({ html, prefer_css_page_size: true, filename: "tickets-order-1042.pdf" }), }); if (!res.ok) throw new Error((await res.json()).error.message); fs.writeFileSync("tickets-order-1042.pdf", Buffer.from(await res.arrayBuffer())); ``` If you prefer vector output, `QRCode.toString(t.id, { type: "svg" })` returns an SVG string instead. In Python, `segno.make(ticket_id).svg_inline()` gives you inline SVG. What goes in the QR code matters more than how it's drawn. Use a random, unguessable ID (or a signed token), check it against your database at the door, and mark it as used on the first scan. ## QR codes: in the page with JavaScript You can also draw the codes in the page itself. Load a QR library from a CDN, draw the codes and set a flag when they're done. Then pass `"wait_for_expression": "window.ticketsReady === true"` so the PDF isn't captured before the codes exist. Setting `wait_delay` (up to 10 seconds) also works, but waiting for an explicit flag is faster and more reliable. ## Python version Here is the render step in Python, assuming your HTML is already filled in. ```python import os, requests html = open("tickets.html", encoding="utf-8").read() # filled, escaped, QR codes embedded r = requests.post("https://html-pdf.com/v1/pdf", headers={"Authorization": f"Bearer {os.environ['HTML_PDF_KEY']}"}, json={"html": html, "prefer_css_page_size": True, "max_pages": 20}, timeout=60) r.raise_for_status() open("tickets.pdf", "wb").write(r.content) ``` ## PDF tickets vs wallet passes A PDF is not an Apple Wallet or Google Wallet pass. Wallet passes are separate formats (a signed `.pkpass` bundle for Apple Wallet, and Google's Wallet API for Android) that need their own developer setup and signing. Many events send both. The PDF is the universal fallback that always works, and an "Add to Wallet" button serves those who want it. The same ticket ID can power both. ## Email delivery The usual flow is to attach the PDF to the order confirmation email. Use your mail provider or SMTP library, and give the file a name that's easy to find later (`tickets-frontend-night-1042.pdf`). For a "download your tickets" button, request `"response": "url"` instead. The link is valid for 24 hours, so store the PDF in your own storage if you need long-lived links. Send tickets only after payment is confirmed, for example from your payment webhook. ## Generate tickets with html-pdf.com html-pdf.com turns HTML or a URL into a PDF with Chromium. Each ticket page costs one credit. You get 100 free credits once you confirm your email, then pay from $0.005 per page, and purchased credits never expire. Your HTML is not stored. [Get an API key](https://html-pdf.com/login), browse [templates](https://html-pdf.com/templates), or read the [docs](https://html-pdf.com/docs). With the [MCP server](https://html-pdf.com/pdf-mcp-server), an AI agent can create tickets on request: > *"Create PDF tickets for Frontend Night on 12 November 2026 at The Warehouse for these 5 attendees, one ticket per page, each with a QR code of its ticket ID and the ID printed underneath."* ## FAQ ### How do I put one ticket per page in a PDF? Wrap each ticket in its own block with `break-after: page`, and set `break-after: auto` on the last one. A group order then becomes one PDF with one ticket per page. ### How do I add a QR code to a ticket PDF? Generate it on your server with a library like `qrcode` (Node.js) or `segno` (Python) and embed it as a data URI or inline SVG. If you draw it with JavaScript in the page instead, use `wait_for_expression` so the PDF waits for the codes. ### How much does it cost to generate ticket PDFs? Each ticket page costs one credit. New accounts get 100 free credits once with no card, then packs run from $10 for 1,000 credits to $250 for 50,000, and purchased credits never expire. ### Can a PDF ticket be added to Apple Wallet or Google Wallet? No. Wallet passes are separate formats with their own setup and signing. Many events send the PDF plus an "Add to Wallet" button, both using the same ticket ID.