[{"data":1,"prerenderedAt":829},["ShallowReactive",2],{"guide-\u002Fdocs\u002Fguides\u002Fauthoring\u002Fhandlebars":3,"guides-all":761},{"id":4,"title":5,"body":6,"category":752,"description":753,"extension":754,"icon":755,"meta":756,"navigation":147,"order":47,"path":757,"seo":758,"stem":759,"__hash__":760},"guides\u002Fdocs\u002Fguides\u002Fauthoring\u002Fhandlebars.md","Handlebars cheat sheet",{"type":7,"value":8,"toc":736},"minimark",[9,13,30,34,81,109,113,167,197,256,260,304,311,396,430,434,459,470,474,483,486,490,499,503,518,525,529,546,549,553,558,577,581,587,596,623,627,630,701,710,714,732],[10,11,5],"h1",{"id":12},"handlebars-cheat-sheet",[14,15,16,17,24,25,29],"p",{},"Transactional uses ",[18,19,23],"a",{"href":20,"rel":21},"https:\u002F\u002Fhandlebarsjs.com\u002F",[22],"nofollow","Handlebars.js"," to interpolate your ",[26,27,28],"code",{},"variables"," into the template's HTML before rendering to PDF. This page is the short, opinionated subset that actually works in our sandbox.",[31,32,33],"h2",{"id":28},"Variables",[35,36,41],"pre",{"className":37,"code":38,"language":39,"meta":40,"style":40},"language-handlebars shiki shiki-themes github-light github-dark","{{ name }}              — escaped (safe by default)\n{{{ raw }}}              — unescaped (only when you really want HTML)\n{{ customer.name }}      — nested path\n{{ ..\u002Fparent }}          — go up one scope\n{{ [key with spaces] }}  — bracketed key\n{{ this }}               — current context (useful inside #each)\n","handlebars","",[26,42,43,51,57,63,69,75],{"__ignoreMap":40},[44,45,48],"span",{"class":46,"line":47},"line",1,[44,49,50],{},"{{ name }}              — escaped (safe by default)\n",[44,52,54],{"class":46,"line":53},2,[44,55,56],{},"{{{ raw }}}              — unescaped (only when you really want HTML)\n",[44,58,60],{"class":46,"line":59},3,[44,61,62],{},"{{ customer.name }}      — nested path\n",[44,64,66],{"class":46,"line":65},4,[44,67,68],{},"{{ ..\u002Fparent }}          — go up one scope\n",[44,70,72],{"class":46,"line":71},5,[44,73,74],{},"{{ [key with spaces] }}  — bracketed key\n",[44,76,78],{"class":46,"line":77},6,[44,79,80],{},"{{ this }}               — current context (useful inside #each)\n",[14,82,83,84,87,88,91,92,91,95,91,98,91,101,104,105,108],{},"Escape rules: ",[26,85,86],{},"{{ x }}"," HTML-escapes ",[26,89,90],{},"\u003C",", ",[26,93,94],{},">",[26,96,97],{},"&",[26,99,100],{},"\"",[26,102,103],{},"'",". Use the triple-stash form ",[26,106,107],{},"{{{ x }}}"," only when the variable already contains HTML you trust.",[31,110,112],{"id":111},"conditionals","Conditionals",[35,114,116],{"className":37,"code":115,"language":39,"meta":40,"style":40},"{{#if paid}}\n  \u003Cspan class=\"text-emerald-600\">PAID\u003C\u002Fspan>\n{{else}}\n  \u003Cspan class=\"text-rose-600\">DUE\u003C\u002Fspan>\n{{\u002Fif}}\n\n{{#unless trial}}\n  \u003Cp>Billing starts next cycle.\u003C\u002Fp>\n{{\u002Funless}}\n",[26,117,118,123,128,133,138,143,149,155,161],{"__ignoreMap":40},[44,119,120],{"class":46,"line":47},[44,121,122],{},"{{#if paid}}\n",[44,124,125],{"class":46,"line":53},[44,126,127],{},"  \u003Cspan class=\"text-emerald-600\">PAID\u003C\u002Fspan>\n",[44,129,130],{"class":46,"line":59},[44,131,132],{},"{{else}}\n",[44,134,135],{"class":46,"line":65},[44,136,137],{},"  \u003Cspan class=\"text-rose-600\">DUE\u003C\u002Fspan>\n",[44,139,140],{"class":46,"line":71},[44,141,142],{},"{{\u002Fif}}\n",[44,144,145],{"class":46,"line":77},[44,146,148],{"emptyLinePlaceholder":147},true,"\n",[44,150,152],{"class":46,"line":151},7,[44,153,154],{},"{{#unless trial}}\n",[44,156,158],{"class":46,"line":157},8,[44,159,160],{},"  \u003Cp>Billing starts next cycle.\u003C\u002Fp>\n",[44,162,164],{"class":46,"line":163},9,[44,165,166],{},"{{\u002Funless}}\n",[14,168,169,173,174,177,178,91,181,91,184,91,187,91,190,91,193,196],{},[170,171,172],"strong",{},"Falsy values"," (the ",[26,175,176],{},"else"," branch runs): ",[26,179,180],{},"false",[26,182,183],{},"null",[26,185,186],{},"undefined",[26,188,189],{},"0",[26,191,192],{},"\"\"",[26,194,195],{},"[]",".",[198,199,212,229],"aside",{"className":200},[201,202,203,204,205,206,207,208,209,210,211],"not-prose","my-6","rounded-md","border","border-amber-200","bg-amber-50","text-amber-900","px-4","py-3","text-[14px]","leading-relaxed",[14,213,214,228],{},[170,215,216,217,220,221,220,224,227],{},"No ",[26,218,219],{},"eq"," \u002F ",[26,222,223],{},"and",[26,225,226],{},"or"," helpers."," Stock Handlebars doesn't ship them. Workarounds:",[230,231,232,243,249],"ul",{},[233,234,235,236,238,239,242],"li",{},"Pre-compute the boolean in your ",[26,237,28],{}," (e.g. send ",[26,240,241],{},"\"isPaid\": true"," rather than expecting Handlebars to compare).",[233,244,245,246,196],{},"Invert with ",[26,247,248],{},"#unless",[233,250,251,252,255],{},"Nest ",[26,253,254],{},"#if"," blocks for AND.",[31,257,259],{"id":258},"loops","Loops",[35,261,263],{"className":37,"code":262,"language":39,"meta":40,"style":40},"{{#each items}}\n  \u003Cdiv class=\"flex justify-between\">\n    \u003Cspan>{{label}}\u003C\u002Fspan>\n    \u003Cspan>{{amount}} €\u003C\u002Fspan>\n  \u003C\u002Fdiv>\n{{else}}\n  \u003Cp>No items.\u003C\u002Fp>\n{{\u002Feach}}\n",[26,264,265,270,275,280,285,290,294,299],{"__ignoreMap":40},[44,266,267],{"class":46,"line":47},[44,268,269],{},"{{#each items}}\n",[44,271,272],{"class":46,"line":53},[44,273,274],{},"  \u003Cdiv class=\"flex justify-between\">\n",[44,276,277],{"class":46,"line":59},[44,278,279],{},"    \u003Cspan>{{label}}\u003C\u002Fspan>\n",[44,281,282],{"class":46,"line":65},[44,283,284],{},"    \u003Cspan>{{amount}} €\u003C\u002Fspan>\n",[44,286,287],{"class":46,"line":71},[44,288,289],{},"  \u003C\u002Fdiv>\n",[44,291,292],{"class":46,"line":77},[44,293,132],{},[44,295,296],{"class":46,"line":151},[44,297,298],{},"  \u003Cp>No items.\u003C\u002Fp>\n",[44,300,301],{"class":46,"line":157},[44,302,303],{},"{{\u002Feach}}\n",[14,305,306,307,310],{},"Inside ",[26,308,309],{},"#each",", special variables are available:",[312,313,314,327],"table",{},[315,316,317],"thead",{},[318,319,320,324],"tr",{},[321,322,323],"th",{},"Variable",[321,325,326],{},"Value",[328,329,330,341,351,361,374,386],"tbody",{},[318,331,332,338],{},[333,334,335],"td",{},[26,336,337],{},"{{this}}",[333,339,340],{},"The current item",[318,342,343,348],{},[333,344,345],{},[26,346,347],{},"{{@index}}",[333,349,350],{},"0-based position",[318,352,353,358],{},[333,354,355],{},[26,356,357],{},"{{@key}}",[333,359,360],{},"The key, when iterating over an object",[318,362,363,368],{},[333,364,365],{},[26,366,367],{},"{{@first}}",[333,369,370,373],{},[26,371,372],{},"true"," for the first iteration",[318,375,376,381],{},[333,377,378],{},[26,379,380],{},"{{@last}}",[333,382,383,385],{},[26,384,372],{}," for the last iteration",[318,387,388,393],{},[333,389,390],{},[26,391,392],{},"{{..\u002Fx}}",[333,394,395],{},"Access the parent scope",[35,397,399],{"className":37,"code":398,"language":39,"meta":40,"style":40},"{{#each lineItems}}\n  \u003Ctr class=\"{{#if @last}}border-b-2{{else}}border-b{{\u002Fif}}\">\n    \u003Ctd>{{label}}\u003C\u002Ftd>\n    \u003Ctd>{{..\u002Fcurrency}} {{amount}}\u003C\u002Ftd>\n  \u003C\u002Ftr>\n{{\u002Feach}}\n",[26,400,401,406,411,416,421,426],{"__ignoreMap":40},[44,402,403],{"class":46,"line":47},[44,404,405],{},"{{#each lineItems}}\n",[44,407,408],{"class":46,"line":53},[44,409,410],{},"  \u003Ctr class=\"{{#if @last}}border-b-2{{else}}border-b{{\u002Fif}}\">\n",[44,412,413],{"class":46,"line":59},[44,414,415],{},"    \u003Ctd>{{label}}\u003C\u002Ftd>\n",[44,417,418],{"class":46,"line":65},[44,419,420],{},"    \u003Ctd>{{..\u002Fcurrency}} {{amount}}\u003C\u002Ftd>\n",[44,422,423],{"class":46,"line":71},[44,424,425],{},"  \u003C\u002Ftr>\n",[44,427,428],{"class":46,"line":77},[44,429,303],{},[31,431,433],{"id":432},"with-change-scope","With (change scope)",[35,435,437],{"className":37,"code":436,"language":39,"meta":40,"style":40},"{{#with customer}}\n  \u003Cp>{{name}}\u003C\u002Fp>\n  \u003Cp>{{address.line1}}\u003C\u002Fp>\n{{\u002Fwith}}\n",[26,438,439,444,449,454],{"__ignoreMap":40},[44,440,441],{"class":46,"line":47},[44,442,443],{},"{{#with customer}}\n",[44,445,446],{"class":46,"line":53},[44,447,448],{},"  \u003Cp>{{name}}\u003C\u002Fp>\n",[44,450,451],{"class":46,"line":59},[44,452,453],{},"  \u003Cp>{{address.line1}}\u003C\u002Fp>\n",[44,455,456],{"class":46,"line":65},[44,457,458],{},"{{\u002Fwith}}\n",[14,460,461,462,465,466,469],{},"Equivalent to writing ",[26,463,464],{},"{{customer.name}}"," and ",[26,467,468],{},"{{customer.address.line1}}",", but cleaner when you're inside one nested object for a while.",[31,471,473],{"id":472},"lookup","Lookup",[35,475,477],{"className":37,"code":476,"language":39,"meta":40,"style":40},"{{lookup data key}}\n",[26,478,479],{"__ignoreMap":40},[44,480,481],{"class":46,"line":47},[44,482,476],{},[14,484,485],{},"Used to access a property whose key is itself a variable. Rare in print templates — usually you can restructure the data instead.",[31,487,489],{"id":488},"comments","Comments",[35,491,493],{"className":37,"code":492,"language":39,"meta":40,"style":40},"{{!-- this is a comment, won't render --}}\n",[26,494,495],{"__ignoreMap":40},[44,496,497],{"class":46,"line":47},[44,498,492],{},[31,500,502],{"id":501},"whitespace-control","Whitespace control",[35,504,506],{"className":37,"code":505,"language":39,"meta":40,"style":40},"{{~ trim }}     — strip whitespace before\n{{ trim ~}}     — strip whitespace after\n",[26,507,508,513],{"__ignoreMap":40},[44,509,510],{"class":46,"line":47},[44,511,512],{},"{{~ trim }}     — strip whitespace before\n",[44,514,515],{"class":46,"line":53},[44,516,517],{},"{{ trim ~}}     — strip whitespace after\n",[14,519,520,521,524],{},"Mostly useful inside ",[26,522,523],{},"\u003Cpre>"," or where leading\u002Ftrailing whitespace would matter. PDFs rarely care.",[31,526,528],{"id":527},"what-transactional-adds-on-top","What Transactional adds on top",[14,530,531,532,535,536,539,540,543,544,196],{},"Nothing. We do ",[170,533,534],{},"not"," ship custom helpers (no date formatters, no math, no currency). If you find yourself wanting ",[26,537,538],{},"{{formatDate created \"DD\u002FMM\u002FYYYY\"}}",", pre-format on your side and pass ",[26,541,542],{},"\"createdDisplay\": \"23\u002F05\u002F2026\""," in ",[26,545,28],{},[14,547,548],{},"This is deliberate: it keeps templates portable and your variable schema explicit. The AI assistant follows the same rule.",[31,550,552],{"id":551},"common-patterns","Common patterns",[554,555,557],"h3",{"id":556},"optional-sections","Optional sections",[35,559,561],{"className":37,"code":560,"language":39,"meta":40,"style":40},"{{#if logoUrl}}\n  \u003Cimg src=\"{{logoUrl}}\" class=\"h-12\" alt=\"Logo\" \u002F>\n{{\u002Fif}}\n",[26,562,563,568,573],{"__ignoreMap":40},[44,564,565],{"class":46,"line":47},[44,566,567],{},"{{#if logoUrl}}\n",[44,569,570],{"class":46,"line":53},[44,571,572],{},"  \u003Cimg src=\"{{logoUrl}}\" class=\"h-12\" alt=\"Logo\" \u002F>\n",[44,574,575],{"class":46,"line":59},[44,576,142],{},[554,578,580],{"id":579},"default-text-via-the-data-layer","Default text via the data layer",[14,582,583,584,586],{},"Send a default in ",[26,585,28],{}," rather than wishing Handlebars had a default helper:",[35,588,590],{"className":37,"code":589,"language":39,"meta":40,"style":40},"\u003Ch1>{{title}}\u003C\u002Fh1>          {{!-- always renders --}}\n",[26,591,592],{"__ignoreMap":40},[44,593,594],{"class":46,"line":47},[44,595,589],{},[35,597,601],{"className":598,"code":599,"language":600,"meta":40,"style":40},"language-json shiki shiki-themes github-light github-dark","{ \"title\": \"Welcome\" }       — pass a default from your code\n","json",[26,602,603],{"__ignoreMap":40},[44,604,605,609,613,616,620],{"class":46,"line":47},[44,606,608],{"class":607},"sVt8B","{ ",[44,610,612],{"class":611},"sj4cs","\"title\"",[44,614,615],{"class":607},": ",[44,617,619],{"class":618},"sZZnC","\"Welcome\"",[44,621,622],{"class":607}," }       — pass a default from your code\n",[554,624,626],{"id":625},"multi-language","Multi-language",[14,628,629],{},"Pre-compute the localized strings on your side:",[35,631,633],{"className":598,"code":632,"language":600,"meta":40,"style":40},"{\n  \"labels\": {\n    \"invoice\": \"Facture\",\n    \"total\":   \"Total\"\n  },\n  \"invoice\": { \"number\": \"INV-2026-0142\" }\n}\n",[26,634,635,640,648,661,672,677,696],{"__ignoreMap":40},[44,636,637],{"class":46,"line":47},[44,638,639],{"class":607},"{\n",[44,641,642,645],{"class":46,"line":53},[44,643,644],{"class":611},"  \"labels\"",[44,646,647],{"class":607},": {\n",[44,649,650,653,655,658],{"class":46,"line":59},[44,651,652],{"class":611},"    \"invoice\"",[44,654,615],{"class":607},[44,656,657],{"class":618},"\"Facture\"",[44,659,660],{"class":607},",\n",[44,662,663,666,669],{"class":46,"line":65},[44,664,665],{"class":611},"    \"total\"",[44,667,668],{"class":607},":   ",[44,670,671],{"class":618},"\"Total\"\n",[44,673,674],{"class":46,"line":71},[44,675,676],{"class":607},"  },\n",[44,678,679,682,685,688,690,693],{"class":46,"line":77},[44,680,681],{"class":611},"  \"invoice\"",[44,683,684],{"class":607},": { ",[44,686,687],{"class":611},"\"number\"",[44,689,615],{"class":607},[44,691,692],{"class":618},"\"INV-2026-0142\"",[44,694,695],{"class":607}," }\n",[44,697,698],{"class":46,"line":151},[44,699,700],{"class":607},"}\n",[35,702,704],{"className":37,"code":703,"language":39,"meta":40,"style":40},"\u003Ch1>{{labels.invoice}} {{invoice.number}}\u003C\u002Fh1>\n",[26,705,706],{"__ignoreMap":40},[44,707,708],{"class":46,"line":47},[44,709,703],{},[31,711,713],{"id":712},"next-steps","Next steps",[230,715,716,724],{},[233,717,718],{},[170,719,720],{},[18,721,723],{"href":722},"\u002Fdocs\u002Fguides\u002Fauthoring\u002Fdesign-for-pdf","Designing templates that survive PDF rendering →",[233,725,726],{},[170,727,728],{},[18,729,731],{"href":730},"\u002Fdocs\u002Fguides\u002Fauthoring\u002Fmodeling-variables","Modeling your variables →",[733,734,735],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}",{"title":40,"searchDepth":53,"depth":53,"links":737},[738,739,740,741,742,743,744,745,746,751],{"id":28,"depth":53,"text":33},{"id":111,"depth":53,"text":112},{"id":258,"depth":53,"text":259},{"id":432,"depth":53,"text":433},{"id":472,"depth":53,"text":473},{"id":488,"depth":53,"text":489},{"id":501,"depth":53,"text":502},{"id":527,"depth":53,"text":528},{"id":551,"depth":53,"text":552,"children":747},[748,749,750],{"id":556,"depth":59,"text":557},{"id":579,"depth":59,"text":580},{"id":625,"depth":59,"text":626},{"id":712,"depth":53,"text":713},"authoring","The exact subset of Handlebars supported in Transactional templates — variables, conditionals, loops, and what NOT to reach for.","md","braces",{},"\u002Fdocs\u002Fguides\u002Fauthoring\u002Fhandlebars",{"title":5,"description":753},"docs\u002Fguides\u002Fauthoring\u002Fhandlebars","E4mzxH34B5YaU07Px7pYADm4wh7quY6lRucnu9viwl8",[762,767,771,775,779,783,787,791,794,795,798,802,807,812,816,820,825],{"path":763,"title":764,"description":765,"category":766,"order":71},"\u002Fdocs\u002Fguides\u002Fai-mcp\u002Fchatgpt","ChatGPT (via Custom GPT Actions)","ChatGPT doesn't speak MCP natively yet — but you can give it the same powers through a Custom GPT pointed at the Transactional REST API.","ai-mcp",{"path":768,"title":769,"description":770,"category":766,"order":59},"\u002Fdocs\u002Fguides\u002Fai-mcp\u002Fclaude-code","Claude Code (CLI)","Connect Transactional to Claude Code so it can read your templates and generate PDFs from your terminal.",{"path":772,"title":773,"description":774,"category":766,"order":53},"\u002Fdocs\u002Fguides\u002Fai-mcp\u002Fclaude-desktop","Claude Desktop","Connect Transactional to Claude Desktop on macOS or Windows so Claude can read your templates and generate PDFs.",{"path":776,"title":777,"description":778,"category":766,"order":65},"\u002Fdocs\u002Fguides\u002Fai-mcp\u002Fcursor","Cursor","Wire Transactional into Cursor's MCP support so you can generate PDFs from inside your editor.",{"path":780,"title":781,"description":782,"category":766,"order":77},"\u002Fdocs\u002Fguides\u002Fai-mcp\u002Fgemini","Gemini Code Assist \u002F Gemini CLI","Connect Transactional to Google's Gemini agents through their MCP support.",{"path":784,"title":785,"description":786,"category":766,"order":151},"\u002Fdocs\u002Fguides\u002Fai-mcp\u002Ftools-reference","MCP tools reference","Every tool the Transactional MCP server exposes, with arguments, return shapes, and a prompt that typically triggers each one.",{"path":788,"title":789,"description":790,"category":766,"order":47},"\u002Fdocs\u002Fguides\u002Fai-mcp\u002Fuse-from-ai","Use Transactional from your AI assistant","Connect Transactional to Claude, Cursor, ChatGPT, or Gemini via MCP so your assistant can read your templates and generate PDFs directly.",{"path":722,"title":792,"description":793,"category":752,"order":53},"Designing templates that survive PDF rendering","PDFs are static — drop the animations, oversample your canvas charts, lean on vectors. The rules that make a template look sharp at print resolution.",{"path":757,"title":5,"description":753,"category":752,"order":47},{"path":730,"title":796,"description":797,"category":752,"order":59},"Modeling your variables","When to make something a variable vs. inline. Keep the API contract small, your templates portable, and your integration code boring.",{"path":799,"title":800,"description":801,"category":752,"order":65},"\u002Fdocs\u002Fguides\u002Fauthoring\u002Fworking-with-ai","Working with the AI assistant","Prompts and patterns to get good templates fast — what to ask, when to iterate, when to start over.",{"path":803,"title":804,"description":805,"category":806,"order":47},"\u002Fdocs\u002Fguides\u002Fgetting-started\u002Fquickstart","Quickstart — your first PDF in 5 minutes","Sign up, design a template, render your first PDF through the API. End-to-end in five minutes.","getting-started",{"path":808,"title":809,"description":810,"category":811,"order":47},"\u002Fdocs\u002Fguides\u002Fintegrations\u002Fnode-bun","Calling \u002Fv1\u002Fgenerate from Node.js & Bun","Production-grade integration using native fetch — retries, error handling, streaming the PDF to your storage.","integrations",{"path":813,"title":814,"description":815,"category":811,"order":53},"\u002Fdocs\u002Fguides\u002Fintegrations\u002Fphp-laravel","Calling \u002Fv1\u002Fgenerate from PHP & Laravel","cURL extension, Guzzle, or Laravel's HTTP client — render PDFs with retries and proper error handling.",{"path":817,"title":818,"description":819,"category":811,"order":59},"\u002Fdocs\u002Fguides\u002Fintegrations\u002Fpython","Calling \u002Fv1\u002Fgenerate from Python","urllib (stdlib), requests, or httpx with retry — render PDFs from Django, FastAPI, or any Python service.",{"path":821,"title":822,"description":823,"category":824,"order":47},"\u002Fdocs\u002Fguides\u002Foperations\u002Fmonitoring-usage","Monitoring usage & credits","Read the dashboard gauges, set sane alerts, and decide when to top up vs. upgrade.","operations",{"path":826,"title":827,"description":828,"category":824,"order":53},"\u002Fdocs\u002Fguides\u002Foperations\u002Fstoring-pdfs","Storing & serving the generated PDF","The \u002Fv1\u002Fgenerate URL is signed and short-lived. Patterns for keeping the PDF around — your bucket, your CDN, your DB.",1780347733851]