<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ethan from reportgen.io</title>
    <description>The latest articles on DEV Community by Ethan from reportgen.io (@ethan_reportgen).</description>
    <link>https://dev.to/ethan_reportgen</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3077893%2F19d953fa-46df-4ad8-8175-ebf58625685b.png</url>
      <title>DEV Community: Ethan from reportgen.io</title>
      <link>https://dev.to/ethan_reportgen</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ethan_reportgen"/>
    <language>en</language>
    <item>
      <title>Reportgen.io vs Html2pdf.app - Which PDF API Should You Use in 2025? ⚔️</title>
      <dc:creator>Ethan from reportgen.io</dc:creator>
      <pubDate>Wed, 04 Jun 2025 06:46:26 +0000</pubDate>
      <link>https://dev.to/ethan_reportgen/reportgenio-vs-html2pdfapp-which-pdf-api-should-you-use-in-2025-357p</link>
      <guid>https://dev.to/ethan_reportgen/reportgenio-vs-html2pdfapp-which-pdf-api-should-you-use-in-2025-357p</guid>
      <description>&lt;p&gt;Before we dive into the details, here’s the TL;DR: &lt;strong&gt;Reportgen.io&lt;/strong&gt; is&lt;br&gt;
purpose-built for &lt;em&gt;dynamic&lt;/em&gt; PDF generation with multiple templating engines,&lt;br&gt;
pay-per-use pricing, and a developer-centric dashboard, while &lt;strong&gt;Html2pdf.app&lt;/strong&gt;&lt;br&gt;
shines as a lightweight, credit-based service for straight-forward&lt;br&gt;
raw-HTML-to-PDF jobs. If you need highly-customized, data-driven documents,&lt;br&gt;
Reportgen.io is likely the better fit; if you just want to turn single pages&lt;br&gt;
into PDFs on a tight budget, Html2pdf.app may suffice.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔍 Overview
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reportgen.io&lt;/strong&gt;: An API that lets you feed &lt;em&gt;templated&lt;/em&gt; HTML (EJS, Handlebars,
GoTempl, or raw) plus JSON data and returns a PDF, either synchronously or via
an async job queue. It offers a generous free tier (150 PDFs/month) and simple
$0.0025 per-report, pay-as-you-go billing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Html2pdf.app&lt;/strong&gt;: A credit-based service that converts raw HTML or a public
URL into a PDF. It supports synchronous calls and an asynchronous callback
mode, with 100 free credits/month (1 MB max per file) and paid plans starting
at $9 for 1 000 credits.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📊 Feature Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Reportgen.io&lt;/th&gt;
&lt;th&gt;Html2pdf.app&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Templating Engines&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;EJS, Handlebars, GoTempl, Raw HTML&lt;/td&gt;
&lt;td&gt;Raw HTML only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Sync &amp;amp; Async&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Both, no concurrency ceiling&lt;/td&gt;
&lt;td&gt;Both; parallel jobs limited by plan&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Built-in Storage/CDN&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cloudflare R2 for 1-year retention&lt;/td&gt;
&lt;td&gt;❌ File is streamed back; you store it yourself&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dashboard UI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Full usage analytics &amp;amp; logs&lt;/td&gt;
&lt;td&gt;Simple credit counter + usage chart&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dynamic Data Insertion&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;JSON payload populates templates&lt;/td&gt;
&lt;td&gt;❌ Not supported (no templating)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Styling Support&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Any modern CSS + JS (e.g., Tailwind, Chart.js)&lt;/td&gt;
&lt;td&gt;Modern CSS &amp;amp; JS via browser engine&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Code Samples&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;cURL, JS/TS, Python, Go&lt;/td&gt;
&lt;td&gt;cURL, PHP, Node, Python, Ruby, Java, Go&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Free Tier&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;150 PDFs/month&lt;/td&gt;
&lt;td&gt;100 credits/month (1 MB/file)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pricing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$0.0025 per PDF (pay-per-use)&lt;/td&gt;
&lt;td&gt;From $9/mo (1 000 credits)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Encryption&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AES-256 optional&lt;/td&gt;
&lt;td&gt;AES-128 optional&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🧑‍💻 Developer Experience
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Reportgen.io&lt;/strong&gt; feels like a developer tool: multiple templating engines,&lt;br&gt;
signed URLs, verbose error payloads, and an observability-first dashboard with&lt;br&gt;
per-job logs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Html2pdf.app&lt;/strong&gt; keeps things minimal. You post HTML, poll (or await a callback)&lt;br&gt;
and get a PDF. A lightweight dashboard shows remaining credits, and a new chart&lt;br&gt;
on the &lt;em&gt;Credits&lt;/em&gt; tab helps you track usage at a glance.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎨 Customization &amp;amp; Integration
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reportgen.io&lt;/strong&gt; lets you mix Tailwind, Chart.js, or any client-side library
inside your templates, so invoices, dashboards, or contracts can be fully
branded.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Html2pdf.app&lt;/strong&gt; renders modern CSS &amp;amp; JS thanks to a headless browser engine,
but without a server-side templating step you must generate your HTML string
yourself.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ⚙️ Performance, Scalability &amp;amp; Security
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Reportgen.io processes unlimited PDFs async out-of-the-box and scales
horizontally; PDFs up to 189 MB have been reported in production.&lt;/li&gt;
&lt;li&gt;Html2pdf.app allows “unlimited PDF size” on paid plans, but each 5 MB chunk
costs 1 credit, so a 15 MB document burns 3 credits.&lt;/li&gt;
&lt;li&gt;Both services offer encrypted PDFs. Reportgen.io supports AES-256, while
Html2pdf.app documents note AES-128.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  💰 Pricing Breakdown
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Free Tier&lt;/th&gt;
&lt;th&gt;Pay-as-you-go / Subscription&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Reportgen.io&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;150 PDFs/mo&lt;/td&gt;
&lt;td&gt;$0.0025 per PDF, no minimum&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Html2pdf.app&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;100 credits (1 MB cap)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Startup&lt;/strong&gt;: $9/mo → 1 000 credits; larger plans scale up with more parallel jobs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Tip:&lt;/em&gt; Html2pdf.app’s credit model means very large files may exhaust your&lt;br&gt;
quota quickly, whereas Reportgen.io’s flat rate is size-agnostic.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🧠 Who Should Use What?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Choose Reportgen.io if you need…&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dynamic PDFs powered by templating and JSON data.&lt;/li&gt;
&lt;li&gt;Pay-per-document pricing without monthly lock-ins.&lt;/li&gt;
&lt;li&gt;A dashboard with logs, usage analytics, and signed download URLs.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Choose Html2pdf.app if you need…&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Quick, no-frills conversion of single-page raw HTML.&lt;/li&gt;
&lt;li&gt;A low-cost entry point (100 free credits) for small files.&lt;/li&gt;
&lt;li&gt;Language-agnostic code snippets in six major languages out-of-the-box.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  ✅ Conclusion
&lt;/h2&gt;

&lt;p&gt;Both APIs turn HTML into PDFs, but &lt;strong&gt;Reportgen.io&lt;/strong&gt; excels when documents are&lt;br&gt;
&lt;em&gt;dynamic&lt;/em&gt;, large, or part of a mission-critical workflow, while &lt;strong&gt;Html2pdf.app&lt;/strong&gt;&lt;br&gt;
remains attractive for lightweight, occasional jobs that fit neatly into its&lt;br&gt;
credit-based model. Match the tool to the complexity of your output and the&lt;br&gt;
predictability of your volume.&lt;/p&gt;




&lt;h3&gt;
  
  
  Ready to build?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;🆓
&lt;strong&gt;&lt;a href="https://reportgen.io/sign-up" rel="noopener noreferrer"&gt;Get 150 free reports/month – no credit card required&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;📖 &lt;strong&gt;&lt;a href="https://docs.reportgen.io/" rel="noopener noreferrer"&gt;Read the Docs&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your PDFs deserve better. Let’s build them right. 🔥&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>pdf</category>
    </item>
    <item>
      <title>If you're doing PDF in your app, check this one out</title>
      <dc:creator>Ethan from reportgen.io</dc:creator>
      <pubDate>Thu, 29 May 2025 08:02:22 +0000</pubDate>
      <link>https://dev.to/ethan_reportgen/if-youre-doing-pdf-in-your-app-check-this-one-out-1790</link>
      <guid>https://dev.to/ethan_reportgen/if-youre-doing-pdf-in-your-app-check-this-one-out-1790</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/ethan_reportgen" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3077893%2F19d953fa-46df-4ad8-8175-ebf58625685b.png" alt="ethan_reportgen"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/ethan_reportgen/ditch-puppeteer-5-painful-lessons-learned-building-pdfs-at-scale-49pc" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;🚫 Ditch Puppeteer: 5 Painful Lessons Learned Building PDFs at Scale&lt;/h2&gt;
      &lt;h3&gt;Ethan from reportgen.io ・ May 28&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>softwaredevelopment</category>
      <category>webdev</category>
      <category>plugin</category>
      <category>tooling</category>
    </item>
    <item>
      <title>🚫 Ditch Puppeteer: 5 Painful Lessons Learned Building PDFs at Scale</title>
      <dc:creator>Ethan from reportgen.io</dc:creator>
      <pubDate>Wed, 28 May 2025 19:45:52 +0000</pubDate>
      <link>https://dev.to/ethan_reportgen/ditch-puppeteer-5-painful-lessons-learned-building-pdfs-at-scale-49pc</link>
      <guid>https://dev.to/ethan_reportgen/ditch-puppeteer-5-painful-lessons-learned-building-pdfs-at-scale-49pc</guid>
      <description>&lt;p&gt;&lt;em&gt;We thought Puppeteer was “good enough.” Turns out, “good enough” breaks at scale. Here’s what nobody tells you about building PDF pipelines with headless browsers.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🪓 The Cold, Hard Truth About Puppeteer PDF Generation
&lt;/h2&gt;

&lt;p&gt;If you’ve ever Googled “generate PDF from HTML in Node.js,” you’ve probably landed on Puppeteer. It’s fast, works for MVPs, and it’s open source. But when our app started generating thousands of PDFs a day, we learned some hard lessons. The kind of lessons that don’t show up in the docs.&lt;/p&gt;

&lt;p&gt;Here’s what went wrong (and what I wish I knew sooner):&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Zombie Chrome Processes Will Haunt You
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Remember that “just use headless Chrome in Docker” tip? Works fine - until it doesn’t.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Puppeteer spawns Chrome processes for each PDF job. But when things go wrong - timeouts, crashes, or OS bugs - it &lt;em&gt;leaks&lt;/em&gt; those processes. Suddenly, your servers are chewing through memory and “OOM killed” becomes your favorite Slack notification.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt;&lt;br&gt;
Managing Chrome at scale is a game of whack-a-mole. You’ll burn time on process cleanup instead of shipping features.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Performance Bottlenecks Sneak Up Fast
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Need to generate PDFs in parallel? Say hello to the bottleneck monster.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Each Puppeteer instance uses 100MB+ RAM and spawns its own Chromium process. Try spinning up 10, 20, or 50 at once. You’ll hit resource limits &lt;em&gt;fast&lt;/em&gt;, especially on smaller VMs or containers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt;&lt;br&gt;
Scaling horizontally gets expensive. For bursty workloads, expect weird delays, timeouts, and server crashes unless you invest in orchestration.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Docker Nightmares &amp;amp; OS Compatibility
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Works on my machine. Fails in prod. Welcome to container hell.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Dockerizing Puppeteer means juggling fonts, dependencies, glibc versions, missing libraries, and obscure startup flags. “Error: failed to launch Chromium” is the bane of your CI/CD pipeline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt;&lt;br&gt;
Upgrading Chrome? Be ready for surprise production outages and dependency chaos.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. Debugging Is a Time Sink
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Your beautiful HTML works in the browser… but your PDF is a hot mess.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Headless Chrome renders differently from your desktop browser: think missing fonts, broken CSS, and no animations. Debugging means endless screenshotting, CSS tweaking, rerunning jobs, and a healthy dose of frustration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt;&lt;br&gt;
Expect to lose hours chasing rendering quirks and “why is my chart missing?” mysteries.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. Security &amp;amp; Maintenance Are Never “Done”
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Running browsers on your backend? Prepare for patch marathons.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Chromium ships security patches almost weekly. Falling behind means risking exploits and stability issues. You’ll end up maintaining a mini browser farm just to keep up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson:&lt;/strong&gt;&lt;br&gt;
Security and compliance become ongoing headaches, especially if you handle sensitive data.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 What Actually Works at Scale?
&lt;/h2&gt;

&lt;p&gt;After all this pain, we created a PDF-as-a-Service model called &lt;a href="https://reportgen.io" rel="noopener noreferrer"&gt;Reportgen.io&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No more Chrome orchestration:&lt;/strong&gt; Just send HTML &amp;amp; data, get a PDF back.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Async &amp;amp; scalable:&lt;/strong&gt; Handles spikes and queues without server bottlenecks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simple REST API:&lt;/strong&gt; Integrates with any stack (Go, Node.js, Python, etc.).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secure &amp;amp; auto-updating:&lt;/strong&gt; Someone else worries about browser patches and exploits.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Bonus:&lt;/strong&gt;&lt;br&gt;
We got back days of engineering time and no more server babysitting or “Chromium upgrade Fridays.”&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚡ TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Puppeteer is fine for hobby projects.&lt;/li&gt;
&lt;li&gt;At scale? It’ll break your infrastructure and your sanity.&lt;/li&gt;
&lt;li&gt;Consider a dedicated PDF API and let someone else handle the mess.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Curious? Try &lt;a href="https://reportgen.io" rel="noopener noreferrer"&gt;Reportgen.io&lt;/a&gt; for free. Skip the Puppeteer pain and focus on shipping.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;Want more technical war stories or a step-by-step migration guide? Drop a comment below! 👇&lt;/p&gt;

</description>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Ethan from reportgen.io</dc:creator>
      <pubDate>Wed, 21 May 2025 09:47:14 +0000</pubDate>
      <link>https://dev.to/ethan_reportgen/-517k</link>
      <guid>https://dev.to/ethan_reportgen/-517k</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/ethan_reportgen/stop-wasting-hours-on-pdf-generation-a-fast-clean-javascript-setup-with-reportgenio-57i6" class="crayons-story__hidden-navigation-link"&gt;Stop Wasting Hours on PDF Generation: A Fast, Clean JavaScript Setup with reportgen.io&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/ethan_reportgen" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3077893%2F19d953fa-46df-4ad8-8175-ebf58625685b.png" alt="ethan_reportgen profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/ethan_reportgen" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Ethan from reportgen.io
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Ethan from reportgen.io
                
              
              &lt;div id="story-author-preview-content-2508962" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/ethan_reportgen" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3077893%2F19d953fa-46df-4ad8-8175-ebf58625685b.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Ethan from reportgen.io&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/ethan_reportgen/stop-wasting-hours-on-pdf-generation-a-fast-clean-javascript-setup-with-reportgenio-57i6" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;May 21 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/ethan_reportgen/stop-wasting-hours-on-pdf-generation-a-fast-clean-javascript-setup-with-reportgenio-57i6" id="article-link-2508962"&gt;
          Stop Wasting Hours on PDF Generation: A Fast, Clean JavaScript Setup with reportgen.io
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/javascript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;javascript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/programming"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;programming&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/backend"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;backend&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/tutorial"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;tutorial&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/ethan_reportgen/stop-wasting-hours-on-pdf-generation-a-fast-clean-javascript-setup-with-reportgenio-57i6" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;5&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/ethan_reportgen/stop-wasting-hours-on-pdf-generation-a-fast-clean-javascript-setup-with-reportgenio-57i6#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>javascript</category>
      <category>programming</category>
      <category>backend</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Stop Wasting Hours on PDF Generation: A Fast, Clean JavaScript Setup with reportgen.io</title>
      <dc:creator>Ethan from reportgen.io</dc:creator>
      <pubDate>Wed, 21 May 2025 05:45:53 +0000</pubDate>
      <link>https://dev.to/ethan_reportgen/stop-wasting-hours-on-pdf-generation-a-fast-clean-javascript-setup-with-reportgenio-57i6</link>
      <guid>https://dev.to/ethan_reportgen/stop-wasting-hours-on-pdf-generation-a-fast-clean-javascript-setup-with-reportgenio-57i6</guid>
      <description>&lt;p&gt;Generating PDFs in a JS app used to mean fragile Puppeteer scripts, bloated code, or expensive third-party services. We hated it. So we built reportgen.io. A faster, simpler way to generate dynamic documents with real templates and real data.&lt;/p&gt;

&lt;p&gt;Whether you’re building invoicing software, generating reports, or creating marketing materials, reportgen.io makes it easy to create dynamic, high-quality PDFs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before You Begin
&lt;/h2&gt;

&lt;p&gt;To follow along, make sure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A JavaScript or TypeScript project set up.&lt;/li&gt;
&lt;li&gt;An Access key from &lt;a href="https://reportgen.io/board/access-keys" rel="noopener noreferrer"&gt;reportgen.io&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Basic familiarity with REST APIs and how to make HTTP requests.&lt;/li&gt;
&lt;li&gt;Node.js installed on your system.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also use tools like &lt;strong&gt;Postman&lt;/strong&gt; or &lt;strong&gt;curl&lt;/strong&gt; to test the API before diving into code. Postman is a powerful API testing tool that simplifies debugging. &lt;a href="https://www.postman.com/downloads/" rel="noopener noreferrer"&gt;Download Postman&lt;/a&gt; to get started.&lt;/p&gt;

&lt;p&gt;In this guide for dynamic PDF generation with Javascript, we will be using the EJS templating engine. EJS is a simple templating language that lets you generate HTML markup with plain JavaScript. If you’re new to EJS, you can learn more about it in the &lt;a href="https://ejs.co/" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;.&lt;br&gt;
There are other templating engines like Handlebars, GoTempl and Raw that you can use with reportgen.io. &lt;a href="https://docs.reportgen.io/api/engines" rel="noopener noreferrer"&gt;Learn more about templating engines&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1: Set Up Your Project and Install Dependencies
&lt;/h2&gt;

&lt;p&gt;First, create a folder structure for your project. Here’s a suggested layout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/project-root
    /templates
        invoice.ejs
    /src
        reportgen.js
    index.js
    package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Initialize Your Project and Install Dependencies
&lt;/h3&gt;

&lt;p&gt;Run the following command to initialize your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install Required Dependencies&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;node-fetch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Create your dynamic HTML template
&lt;/h2&gt;

&lt;p&gt;Create an HTML template in the &lt;code&gt;/templates&lt;/code&gt; folder. For example, name it &lt;code&gt;invoice.ejs&lt;/code&gt; and include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Invoice&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Invoice for &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="na"&gt;Name&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Total Due: $&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="na"&gt;Total&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save this file as &lt;code&gt;invoice.ejs&lt;/code&gt;. This template will be processed server-side by reportgen.io using the EJS templating engine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Integrate with the reportgen.io API
&lt;/h2&gt;

&lt;p&gt;Create a new file in the &lt;code&gt;/src&lt;/code&gt; directory, e.g., &lt;code&gt;reportgen.js&lt;/code&gt;. Add the following code which will interact with reportgen API (the core function that you will call across your project):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;readFileSync&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node-fetch&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;generatePDF&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;templateKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;apiUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://reportgen.io/api/v1/generate-pdf-sync&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;accessKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REPORTGEN_ACCESS_KEY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Load the HTML template&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;htmlTemplate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;templates&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;templateKey&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.ejs`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;html_template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;htmlTemplate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ejs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Also supports "handlebars, gotempl and raw"&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;apiUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;X-API-Key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;accessKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`API error: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pdfBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;arrayBuffer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;pdfBuffer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Error generating PDF: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explanation of the Code:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;File Read: The fs module reads your template file.&lt;/li&gt;
&lt;li&gt;Payload: Prepares the payload for the API request.&lt;/li&gt;
&lt;li&gt;Fetch API: Makes an HTTP POST request to the reportgen.io endpoint.&lt;/li&gt;
&lt;li&gt;Error Handling: Outputs helpful messages if something goes wrong.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 4: Prepare the last pieces for your integration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Set your access key in the environment
&lt;/h3&gt;

&lt;p&gt;Usually you would have .env file in the project root directory. Add your access key to the .env file like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;REPORTGEN_ACCESS_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_access_key_here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But you can also simply set the environment variable in your terminal with &lt;code&gt;export&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;REPORTGEN_ACCESS_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_access_key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create the main file that will call the function
&lt;/h3&gt;

&lt;p&gt;Create an &lt;code&gt;index.js&lt;/code&gt; file where you'll call the new function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;generatePDF&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./src/reportgen.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;John Doe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;Total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;generatePDF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;invoice&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;pdfArrayBuffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;invoice_for_john.pdf&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pdfArrayBuffer&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PDF successfully generated and saved as invoice_for_john.pdf&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Error generating PDF: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explanation of the Code:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Data Object: Contains the "dynamic" data to be injected into the template.&lt;/li&gt;
&lt;li&gt;Function Call: Invokes the &lt;code&gt;generatePDF&lt;/code&gt; function with the template key and data.&lt;/li&gt;
&lt;li&gt;Write PDF: Saves the generated PDF to a file.&lt;/li&gt;
&lt;li&gt;Console Log: Displays a success message or error.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 5: Test your integration ✅
&lt;/h2&gt;

&lt;p&gt;Run your script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node index.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Upon success, the console will display a message that the PDF has been generated and saved. You can find the freshly generated PDF in your project directory under the name &lt;code&gt;invoice_for_john.pdf&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extra: Testing with tools like Postman
&lt;/h2&gt;

&lt;p&gt;Before coding, you can use testing tools like Postman to validate your API calls:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set the method to POST and the URL to &lt;a href="https://reportgen.io/api/v1/generate-pdf-sync" rel="noopener noreferrer"&gt;https://reportgen.io/api/v1/generate-pdf-sync&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Add the X-API-Key header with your access key.&lt;/li&gt;
&lt;li&gt;In the body, set the payload as raw JSON:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"html_template"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;h1&amp;gt;Hello &amp;lt;%= Name %&amp;gt;&amp;lt;/h1&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John Doe"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"engine"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ejs"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Check the response for errors or success.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Learn more about using Postman in their documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;Ready to stop wasting time on document generation? Sign up at reportgen.io and create your first PDF in under 5 minutes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;💻 Source code: &lt;a href="https://github.com/reportgenio/examples/tree/main/how-to-with-node" rel="noopener noreferrer"&gt;On GitHub&lt;/a&gt;, plus a lot more examples.&lt;/li&gt;
&lt;li&gt;👉 Create an Account: &lt;a href="https://reportgen.io/sign-up" rel="noopener noreferrer"&gt;Sign up&lt;/a&gt; if you haven’t already.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👥 Have a better way to write this code? Drop it in the comments below. I always love a good code review!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>programming</category>
      <category>backend</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Ethan from reportgen.io</dc:creator>
      <pubDate>Wed, 14 May 2025 04:33:42 +0000</pubDate>
      <link>https://dev.to/ethan_reportgen/-emd</link>
      <guid>https://dev.to/ethan_reportgen/-emd</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/ethan_reportgen/how-to-generate-dynamic-invoices-for-saas-applications-in-python-4j5p" class="crayons-story__hidden-navigation-link"&gt;How to generate dynamic invoices for SaaS applications in Python 💸&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/ethan_reportgen" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3077893%2F19d953fa-46df-4ad8-8175-ebf58625685b.png" alt="ethan_reportgen profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/ethan_reportgen" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Ethan from reportgen.io
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Ethan from reportgen.io
                
              
              &lt;div id="story-author-preview-content-2486303" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/ethan_reportgen" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3077893%2F19d953fa-46df-4ad8-8175-ebf58625685b.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Ethan from reportgen.io&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/ethan_reportgen/how-to-generate-dynamic-invoices-for-saas-applications-in-python-4j5p" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;May 14 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/ethan_reportgen/how-to-generate-dynamic-invoices-for-saas-applications-in-python-4j5p" id="article-link-2486303"&gt;
          How to generate dynamic invoices for SaaS applications in Python 💸
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/programming"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;programming&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/python"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;python&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/tutorial"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;tutorial&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/ethan_reportgen/how-to-generate-dynamic-invoices-for-saas-applications-in-python-4j5p" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;5&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/ethan_reportgen/how-to-generate-dynamic-invoices-for-saas-applications-in-python-4j5p#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>webdev</category>
      <category>programming</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to generate dynamic invoices for SaaS applications in Python 💸</title>
      <dc:creator>Ethan from reportgen.io</dc:creator>
      <pubDate>Wed, 14 May 2025 04:28:19 +0000</pubDate>
      <link>https://dev.to/ethan_reportgen/how-to-generate-dynamic-invoices-for-saas-applications-in-python-4j5p</link>
      <guid>https://dev.to/ethan_reportgen/how-to-generate-dynamic-invoices-for-saas-applications-in-python-4j5p</guid>
      <description>&lt;p&gt;Invoice generation in SaaS applications doesn’t have to be tedious. With &lt;strong&gt;reportgen.io&lt;/strong&gt;, you can automate the entire process, offering dynamic, scalable, and secure solutions. Whether you're working on a single invoice or handling bulk generation, reportgen.io’s modern API is built to make developers’ lives easier.&lt;/p&gt;

&lt;p&gt;This guide walks you through the steps of integrating reportgen.io into your SaaS application for dynamic invoice generation, complete with advanced templating and efficient API calls.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Define a Dynamic Template with Conditional Logic
&lt;/h2&gt;

&lt;p&gt;Invoices are more than just a list of numbers; they must reflect accurate calculations, dynamic line items, and conditional elements like VAT. With &lt;strong&gt;reportgen.io&lt;/strong&gt;, you can use templating engines such as EJS to create powerful, flexible templates.&lt;/p&gt;

&lt;p&gt;Here’s an example template that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Iterates through line items dynamically.&lt;/li&gt;
&lt;li&gt;Calculates VAT conditionally based on the input percentage.&lt;/li&gt;
&lt;li&gt;Includes subtotals and totals.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  EJS Template Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Invoice for &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="na"&gt;CustomerName&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;table&lt;/span&gt; &lt;span class="na"&gt;border=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"border-collapse: collapse; width: 100%;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;thead&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;Description&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;Quantity&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;Price&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;Subtotal&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/thead&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;tbody&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%&lt;/span&gt; &lt;span class="na"&gt;LineItems.forEach(item =&lt;/span&gt;&lt;span class="err"&gt;&amp;gt; &lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="na"&gt;item.description&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="na"&gt;item.quantity&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="na"&gt;item.price.toFixed&lt;/span&gt;&lt;span class="err"&gt;(2)&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="na"&gt;item.quantity&lt;/span&gt; &lt;span class="na"&gt;*&lt;/span&gt; &lt;span class="na"&gt;item.price&lt;/span&gt;&lt;span class="err"&gt;).&lt;/span&gt;&lt;span class="na"&gt;toFixed&lt;/span&gt;&lt;span class="err"&gt;(2)&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%&lt;/span&gt; &lt;span class="err"&gt;});&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/tbody&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Subtotal: $&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="na"&gt;Subtotal.toFixed&lt;/span&gt;&lt;span class="err"&gt;(2)&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt; &lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="na"&gt;VATPercentage&lt;/span&gt; &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; 0) { %&amp;gt;
      &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;VAT (&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="na"&gt;VATPercentage&lt;/span&gt; &lt;span class="na"&gt;*&lt;/span&gt; &lt;span class="err"&gt;100).&lt;/span&gt;&lt;span class="na"&gt;toFixed&lt;/span&gt;&lt;span class="err"&gt;(1)&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;%): $&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="na"&gt;Subtotal&lt;/span&gt; &lt;span class="na"&gt;*&lt;/span&gt; &lt;span class="na"&gt;VATPercentage&lt;/span&gt;&lt;span class="err"&gt;).&lt;/span&gt;&lt;span class="na"&gt;toFixed&lt;/span&gt;&lt;span class="err"&gt;(2)&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;&lt;/span&gt;Total: $&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="na"&gt;Total.toFixed&lt;/span&gt;&lt;span class="err"&gt;(2)&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This template ensures flexibility and clarity, allowing you to dynamically populate all values, including VAT percentages and line items.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Write Python Functions
&lt;/h2&gt;

&lt;p&gt;To make the implementation reusable and scalable, we’ll create functions that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Dynamically calculate invoice data.&lt;/li&gt;
&lt;li&gt;Handle synchronous PDF generation for immediate needs.&lt;/li&gt;
&lt;li&gt;Use asynchronous generation for bulk operations.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 2.1: A Function to Generate Dynamic Data
&lt;/h3&gt;

&lt;p&gt;This function calculates the subtotal, VAT, and total dynamically based on the provided line items and VAT percentage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_invoice_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line_items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vat_percentage&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;subtotal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;quantity&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;line_items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;vat_amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subtotal&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;vat_percentage&lt;/span&gt;
    &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subtotal&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;vat_amount&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CustomerName&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;LineItems&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;line_items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Subtotal&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;subtotal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;VATPercentage&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;vat_percentage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Total&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2.2: A Function for Synchronous PDF Generation
&lt;/h3&gt;

&lt;p&gt;Synchronous generation is best for smaller workloads or when you need the invoice immediately. This function sends the request and saves the PDF locally.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_pdf_sync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://reportgen.io/api/v1/generate-pdf-sync&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;X-API-Key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;html_template&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;engine&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ejs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;invoice_sync.pdf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invoice generated successfully as &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;invoice_sync.pdf&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Failed to generate PDF: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; - &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2.3: A Function for Asynchronous PDF Generation
&lt;/h3&gt;

&lt;p&gt;Asynchronous generation is ideal for handling bulk operations or when the task isn’t time-sensitive. This function queues the PDF generation and returns a &lt;code&gt;report_id&lt;/code&gt; for tracking.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_pdf_async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://reportgen.io/api/v1/generate-pdf-async&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;X-API-Key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;html_template&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;engine&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ejs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;report_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;report_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invoice queued successfully. Report ID: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;report_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;report_id&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Failed to queue PDF generation: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; - &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 3: Usage
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Example Input
&lt;/h3&gt;

&lt;p&gt;Here’s an example of how to call the functions with dynamic data, but it doesn't include the functions. You can simply copy them over.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;api_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;template&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
&amp;lt;html&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;Invoice for &amp;lt;%= CustomerName %&amp;gt;&amp;lt;/h1&amp;gt;
    &amp;lt;table border=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; style=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;border-collapse: collapse; width: 100%;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;
      &amp;lt;thead&amp;gt;
        &amp;lt;tr&amp;gt;
          &amp;lt;th&amp;gt;Description&amp;lt;/th&amp;gt;
          &amp;lt;th&amp;gt;Quantity&amp;lt;/th&amp;gt;
          &amp;lt;th&amp;gt;Price&amp;lt;/th&amp;gt;
          &amp;lt;th&amp;gt;Subtotal&amp;lt;/th&amp;gt;
        &amp;lt;/tr&amp;gt;
      &amp;lt;/thead&amp;gt;
      &amp;lt;tbody&amp;gt;
        &amp;lt;% LineItems.forEach(item =&amp;gt; { %&amp;gt;
          &amp;lt;tr&amp;gt;
            &amp;lt;td&amp;gt;&amp;lt;%= item.description %&amp;gt;&amp;lt;/td&amp;gt;
            &amp;lt;td&amp;gt;&amp;lt;%= item.quantity %&amp;gt;&amp;lt;/td&amp;gt;
            &amp;lt;td&amp;gt;&amp;lt;%= item.price.toFixed(2) %&amp;gt;&amp;lt;/td&amp;gt;
            &amp;lt;td&amp;gt;&amp;lt;%= (item.quantity * item.price).toFixed(2) %&amp;gt;&amp;lt;/td&amp;gt;
          &amp;lt;/tr&amp;gt;
        &amp;lt;% }); %&amp;gt;
      &amp;lt;/tbody&amp;gt;
    &amp;lt;/table&amp;gt;
    &amp;lt;p&amp;gt;Subtotal: $&amp;lt;%= Subtotal.toFixed(2) %&amp;gt;&amp;lt;/p&amp;gt;
    &amp;lt;% if (VATPercentage &amp;gt; 0) { %&amp;gt;
      &amp;lt;p&amp;gt;VAT (&amp;lt;%= (VATPercentage * 100).toFixed(1) %&amp;gt;%): $&amp;lt;%= (Subtotal * VATPercentage).toFixed(2) %&amp;gt;&amp;lt;/p&amp;gt;
    &amp;lt;% } %&amp;gt;
    &amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Total: $&amp;lt;%= Total.toFixed(2) %&amp;gt;&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;span class="n"&gt;line_items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DevOps monthly&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;quantity&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;5000.0&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SysAdmin hours&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;quantity&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;35.0&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;vat_percentage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.22&lt;/span&gt;  &lt;span class="c1"&gt;# Dynamic VAT percentage
&lt;/span&gt;&lt;span class="n"&gt;customer_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;John Doe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate_invoice_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line_items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vat_percentage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Sync
&lt;/span&gt;&lt;span class="nf"&gt;generate_pdf_sync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Or async:
&lt;/span&gt;&lt;span class="n"&gt;report_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate_pdf_async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Track your report status using this ID: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;report_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Why Choose reportgen.io?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Powerhouse&lt;/strong&gt;: Unlike competitors, &lt;strong&gt;reportgen.io&lt;/strong&gt; empowers you to generate complex documents with dynamic data, conditional logic, and flexibility in templates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built for Scalability&lt;/strong&gt;: Handle large volumes of PDF generation asynchronously without performance bottlenecks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Developer-Centric&lt;/strong&gt;: We prioritize ease of use, robust documentation, and advanced templating options like EJS and Handlebars.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secure &amp;amp; Modern&lt;/strong&gt;: With Cloudflare-backed security and data privacy, reportgen.io ensures your sensitive data is always protected.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Competitive Edge&lt;/strong&gt;: &lt;strong&gt;reportgen.io&lt;/strong&gt; offers simplicity without compromising on advanced features and flexibility, giving you the best of both worlds.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Implement integrations with services like &lt;a href="https://novu.co" rel="noopener noreferrer"&gt;Novu.co&lt;/a&gt; for automated invoice emailing.&lt;/li&gt;
&lt;li&gt;Attach payment links using Stripe or PayPal APIs for seamless transactions.&lt;/li&gt;
&lt;li&gt;Enhance workflows by incorporating invoice tracking and CRM updates with HubSpot or Salesforce.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Start leveraging &lt;strong&gt;reportgen.io&lt;/strong&gt; to elevate your SaaS application's automation game today! 🚀&lt;/p&gt;




&lt;p&gt;💻 Source code can be found &lt;a href="https://github.com/reportgenio/examples/tree/main/how-to-with-python" rel="noopener noreferrer"&gt;on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;👉 Ready to make your PDFs not suck? Try it free at reportgen.io&lt;br&gt;
You get 150 reports for free each month, no credit card required.&lt;/p&gt;

&lt;p&gt;👥 Have a better way to write this code? Drop it in the comments below. I always love a good code review!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Level Up Your PDF Game: From 1998 to Stunning in 15 Minutes</title>
      <dc:creator>Ethan from reportgen.io</dc:creator>
      <pubDate>Wed, 07 May 2025 07:07:09 +0000</pubDate>
      <link>https://dev.to/ethan_reportgen/level-up-your-pdf-game-from-1998-to-stunning-in-15-minutes-3m60</link>
      <guid>https://dev.to/ethan_reportgen/level-up-your-pdf-game-from-1998-to-stunning-in-15-minutes-3m60</guid>
      <description>&lt;p&gt;You're shipping reports, invoices, or data exports as PDFs. And they look like they were built in 1998. That might fly internally, but the moment you're sending them to clients, investors, or partners, it reflects &lt;em&gt;directly&lt;/em&gt; on your brand.&lt;/p&gt;

&lt;p&gt;Bad design isn't neutral. It kills trust.&lt;/p&gt;

&lt;p&gt;With &lt;strong&gt;reportgen.io&lt;/strong&gt;, you can generate stunning PDFs using modern CSS, Tailwind, and Chart.js - without turning your dev team into a design agency.&lt;/p&gt;

&lt;p&gt;Here's how to go from "ugh" to "damn" in 15 minutes.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚧 Step 1: Basic CSS – Full Control, Old School
&lt;/h2&gt;

&lt;p&gt;If you want tight control and don't mind some manual work, you can write vanilla CSS. Think of this like hand-coding an HTML email.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- sample invoice template --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Arial&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nc"&gt;.invoice&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;600px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#ccc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"invoice"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Invoice&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;table&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No dependencies.&lt;/li&gt;
&lt;li&gt;Predictable rendering.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Verbose.&lt;/li&gt;
&lt;li&gt;No design system or utility classes.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ⚡ Step 2: Tailwind – Fast, Consistent Styling
&lt;/h2&gt;

&lt;p&gt;Already using Tailwind in your app? Great! Carry that system into your PDFs. Just inline the CDN or use a local build.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.tailwindcss.com"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"max-w-xl mx-auto bg-white p-6 rounded shadow"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-2xl font-bold mb-4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Invoice&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;table&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"w-full text-sm"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Speed. Utility-first styling is &lt;em&gt;fast&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Reusability. Copy-paste styles from your app.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Caveat:&lt;/strong&gt;&lt;br&gt;
Tailwind must be &lt;strong&gt;inlined&lt;/strong&gt; as external network calls won't work in the PDF engine.&lt;/p&gt;


&lt;h2&gt;
  
  
  📊 Step 3: Add Dynamic Charts with Chart.js
&lt;/h2&gt;

&lt;p&gt;Static reports are fine. But &lt;strong&gt;data-driven PDFs with live charts&lt;/strong&gt;? That's next-level.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;canvas&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"myChart"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/canvas&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Chart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myChart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;getContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...],&lt;/span&gt; &lt;span class="na"&gt;datasets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yes, this renders &lt;em&gt;directly&lt;/em&gt; into your PDF. No screenshotting, no hacks.&lt;/p&gt;

&lt;p&gt;Want to make it dynamic? Use EJS (or any template engine):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;%-&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then inject your data via the reportgen.io API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"html_template"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"myData"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"engine"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ejs"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📄 Learn More: &lt;a href="https://reportgen.io/blog/less-ugly-reports" rel="noopener noreferrer"&gt;Read the Full Guide →&lt;/a&gt;
&lt;/h2&gt;




&lt;h2&gt;
  
  
  🧰 Docs &amp;amp; GitHub reference
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Full Docs: &lt;a href="https://docs.reportgen.io" rel="noopener noreferrer"&gt;docs.reportgen.io&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Code examples: &lt;a href="https://github.com/reportgenio/examples" rel="noopener noreferrer"&gt;github.com/reportgenio/examples&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Final Take
&lt;/h2&gt;

&lt;p&gt;You built a great product. Don't let your PDFs be the weakest link.&lt;/p&gt;

&lt;p&gt;With reportgen.io, you can generate client-ready, visually impressive, dynamic PDFs in minutes, not days.&lt;/p&gt;

&lt;p&gt;Make your output match your quality.&lt;/p&gt;




&lt;p&gt;👉 Ready to make your PDFs not suck? Try it free at reportgen.io&lt;br&gt;
You get 150 reports for free each month, no credit card required.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>productivity</category>
      <category>tutorial</category>
      <category>saas</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Ethan from reportgen.io</dc:creator>
      <pubDate>Wed, 30 Apr 2025 06:52:52 +0000</pubDate>
      <link>https://dev.to/ethan_reportgen/-4anj</link>
      <guid>https://dev.to/ethan_reportgen/-4anj</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/ethan_reportgen/from-html-to-pdf-at-scale-without-subscriptions-limits-or-pain-1ah3" class="crayons-story__hidden-navigation-link"&gt;From HTML to PDF at Scale - Without Subscriptions, Limits, or Pain&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/ethan_reportgen" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3077893%2F19d953fa-46df-4ad8-8175-ebf58625685b.png" alt="ethan_reportgen profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/ethan_reportgen" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Ethan from reportgen.io
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Ethan from reportgen.io
                
              
              &lt;div id="story-author-preview-content-2447865" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/ethan_reportgen" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3077893%2F19d953fa-46df-4ad8-8175-ebf58625685b.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Ethan from reportgen.io&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/ethan_reportgen/from-html-to-pdf-at-scale-without-subscriptions-limits-or-pain-1ah3" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Apr 30 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/ethan_reportgen/from-html-to-pdf-at-scale-without-subscriptions-limits-or-pain-1ah3" id="article-link-2447865"&gt;
          From HTML to PDF at Scale - Without Subscriptions, Limits, or Pain
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/ethan_reportgen/from-html-to-pdf-at-scale-without-subscriptions-limits-or-pain-1ah3" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;5&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/ethan_reportgen/from-html-to-pdf-at-scale-without-subscriptions-limits-or-pain-1ah3#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            3 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Ethan from reportgen.io</dc:creator>
      <pubDate>Wed, 30 Apr 2025 06:12:54 +0000</pubDate>
      <link>https://dev.to/ethan_reportgen/-1pjk</link>
      <guid>https://dev.to/ethan_reportgen/-1pjk</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/ethan_reportgen" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3077893%2F19d953fa-46df-4ad8-8175-ebf58625685b.png" alt="ethan_reportgen"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/ethan_reportgen/from-html-to-pdf-at-scale-without-subscriptions-limits-or-pain-1ah3" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;From HTML to PDF at Scale - Without Subscriptions, Limits, or Pain&lt;/h2&gt;
      &lt;h3&gt;Ethan from reportgen.io ・ Apr 30&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>webdev</category>
      <category>softwaredevelopment</category>
      <category>productivity</category>
    </item>
    <item>
      <title>From HTML to PDF at Scale - Without Subscriptions, Limits, or Pain</title>
      <dc:creator>Ethan from reportgen.io</dc:creator>
      <pubDate>Wed, 30 Apr 2025 05:49:59 +0000</pubDate>
      <link>https://dev.to/ethan_reportgen/from-html-to-pdf-at-scale-without-subscriptions-limits-or-pain-1ah3</link>
      <guid>https://dev.to/ethan_reportgen/from-html-to-pdf-at-scale-without-subscriptions-limits-or-pain-1ah3</guid>
      <description>&lt;p&gt;&lt;strong&gt;Generating PDFs should be simple.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But if you've tried to do it inside a SaaS product, you already know it's anything but. Most APIs lock you into rigid templates, slow render speeds, or bloated subscription plans for what should be a basic developer utility.&lt;/p&gt;

&lt;p&gt;We hit this wall ourselves while building internal tools. We didn’t want to manage Chromium headless rendering ourselves. But every "PDF as a Service" option we found came with restrictions that made no sense:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Subscriptions even if you're only rendering a few reports a month.&lt;/li&gt;
&lt;li&gt;Hard limits on parallel processing or file sizes.&lt;/li&gt;
&lt;li&gt;Poor templating support.&lt;/li&gt;
&lt;li&gt;No async API for high-volume or background batch jobs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So we built &lt;strong&gt;&lt;a href="https://reportgen.io" rel="noopener noreferrer"&gt;Reportgen.io&lt;/a&gt;&lt;/strong&gt; - a simple, scalable, and affordable HTML-to-PDF API with &lt;strong&gt;pay-per-use pricing&lt;/strong&gt;, unlimited parallelism, and built-in storage/CDN.&lt;/p&gt;




&lt;h3&gt;
  
  
  What Makes Reportgen Different
&lt;/h3&gt;

&lt;p&gt;Most PDF APIs are priced like they're serving Fortune 500s. We're not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With Reportgen, you get:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;150 free reports/month&lt;/li&gt;
&lt;li&gt;Just &lt;strong&gt;$0.0025 per PDF&lt;/strong&gt; after that&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No subscriptions&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unlimited parallel jobs&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unlimited file size&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Built-in &lt;strong&gt;Cloudflare CDN&lt;/strong&gt; &amp;amp; &lt;strong&gt;R2 storage&lt;/strong&gt; (1-year retention)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Async and sync APIs&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Templating support for &lt;strong&gt;EJS&lt;/strong&gt;, &lt;strong&gt;Handlebars&lt;/strong&gt;, &lt;strong&gt;Go templates&lt;/strong&gt;, and raw HTML&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We focused on &lt;strong&gt;developer ergonomics and performance at scale&lt;/strong&gt;. Whether you're rendering one-off invoices or 10,000 reports per day, it just works.&lt;/p&gt;




&lt;h3&gt;
  
  
  How It Works
&lt;/h3&gt;

&lt;p&gt;Here’s a basic example using the sync API and Handlebars:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node-fetch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Define the Handlebars template&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;htmlTemplate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
&amp;lt;html&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset="UTF-8"&amp;gt;
    &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&amp;gt;
    &amp;lt;title&amp;gt;Order Confirmation&amp;lt;/title&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;Order Confirmation&amp;lt;/h1&amp;gt;
    &amp;lt;p&amp;gt;Thank you for your order!&amp;lt;/p&amp;gt;
    &amp;lt;p&amp;gt;Order ID: {{orderId}}&amp;lt;/p&amp;gt;
    &amp;lt;p&amp;gt;Date: {{orderDate}}&amp;lt;/p&amp;gt;
    &amp;lt;p&amp;gt;Your order will be shipped soon.&amp;lt;/p&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Define the dynamic data for the Handlebars template&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;templateData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;orderId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;123456789&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;orderDate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;October 7, 2024&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Define the payload for the request&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requestData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;html_template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;htmlTemplate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;templateData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;handlebars&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// API Key&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;apiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_API_KEY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Function to generate PDF using the Fetch API&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;generatePDF&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://reportgen.io/api/v1/generate-pdf-sync&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;X-API-Key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requestData&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Error generating PDF: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusText&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pdfBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;order_confirmation.pdf&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pdfBuffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PDF successfully generated and saved as order_confirmation.pdf&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error generating PDF:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;generatePDF&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can pass raw HTML or use placeholders to inject dynamic data using your preferred engine. Our API supports both &lt;strong&gt;sync (fast, simple)&lt;/strong&gt; and &lt;strong&gt;async (long-running, high-volume)&lt;/strong&gt; operations.&lt;/p&gt;




&lt;h3&gt;
  
  
  Use Cases We See A Lot
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;SaaS platforms generating client invoices, reports, and dashboards&lt;/li&gt;
&lt;li&gt;Marketing teams automating branded proposals&lt;/li&gt;
&lt;li&gt;Backend systems that need contract rendering at scale&lt;/li&gt;
&lt;li&gt;Platforms offering document downloads directly to end users&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Basically, if you’re building an app and need a reliable, zero-maintenance way to generate and host PDFs, you’ll probably love this.&lt;/p&gt;




&lt;h3&gt;
  
  
  Trade-Offs (Yes, We Have Some)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No sandbox/test mode&lt;/strong&gt; yet - we recommend using a separate dev account during early integration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Billing model is new&lt;/strong&gt; - we’re tracking feedback closely, but the pay-per-use is here to stay&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We believe in being transparent. We’d rather earn your trust by showing you where we’re still improving.&lt;/p&gt;




&lt;h3&gt;
  
  
  Try It Free (No Credit Card Needed)
&lt;/h3&gt;

&lt;p&gt;Sign up at &lt;a href="https://reportgen.io" rel="noopener noreferrer"&gt;reportgen.io&lt;/a&gt; and get &lt;strong&gt;150 reports free every month&lt;/strong&gt;. No billing, no nonsense.&lt;/p&gt;

&lt;p&gt;We built this because we were sick of the subscription tax on basic developer tools. If you are too, come try it out and tell us what breaks.&lt;/p&gt;




&lt;p&gt;Questions, feature requests, edge cases? Drop them in the comments or ping us on Twitter.&lt;/p&gt;

&lt;p&gt;Happy rendering.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
