PageSourceSearch

https://docs.polydoc.tech/assets/js/1be9a558.a7ae4193.js

js polydoc.tech collected 2026-10-05 02:04:21 UTC 30,048 bytes, 1 lines download raw bytes

1"use strict";(globalThis.webpackChunkdocumentation=globalThis.webpackChunkdocumentation||[]).push([[4729],{886(e,t,s){s.d(t,{A:()=>n});s(6540);var a=s(4848);const n=({src:e,title:t,className:s="w-full",children:n})=>(0,a.jsx)("a",{href:e,target:"_blank",rel:"noopener",className:`group block cursor-pointer text-left ${s}`,"aria-label":`Open PDF: ${t}`,children:n})},932(e,t,s){s.r(t),s.d(t,{assets:()=>D,contentTitle:()=>T,default:()=>I,frontMatter:()=>A,metadata:()=>a,toc:()=>P});const a=JSON.parse('{"id":"guides/templates","title":"Templates","description":"How PolyDoc templates work, from default vs custom Liquid templates, structure, API usage, and tips for HTML-to-PDF and screenshot payloads.","source":"@site/docs/guides/templates.md","sourceDirName":"guides","slug":"/guides/templates","permalink":"/guides/templates","draft":false,"unlisted":false,"tags":[],"version":"current","sidebarPosition":2,"frontMatter":{"sidebar_position":2,"toc_min_heading_level":2,"toc_max_heading_level":3,"description":"How PolyDoc templates work, from default vs custom Liquid templates, structure, API usage, and tips for HTML-to-PDF and screenshot payloads."},"sidebar":"tutorialSidebar","previous":{"title":"Webhook signature verification","permalink":"/guides/cloud-storage/webhook-signature"},"next":{"title":"CSS Paged Media","permalink":"/guides/css-paged-media/"}}');var n=s(4848),i=s(8453),l=(s(6540),s(6025)),r=s(3323),o=s(3422),d=s(2362),c=s(1811),h=s(886),m=s(4176),p=s(9728),x=s(5693);const u=()=>(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)("p",{children:["When converting HTML to PDF or a screenshot, the"," ",(0,n.jsx)("code",{children:(0,n.jsx)(r.A,{id:"source",children:"source"})})," ","parameter accepts one of three input types:"]}),(0,n.jsxs)("div",{role:"tablist",className:"tabs tabs-lifted mb-1",children:[(0,n.jsx)("input",{type:"radio",name:"source_type_tabs",role:"tab",className:"tab font-normal checked:text-main-500","aria-label":"Template",defaultChecked:!0}),(0,n.jsx)("div",{role:"tabpanel",className:"tab-content bg-base-100 border-base-300 rounded-box p-1 w-full",children:(0,n.jsx)(d.A,{language:"json",children:'{\n  "source": "[template:jlE-whg]",\n  "templateData": {\n    "customer_name": "Jane Smith",\n    "invoice_total": 1320\n  }\n}'})}),(0,n.jsx)("input",{type:"radio",name:"source_type_tabs",role:"tab",className:"tab font-normal checked:text-main-500","aria-label":"Raw HTML"}),(0,n.jsx)("div",{role:"tabpanel",className:"tab-content bg-base-100 border-base-300 rounded-box p-1 w-full",children:(0,n.jsx)(d.A,{language:"json",children:'{\n  "source": "<html><body><h1>Hello World</h1></body></html>"\n}'})}),(0,n.jsx)("input",{type:"radio",name:"source_type_tabs",role:"tab",className:"tab font-normal checked:text-main-500","aria-label":"URL"}),(0,n.jsx)("div",{role:"tabpanel",className:"tab-content bg-base-100 border-base-300 rounded-box p-1 w-full",children:(0,n.jsx)(d.A,{language:"json",children:'{\n  "source": "https://example.com/my-page"\n}'})})]}),(0,n.jsxs)("p",{className:"!mb-2",children:[(0,n.jsx)("strong",{children:"Templates"})," keep the HTML on the server, so your API call only sends the dynamic data. ",(0,n.jsx)("strong",{children:"Raw HTML"})," and"," ",(0,n.jsx)("strong",{children:"URL"})," are simpler: you provide the content directly in every API call."]}),(0,n.jsxs)("p",{className:"!mt-0",children:[(0,n.jsx)("strong",{children:"Where to find the template ID:"})," every template has a short ID. It is shown on the template's card on the"," ",(0,n.jsx)(x.A,{href:"https://dashboard.polydoc.tech/templates",children:"Templates page"})," ","of the dashboard, and the copy icon next to it copies the ID to your clipboard. To use the template, put the ID inside"," ",(0,n.jsx)("code",{children:"[template:...]"})," and pass that as the ",(0,n.jsx)("code",{children:"source"})," ","value. The ID ",(0,n.jsx)("code",{children:"jlE-whg"})," shown below becomes"," ",(0,n.jsx)("code",{children:'"source": "[template:jlE-whg]"'}),"."]}),(0,n.jsx)(c.A,{src:(0,l.Ay)("/img/guides/templates/template-id-dashboard.webp"),alt:"Template card on the dashboard's Templates page, with an arrow pointing at the template's short ID and its copy icon",width:760,height:630,className:"mx-auto mb-3 block h-auto w-full max-w-[16rem] rounded-lg border border-base-300 bg-base-200/40 p-1"}),(0,n.jsxs)(o.A,{children:[(0,n.jsx)("h3",{children:"When to use templates"}),(0,n.jsxs)("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-3 mb-1",children:[(0,n.jsxs)("div",{className:"bg-base-200/60 rounded-lg p-3",children:[(0,n.jsx)("div",{className:"font-semibold text-sm mb-1",children:"Reusable document designs"}),(0,n.jsx)("div",{className:"text-sm text-base-content/75",children:"Define the layout once \u2014 invoice, report, ticket, or any other document type \u2014 and generate as many instances as you need from it."})]}),(0,n.jsxs)("div",{className:"bg-base-200/60 rounded-lg p-3",children:[(0,n.jsx)("div",{className:"font-semibold text-sm mb-1",children:"Dynamic data at render time"}),(0,n.jsxs)("div",{className:"text-sm text-base-content/75",children:["Inject customer names, line items, dates, and totals into the HTML using ",(0,n.jsx)("a",{href:"#liquid-templating",children:"Liquid"})," syntax, without rebuilding HTML in your application on every call."]})]}),(0,n.jsxs)("div",{className:"bg-base-200/60 rounded-lg p-3",children:[(0,n.jsx)("div",{className:"font-semibold text-sm mb-1",children:"Consistent branding"}),(0,n.jsx)("div",{className:"text-sm text-base-content/75",children:"Maintain a single source of truth for headers, footers, and styling across all generated documents."})]}),(0,n.jsxs)("div",{className:"bg-base-200/60 rounded-lg p-3",children:[(0,n.jsx)("div",{className:"font-semibold text-sm mb-1",children:"Smaller API payloads"}),(0,n.jsx)("div",{className:"text-sm text-base-content/75",children:"Send only the variable data instead of the entire HTML document on every request."})]})]})]})]}),b=()=>(0,n.jsxs)(o.A,{children:[(0,n.jsx)("p",{children:"PolyDoc provides two categories of templates:"}),(0,n.jsx)("div",{className:"overflow-x-auto mb-2",children:(0,n.jsxs)("table",{className:"table w-full [&_td]:text-sm [&_th]:text-sm",children:[(0,n.jsx)("thead",{children:(0,n.jsxs)("tr",{children:[(0,n.jsx)("th",{}),(0,n.jsx)("th",{children:"Default (System) Templates"}),(0,n.jsx)("th",{children:"User Templates"})]})}),(0,n.jsxs)("tbody",{children:[(0,n.jsxs)("tr",{children:[(0,n.jsx)("td",{className:"font-semibold",children:"Provided by"}),(0,n.jsx)("td",{children:"PolyDoc"}),(0,n.jsx)("td",{children:"You"})]}),(0,n.jsxs)("tr",{children:[(0,n.jsx)("td",{className:"font-semibold",children:"Editable"}),(0,n.jsx)("td",{children:"No (read-only)"}),(0,n.jsx)("td",{children:"Yes"})]}),(0,n.jsxs)("tr",{children:[(0,n.jsx)("td",{className:"font-semibold",children:"Usable in API calls"}),(0,n.jsx)("td",{children:"Only by short ID, which the dashboard does not show"}),(0,n.jsx)("td",{children:"Yes \u2014 via short ID"})]}),(0,n.jsxs)("tr",{children:[(0,n.jsx)("td",{className:"font-semibold",children:"Stability"}),(0,n.jsx)("td",{children:"May be updated or removed"}),(0,n.jsx)("td",{children:"Stable \u2014 you control changes"})]})]})]})}),(0,n.jsxs)("p",{children:[(0,n.jsx)("strong",{children:"Default templates"})," are starting points, professionally designed examples such as invoices, e-invoices, bank statements, reports, and tickets. They exist so you can see what is possible and get a head start, but they are maintained by PolyDoc and may change at any time."]}),(0,n.jsxs)("p",{children:[(0,n.jsx)("strong",{children:"User templates"})," are your own. Each one receives a unique short ID (e.g. ",(0,n.jsx)("code",{children:"a1b-c2d"}),") that you reference in API calls. You have full control over the content, styles, header, footer, and default options."]})]}),j=()=>(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(m.A,{children:(0,n.jsx)("span",{children:"Duplicate a default template before you reference it in API calls. The dashboard shows no short ID for defaults, and PolyDoc may change or remove them. Your copy is editable, keeps a 
1stable short ID, and is unaffected by those changes."})}),(0,n.jsxs)(o.A,{children:[(0,n.jsx)("p",{children:"You can create a user template in two ways:"}),(0,n.jsxs)("ul",{className:"list-disc list-outside ps-5 marker:text-base-content mb-1",children:[(0,n.jsxs)("li",{children:[(0,n.jsx)("strong",{children:"From scratch"})," \u2014 click ",(0,n.jsx)("strong",{children:"New Template"})," in the"," ",(0,n.jsx)(x.A,{href:"https://dashboard.polydoc.tech",children:"Dashboard"})," ","and build your own HTML, styles, header and footer."]}),(0,n.jsxs)("li",{children:[(0,n.jsx)("strong",{children:"Duplicate a default"})," \u2014 pick a default template and click ",(0,n.jsx)("strong",{children:"Duplicate"}),". This copies the content, styles, header, footer, and default options into a new user template that you can customize."]})]})]})]}),g=[{file:"invoice.pdf",preview:"invoice-preview.png",label:"Invoice"},{file:"e-invoice.pdf",preview:"e-invoice-preview.png",label:"E-Invoice"},{file:"report.pdf",preview:"report-preview.png",label:"Report"},{file:"ticket.pdf",preview:"ticket-preview.png",label:"Ticket"},{file:"bank-statement.pdf",preview:"bank-statement-preview.png",label:"Bank statement"}],f=()=>{const e=(0,l.Ay)("/template-examples/email-banner.png"),t=(0,l.Ay)("/template-examples/invoice.pdf"),s=(0,l.Ay)("/template-examples/e-invoice.pdf"),a=(0,l.Ay)("/template-examples/bank-statement.pdf"),i=(0,l.Ay)("/template-examples/report.pdf"),r=(0,l.Ay)("/template-examples/ticket.pdf"),d=(0,l.Ay)("/template-examples/invoice-preview.png"),m=(0,l.Ay)("/template-examples/e-invoice-preview.png"),p=(0,l.Ay)("/template-examples/bank-statement-preview.png"),x=(0,l.Ay)("/template-examples/report-preview.png"),u=(0,l.Ay)("/template-examples/ticket-preview.png"),b={"invoice.pdf":t,"e-invoice.pdf":s,"bank-statement.pdf":a,"report.pdf":i,"ticket.pdf":r},j={"invoice-preview.png":d,"e-invoice-preview.png":m,"bank-statement-preview.png":p,"report-preview.png":x,"ticket-preview.png":u};return(0,n.jsxs)(o.A,{children:[(0,n.jsx)("p",{className:"text-sm text-base-content/80 mb-4",children:"Sample exports from the default templates (placeholder data). Previews show the first page of each PDF; click to open the full file."}),(0,n.jsxs)("div",{className:"grid grid-cols-2 sm:grid-cols-3 gap-4",children:[g.map(({file:e,preview:t,label:s})=>(0,n.jsxs)("div",{className:"min-w-0 flex flex-col",children:[(0,n.jsx)(h.A,{src:b[e],title:`${s} \u2014 sample PDF`,children:(0,n.jsx)("img",{src:j[t],alt:`${s} \u2014 first page preview`,width:433,height:560,className:"mx-auto block h-[8.5rem] w-full rounded-lg border border-base-300 bg-base-200/40 object-contain object-top p-0.5 transition group-hover:border-main-400/40 group-hover:bg-base-200/70",loading:"lazy",decoding:"async"})}),(0,n.jsxs)("div",{className:"mt-2 flex flex-col items-center gap-1",children:[(0,n.jsx)("span",{className:"text-center text-sm font-medium text-base-content",children:s}),(0,n.jsx)("span",{className:"badge badge-sm border-0 bg-base-300/50 font-medium text-xs text-base-content/65",children:"PDF"})]})]},e)),(0,n.jsxs)("div",{className:"min-w-0 flex flex-col",children:[(0,n.jsx)(c.A,{src:e,alt:"Email banner \u2014 sample PNG output from the default email banner template",width:600,height:120,className:"mx-auto block h-[8.5rem] w-full rounded-lg border border-base-300 bg-base-200/40 object-contain object-center p-2 transition group-hover:border-main-400/40 group-hover:bg-base-200/70"}),(0,n.jsxs)("div",{className:"mt-2 flex flex-col items-center gap-1",children:[(0,n.jsx)("span",{className:"text-center text-sm font-medium text-base-content",children:"Email banner"}),(0,n.jsx)("span",{className:"badge badge-sm border-0 bg-base-300/50 font-medium text-xs text-base-content/65",children:"Screenshot"})]})]})]})]})},v=()=>(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)(o.A,{children:[(0,n.jsx)("p",{children:"Every template consists of up to four parts:"}),(0,n.jsx)("div",{className:"overflow-x-auto mb-2",children:(0,n.jsxs)("table",{className:"table w-full [&_td]:text-sm [&_th]:text-sm",children:[(0,n.jsx)("thead",{children:(0,n.jsxs)("tr",{children:[(0,n.jsx)("th",{children:"Part"}),(0,n.jsx)("th",{children:"Purpose"}),(0,n.jsx)("th",{children:"Applies to"})]})}),(0,n.jsxs)("tbody",{children:[(0,n.jsxs)("tr",{children:[(0,n.jsx)("td",{className:"font-semibold",children:"Content"}),(0,n.jsx)("td",{children:"Main HTML body of the document"}),(0,n.jsx)("td",{children:"PDF + Screenshot"})]}),(0,n.jsxs)("tr",{children:[(0,n.jsx)("td",{className:"font-semibold",children:"Header"}),(0,n.jsx)("td",{children:"HTML shown at the top of every PDF page"}),(0,n.jsx)("td",{children:"PDF only"})]}),(0,n.jsxs)("tr",{children:[(0,n.jsx)("td",{className:"font-semibold",children:"Footer"}),(0,n.jsx)("td",{children:"HTML shown at the bottom of every PDF page"}),(0,n.jsx)("td",{children:"PDF only"})]}),(0,n.jsxs)("tr",{children:[(0,n.jsx)("td",{className:"font-semibold",children:"Styles"}),(0,n.jsx)("td",{children:"CSS applied to the main content"}),(0,n.jsx)("td",{children:"PDF + Screenshot"})]})]})]})}),(0,n.jsxs)("p",{children:["Additionally, each template can define ",(0,n.jsx)("strong",{children:"Default Options"})," ","\u2014 a JSON object with default API parameters (margins, page format, viewport size, etc.). These are merged with the options you send in each request, where ",(0,n.jsx)("strong",{children:"request-level values take priority"}),"."]})]}),(0,n.jsxs)(o.A,{children:[(0,n.jsx)("h3",{children:"Header and Footer (PDF only)"}),(0,n.jsx)("p",{children:"Headers and footers are rendered by the browser's print engine in a separate context from the main content. This has a few important implications:"}),(0,n.jsxs)("ul",{className:"list-disc list-outside ps-5 marker:text-base-content mb-2",children:[(0,n.jsxs)("li",{children:["They do ",(0,n.jsx)("strong",{children:"not"})," share CSS with the main content. Any styles you need in the header or footer must be defined as inline"," ",(0,n.jsx)("code",{children:"<style>"})," blocks within the header/footer HTML itself."]}),(0,n.jsxs)("li",{children:["Header and footer ",(0,n.jsx)("strong",{children:"do"})," share styles with each other \u2014 a"," ",(0,n.jsx)("code",{children:"<style>"})," block in the header is also available in the footer, and vice versa."]}),(0,n.jsxs)("li",{children:["Header/footer styles are ",(0,n.jsx)("strong",{children:"not"})," subject to Content Security Policy (CSP) restrictions, so inline styles always work."]}),(0,n.jsxs)("li",{children:["When using headers or footers, you need to account for their height in y
1our page margins. For example, an invoice header of approximately 2.5 inches requires setting"," ",(0,n.jsx)("code",{children:'"layout": { "margin": { "top": "2.8in" } }'})," to prevent content from overlapping."]})]}),(0,n.jsxs)(p.A,{children:["The browser provides special CSS classes for page numbering inside headers and footers: ",(0,n.jsx)("code",{children:'<span class="pageNumber"></span>'})," ","and ",(0,n.jsx)("code",{children:'<span class="totalPages"></span>'}),". These only work in header/footer HTML, not in the main content."]}),(0,n.jsx)("h3",{className:"mt-4",children:"Examples"}),(0,n.jsxs)("div",{role:"tablist",className:"tabs tabs-lifted",children:[(0,n.jsx)("input",{type:"radio",name:"header_footer_tabs",role:"tab",className:"tab font-normal checked:text-main-500","aria-label":"Header",defaultChecked:!0}),(0,n.jsxs)("div",{role:"tabpanel",className:"tab-content bg-base-100 border-base-300 rounded-box p-1 w-full",children:[(0,n.jsxs)("p",{className:"px-2 pt-2 pb-1 text-sm",children:["This header shows the company logo, address, invoice details, and page numbers. Note the inline ",(0,n.jsx)("code",{children:"<style>"})," block \u2014 required because the header does not inherit styles from the main content."]}),(0,n.jsx)(d.A,{language:"html",children:'<html>\n  <head>\n    <style>\n      body { font-family: "Open Sans", sans-serif; }\n      * { font-size: 16px; }\n      .header { margin: 1cm 1cm 0; }\n      .flex { display: flex; }\n      .justify-between { justify-content: space-between; }\n      .text-xs, .text-xs * { font-size: 0.75rem; }\n      /* ... more utility classes as needed ... */\n    </style>\n  </head>\n  <body>\n    <div class="header flex justify-between">\n      <div>\n        <img src="data:image/svg+xml;base64,..." />\n        <div>Acme Inc.</div>\n        <div class="text-xs">123 Main St, Anytown, USA</div>\n      </div>\n      <div>\n        <div>Invoice</div>\n        <div class="text-xs">\n          Page: <span class="pageNumber"></span>\n          of <span class="totalPages"></span>\n        </div>\n      </div>\n    </div>\n  </body>\n</html>'})]}),(0,n.jsx)("input",{type:"radio",name:"header_footer_tabs",role:"tab",className:"tab font-normal checked:text-main-500","aria-label":"Footer"}),(0,n.jsxs)("div",{role:"tabpanel",className:"tab-content bg-base-100 border-base-300 rounded-box p-1 w-full",children:[(0,n.jsx)("p",{className:"px-2 pt-2 pb-1 text-sm",children:"A simple footer strip with company info. It automatically appears at the bottom of every page."}),(0,n.jsx)(d.A,{language:"html",children:'<html>\n  <body>\n    <div style="display: flex; justify-content: center;\n                border-top: 1px solid #e0e0e0;\n                padding-top: 0.75rem; margin-top: 0.75rem;\n                font-size: 0.625rem; color: #99a1af; gap: 0.5rem;">\n      Acme Inc. \xb7 123 Main St \xb7 Anytown, USA\n      <div style="border-left: 1px solid #99a1af;\n                  border-right: 1px solid #99a1af;\n                  padding: 0 0.5rem; margin: 0 0.5rem;">\n        <a href="https://www.acme-inc.com">www.acme-inc.com</a>\n      </div>\n      VAT: 1234567890\n    </div>\n  </body>\n</html>'})]})]})]})]}),y=()=>(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)(o.A,{children:[(0,n.jsxs)("p",{children:["To use a template, set the"," ",(0,n.jsx)("code",{children:(0,n.jsx)(r.A,{id:"source",children:"source"})})," ","parameter to a template reference in the format"," ",(0,n.jsx)("code",{children:"[template:xxx-yyy]"}),", where ",(0,n.jsx)("code",{children:"xxx-yyy"})," is the template's short ID. You can find the short ID on the"," ",(0,n.jsx)(x.A,{href:"https://dashboard.polydoc.tech/templates",children:"Templates page"})," ","of the dashboard."]}),(0,n.jsxs)("p",{className:"mb-1",children:["Pass dynamic values through the ",(0,n.jsx)("code",{children:"templateData"})," object. Every key in ",(0,n.jsx)("code",{children:"templateData"})," becomes available as a Liquid variable inside the template."]}),(0,n.jsx)(d.A,{language:"json",children:'{\n  "source": "[template:a1b-c2d]",\n  "templateData": {\n    "invoice_number": "INV-2026-042",\n    "invoice_date": "2026-03-15",\n    "invoice_due_date": "2026-04-14",\n    "customer_name": "Jane Smith",\n    "customer_street": "789 Oak Avenue",\n    "customer_city": "Springfield",\n    "customer_country": "US",\n    "invoice_subtotal": 1500,\n    "invoice_tax_rate": 0.08,\n    "invoice_tax_amount": 120,\n    "invoice_total": 1620,\n    "items": [\n      {\n        "quantity": 5,\n        "name": "Consulting Hours",\n        "description": "Technical architecture review",\n        "price": 200\n      },\n      {\n        "quantity": 1,\n        "name": "Project Setup",\n        "price": 500\n      }\n    ]\n  }\n}'})]}),(0,n.jsxs)(o.A,{children:[(0,n.jsx)("h3",{children:"Option merging"}),(0,n.jsx)("p",{children:"Templates can store default options such as page margins, format, or viewport dimensions. When you make an API request, the options are merged in this order:"}),(0,n.jsxs)("ol",{className:"list-decimal list-outside ps-5 marker:text-base-content mb-1",children:[(0,n.jsxs)("li",{children:[(0,n.jsx)("strong",{children:"Template defaults"})," are applied first (e.g., margins defined in the template's Options tab)."]}),(0,n.jsxs)("li",{children:[(0,n.jsx)("strong",{children:"Request-level options"})," override any matching template defaults."]})]}),(0,n.jsxs)("p",{className:"mb-1",children:["For example, if a template defines"," ",(0,n.jsx)("code",{children:'"layout": { "margin": { "top": "2.8in" } }'})," and your request also specifies"," ",(0,n.jsxs)("code",{children:["layout.margin.",(0,n.jsx)(r.A,{id:"top",children:"top"})]}),", the request value wins. Options not specified in the request fall back to the template defaults."]}),(0,n.jsx)(p.A,{children:"This means you can set sensible defaults in the template (like margins that account for your header height) and only override what changes per request."})]})]}),w=()=>{const e=(0,l.Ay)("/guides/compliance/e-invoice");return(0,n.jsxs)(o.A,{children:[(0,n.jsxs)("p",{children:["One default template behaves differently from the rest: the built-in"," ",(0,n.jsx)("strong",{children:"E-Invoice"})," template, the starting point for compliant ZUGFeRD and Factur-X invoices. When you send an ",(0,n.jsx)("code",{children:"eInvoice"})," ","payload, its ",(0,n.jsx)("code",{children:"invoice"})," object replaces"," ",(0,n.jsx)("code",{children:"templateData.invoice"}),", so the visible PDF and the embedded machine-readable XML are always generated from the same data and can never disagree."]}),(0,n.jsxs)("p",{className:"!mb-0",children:["Everything else on this page still applies: you duplicate it, edit the content, header, footer, and styles, and reference it by short ID. The full data flow, the sibling ",(0,n.jsx)("code",{children:"templateData.company"})," key for statutory footer details, and a step-by-step walkthrough live in the"," ",(0,n.jsx)("a",{href:e,children:"e-invoice guide"}),"."]})]})},N=()=>(0,n.jsx)(n.Fragment,{children:(0,n.jsxs)(o.A,{children:[(0,n.jsxs)("p",{children:["Templates use"," ",(0,n.jsx)(x.A,{href:"https://liquidjs.com",children:"Liquid"})," as their templating language. Every key in the ",(0,n.jsx)("code",{children:"templateData"})," object you send with the API request becomes a variable you can reference in the template's content, header, and footer."]}),(0,n.jsxs)("div",{role:"tablist",className:"tabs tabs-lifted mt-3",children:[(0,n.jsx)("input",{type:"radio",name:"liquid_tabs",role:"tab",className:"tab font-normal checked:text-main-500","aria-label":"Variables",defaultChecked:!0}),(0,n.jsxs)("div",{role:"tabpanel",className:"tab-content bg-base-100 border-base-300 rounded-box p-1 w-full",children:[(0,n.jsx)("p",{className:"px-2 pt-2 pb-1 text-sm",children:"Output a value with double curly braces. Dot notation accesses nested properties."}),(0,n.jsx)(d.A,{language:"html",children:"\x3c!-- Simple variable --\x3e\n<h1>Invoice {{ invoice_number }}</h1>\n\n\x3c!-- Nested property --\x3e\n<td>{{ item.name }}</td>\n\n\x3c!-- Combining variables --\x3e\n<div>{{ customer_name }}, {{ customer_city }}</div>"})]}),(0,n.jsx)("input",{type:"radio",name:"liquid_tabs",role:"tab",className:"tab font-normal checked:text-main-500","aria-label":"Loops"}),(0,n.jsxs)("div",{role:"tabpanel",className:"tab-content bg-base-100 border-base-300 rounded-box p-1 w-full",children:[(0,n.jsxs)("p",{className:"px-2 pt-2 pb-1 text-sm",children:["Iterate over arrays with ",(0,n.jsx)("code",{children:"{% for %}"}),". This is the core pattern for rendering line items, transactions, or any list of records. The example below \u2014 from the invoice template \u2014 loops over an ",(0,n.jsx)("code",{children:"items"})," array and renders a table row per line item, including an optional description and computed total."]}),(0,n.jsx)(d.A,{language:"html",children:'{% for item in items %}\n<tr>\n  <td>{{ item.quantity }}</td>\n  <td>\n    <div>{{ item.name }}</div>\n    {% if item.description %}\n    <div class="text-gray-400">{{ item.description }}</div>\n    {% endif %}\n  </td>\n  <td>${{ item.price | round: 2 }}</td>\n  <td>
1${{ item.price | times: item.quantity | round: 2 }}</td>\n</tr>\n{% endfor %}'})]}),(0,n.jsx)("input",{type:"radio",name:"liquid_tabs",role:"tab",className:"tab font-normal checked:text-main-500","aria-label":"Conditionals"}),(0,n.jsxs)("div",{role:"tabpanel",className:"tab-content bg-base-100 border-base-300 rounded-box p-1 w-full",children:[(0,n.jsxs)("p",{className:"px-2 pt-2 pb-1 text-sm",children:["Use ",(0,n.jsx)("code",{children:"{% if %}"})," to show or hide content based on the data. You can also check string content with ",(0,n.jsx)("code",{children:"contains"}),"."]}),(0,n.jsx)(d.A,{language:"html",children:'\x3c!-- Show a field only when present --\x3e\n{% if item.description %}\n<div class="text-gray-400">{{ item.description }}</div>\n{% endif %}\n\n\x3c!-- Check string content (e.g. negative amounts in a bank statement) --\x3e\n{% if transaction.amount contains "-" %}\n<span class="text-red-500">{{ transaction.amount }}</span>\n{% else %}\n<span class="text-green-500">+{{ transaction.amount }}</span>\n{% endif %}'})]}),(0,n.jsx)("input",{type:"radio",name:"liquid_tabs",role:"tab",className:"tab font-normal checked:text-main-500","aria-label":"Filters"}),(0,n.jsxs)("div",{role:"tabpanel",className:"tab-content bg-base-100 border-base-300 rounded-box p-1 w-full",children:[(0,n.jsxs)("p",{className:"px-2 pt-2 pb-1 text-sm",children:["Filters transform values using the pipe (",(0,n.jsx)("code",{children:"|"}),") operator. Multiple filters can be chained."]}),(0,n.jsx)(d.A,{language:"html",children:'\x3c!-- Math: round, multiply --\x3e\n${{ item.price | round: 2 }}\n${{ item.price | times: item.quantity | round: 2 }}\nTax ({{ invoice_tax_rate | times: 100 }}%)\n\n\x3c!-- Dates: format a date string --\x3e\n{{ invoice_date | date: "%B %d, %Y" }}\n{{- "- Output: March 15, 2026" }}\n\n{{ transaction.booking_date | date: "%m/%d" }}\n{{- "- Output: 03/15" }}\n\n\x3c!-- Default: fallback when a value is missing --\x3e\n{{ notes | default: "No additional notes" }}'})]})]})]})}),k=()=>(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(p.A,{children:(0,n.jsxs)("span",{children:[(0,n.jsx)("strong",{children:"Prevent page-break issues"})," \u2014 add"," ",(0,n.jsx)("code",{children:"break-inside-avoid"})," to table rows or any block that should not be split across PDF pages:"," ",(0,n.jsx)("code",{children:'<tr class="break-inside-avoid">'}),"."]})}),(0,n.jsx)(p.A,{children:(0,n.jsxs)("span",{children:[(0,n.jsx)("strong",{children:"Set margins to match your header/footer height"})," \u2014 if your header is roughly 2.5 inches tall, set"," ",(0,n.jsx)("code",{children:'"margin": { "top": "2.8in" }'})," in the template's default options. Without enough top margin, the main content will overlap with the header."]})}),(0,n.jsx)(p.A,{children:(0,n.jsxs)("span",{children:[(0,n.jsx)("strong",{children:"Inline images in headers/footers with data URIs"})," \u2014 since header and footer HTML is rendered in an isolated context, external image URLs may not load reliably. Encode logos and icons as"," ",(0,n.jsx)("code",{children:"data:image/svg+xml;base64,..."})," or"," ",(0,n.jsx)("code",{children:"data:image/png;base64,..."})," for consistent results."]})}),(0,n.jsx)(p.A,{children:(0,n.jsxs)("span",{children:[(0,n.jsx)("strong",{children:"Preview before integrating"})," \u2014 use the template preview in the"," ",(0,n.jsx)(x.A,{href:"https://dashboard.polydoc.tech",children:"Dashboard"})," ","to see exactly how your template renders before wiring it into your API integration."]})}),(0,n.jsx)(p.A,{children:(0,n.jsxs)("span",{children:[(0,n.jsx)("strong",{children:"Keep templateData flat when possible"})," \u2014 simple top-level keys like ",(0,n.jsx)("code",{children:"{{ customer_name }}"})," are easier to work with than deeply nested objects. Use arrays (like ",(0,n.jsx)("code",{children:"items"}),") only when you need to loop over them."]})})]}),A={sidebar_position:2,toc_min_heading_level:2,toc_max_heading_level:3,description:"How PolyDoc templates work, from default vs custom Liquid templates, structure, API usage, and tips for HTML-to-PDF and screenshot payloads."},T="Templates",D={},P=[{value:"Introduction",id:"introduction",level:2}
1,{value:"Default vs User Templates",id:"default-vs-user-templates",level:2},{value:"Built-in template examples",id:"built-in-template-examples",level:2},{value:"Duplicating and creating templates",id:"duplicating-and-creating-templates",level:2},{value:"Template Structure",id:"template-structure",level:2},{value:"Using Templates via API",id:"using-templates-via-api",level:2},{value:"The E-Invoice template",id:"the-e-invoice-template",level:2},{value:"Liquid Templating",id:"liquid-templating",level:2},{value:"Tips and Best Practices",id:"tips-and-best-practices",level:2}];function _(e){const t={h1:"h1",h2:"h2",header:"header",...(0,i.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.header,{children:(0,n.jsx)(t.h1,{id:"templates",children:"Templates"})}),"\n",(0,n.jsx)(t.h2,{id:"introduction",children:"Introduction"}),"\n",(0,n.jsx)(u,{}),"\n",(0,n.jsx)(t.h2,{id:"default-vs-user-templates",children:"Default vs User Templates"}),"\n",(0,n.jsx)(b,{}),"\n",(0,n.jsx)(t.h2,{id:"built-in-template-examples",children:"Built-in template examples"}),"\n",(0,n.jsx)(f,{}),"\n",(0,n.jsx)(t.h2,{id:"duplicating-and-creating-templates",children:"Duplicating and creating templates"}),"\n",(0,n.jsx)(j,{}),"\n",(0,n.jsx)(t.h2,{id:"template-structure",children:"Template Structure"}),"\n",(0,n.jsx)(v,{}),"\n",(0,n.jsx)(t.h2,{id:"using-templates-via-api",children:"Using Templates via API"}),"\n",(0,n.jsx)(y,{}),"\n",(0,n.jsx)(t.h2,{id:"the-e-invoice-template",children:"The E-Invoice template"}),"\n",(0,n.jsx)(w,{}),"\n",(0,n.jsx)(t.h2,{id:"liquid-templating",children:"Liquid Templating"}),"\n",(0,n.jsx)(N,{}),"\n",(0,n.jsx)(t.h2,{id:"tips-and-best-practices",children:"Tips and Best Practices"}),"\n",(0,n.jsx)(k,{})]})}function I(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(_,{...e})}):_(e)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.