[{"data":1,"prerenderedAt":1092},["ShallowReactive",2],{"guide-\u002Fdocs\u002Fguides\u002Fauthoring\u002Fmodeling-variables":3,"guides-all":1024},{"id":4,"title":5,"body":6,"category":1015,"description":1016,"extension":1017,"icon":1018,"meta":1019,"navigation":929,"order":183,"path":1020,"seo":1021,"stem":1022,"__hash__":1023},"guides\u002Fdocs\u002Fguides\u002Fauthoring\u002Fmodeling-variables.md","Modeling your variables",{"type":7,"value":8,"toc":1004},"minimark",[9,13,22,27,33,36,40,43,65,69,72,113,139,143,146,336,339,455,458,462,465,572,590,594,649,653,660,822,825,829,839,969,976,980,1000],[10,11,5],"h1",{"id":12},"modeling-your-variables",[14,15,16,17,21],"p",{},"A great template has the ",[18,19,20],"strong",{},"smallest variable surface possible",". Everything else lives inline in the HTML. This guide is the rule of thumb for where to draw that line.",[23,24,26],"h2",{"id":25},"the-rule","The rule",[28,29,30],"blockquote",{},[14,31,32],{},"If you'd send the same value on every generation, it's not a variable.",[14,34,35],{},"That's it. Section titles, legal notices, column headers, footer copyright, button labels — all inline. They never change between two invoices for the same template.",[23,37,39],{"id":38},"what-should-be-a-variable","What SHOULD be a variable",[14,41,42],{},"Anything that genuinely differs from one generation to the next:",[44,45,46,50,53,56,59,62],"ul",{},[47,48,49],"li",{},"Customer \u002F recipient data (name, email, address)",[47,51,52],{},"Document identifiers (invoice number, order id, ticket id)",[47,54,55],{},"Dates (issue date, due date, period)",[47,57,58],{},"Monetary amounts and line items",[47,60,61],{},"Status flags (paid \u002F unpaid, trial \u002F billed)",[47,63,64],{},"Image URLs that change per recipient (avatar, signature)",[23,66,68],{"id":67},"what-should-not-be-a-variable","What should NOT be a variable",[14,70,71],{},"Anything that's static for the template:",[44,73,74,89,101,104,107,110],{},[47,75,76,77,81,82,81,85,88],{},"Section headings (",[78,79,80],"em",{},"\"Billed to\"",", ",[78,83,84],{},"\"Items\"",[78,86,87],{},"\"Notes\"",")",[47,90,91,92,81,95,81,98,88],{},"Column headers (",[78,93,94],{},"\"Item\"",[78,96,97],{},"\"Qty\"",[78,99,100],{},"\"Amount\"",[47,102,103],{},"Legal text and footers",[47,105,106],{},"The brand name, logo URL (unless multi-tenant)",[47,108,109],{},"Visual decorations",[47,111,112],{},"Button text on receipt CTAs",[114,115,128],"aside",{"className":116},[117,118,119,120,121,122,123,124,125,126,127],"not-prose","my-6","rounded-md","border","border-blue-200","bg-blue-50","text-blue-900","px-4","py-3","text-[14px]","leading-relaxed",[14,129,130,133,134,138],{},[18,131,132],{},"Why this matters."," Every variable is a piece of contract your integration code must pass. A template with 30 variables means 30 fields your ",[135,136,137],"code",{},"variables"," object must always include. A template with 6 variables is six lines of integration code. Keep it small.",[23,140,142],{"id":141},"a-practical-example","A practical example",[14,144,145],{},"Bad — variables doing too much:",[147,148,153],"pre",{"className":149,"code":150,"language":151,"meta":152,"style":152},"language-json shiki shiki-themes github-light github-dark","{\n  \"title\": \"Invoice\",\n  \"billedToLabel\": \"Billed to\",\n  \"fromLabel\": \"From\",\n  \"itemColumnHeader\": \"Item\",\n  \"qtyColumnHeader\": \"Qty\",\n  \"amountColumnHeader\": \"Amount\",\n  \"totalLabel\": \"Total\",\n  \"footerLegal\": \"© 2026 Acme Corp\",\n  \"paidLabel\": \"PAID\",\n  \"customer\": { \"name\": \"Customer SAS\" },\n  \"invoice\": { \"number\": \"INV-001\", \"total\": 100 }\n}\n","json","",[135,154,155,164,181,193,206,218,230,242,255,268,281,301,330],{"__ignoreMap":152},[156,157,160],"span",{"class":158,"line":159},"line",1,[156,161,163],{"class":162},"sVt8B","{\n",[156,165,167,171,174,178],{"class":158,"line":166},2,[156,168,170],{"class":169},"sj4cs","  \"title\"",[156,172,173],{"class":162},": ",[156,175,177],{"class":176},"sZZnC","\"Invoice\"",[156,179,180],{"class":162},",\n",[156,182,184,187,189,191],{"class":158,"line":183},3,[156,185,186],{"class":169},"  \"billedToLabel\"",[156,188,173],{"class":162},[156,190,80],{"class":176},[156,192,180],{"class":162},[156,194,196,199,201,204],{"class":158,"line":195},4,[156,197,198],{"class":169},"  \"fromLabel\"",[156,200,173],{"class":162},[156,202,203],{"class":176},"\"From\"",[156,205,180],{"class":162},[156,207,209,212,214,216],{"class":158,"line":208},5,[156,210,211],{"class":169},"  \"itemColumnHeader\"",[156,213,173],{"class":162},[156,215,94],{"class":176},[156,217,180],{"class":162},[156,219,221,224,226,228],{"class":158,"line":220},6,[156,222,223],{"class":169},"  \"qtyColumnHeader\"",[156,225,173],{"class":162},[156,227,97],{"class":176},[156,229,180],{"class":162},[156,231,233,236,238,240],{"class":158,"line":232},7,[156,234,235],{"class":169},"  \"amountColumnHeader\"",[156,237,173],{"class":162},[156,239,100],{"class":176},[156,241,180],{"class":162},[156,243,245,248,250,253],{"class":158,"line":244},8,[156,246,247],{"class":169},"  \"totalLabel\"",[156,249,173],{"class":162},[156,251,252],{"class":176},"\"Total\"",[156,254,180],{"class":162},[156,256,258,261,263,266],{"class":158,"line":257},9,[156,259,260],{"class":169},"  \"footerLegal\"",[156,262,173],{"class":162},[156,264,265],{"class":176},"\"© 2026 Acme Corp\"",[156,267,180],{"class":162},[156,269,271,274,276,279],{"class":158,"line":270},10,[156,272,273],{"class":169},"  \"paidLabel\"",[156,275,173],{"class":162},[156,277,278],{"class":176},"\"PAID\"",[156,280,180],{"class":162},[156,282,284,287,290,293,295,298],{"class":158,"line":283},11,[156,285,286],{"class":169},"  \"customer\"",[156,288,289],{"class":162},": { ",[156,291,292],{"class":169},"\"name\"",[156,294,173],{"class":162},[156,296,297],{"class":176},"\"Customer SAS\"",[156,299,300],{"class":162}," },\n",[156,302,304,307,309,312,314,317,319,322,324,327],{"class":158,"line":303},12,[156,305,306],{"class":169},"  \"invoice\"",[156,308,289],{"class":162},[156,310,311],{"class":169},"\"number\"",[156,313,173],{"class":162},[156,315,316],{"class":176},"\"INV-001\"",[156,318,81],{"class":162},[156,320,321],{"class":169},"\"total\"",[156,323,173],{"class":162},[156,325,326],{"class":169},"100",[156,328,329],{"class":162}," }\n",[156,331,333],{"class":158,"line":332},13,[156,334,335],{"class":162},"}\n",[14,337,338],{},"Good — variables only for what varies:",[147,340,342],{"className":149,"code":341,"language":151,"meta":152,"style":152},"{\n  \"customer\": { \"name\": \"Customer SAS\" },\n  \"invoice\": { \"number\": \"INV-001\", \"issuedOn\": \"2026-05-23\", \"total\": 100 },\n  \"items\": [\n    { \"label\": \"Pro plan\", \"qty\": 1, \"amount\": 100 }\n  ],\n  \"paid\": true\n}\n",[135,343,344,348,362,394,402,436,441,451],{"__ignoreMap":152},[156,345,346],{"class":158,"line":159},[156,347,163],{"class":162},[156,349,350,352,354,356,358,360],{"class":158,"line":166},[156,351,286],{"class":169},[156,353,289],{"class":162},[156,355,292],{"class":169},[156,357,173],{"class":162},[156,359,297],{"class":176},[156,361,300],{"class":162},[156,363,364,366,368,370,372,374,376,379,381,384,386,388,390,392],{"class":158,"line":183},[156,365,306],{"class":169},[156,367,289],{"class":162},[156,369,311],{"class":169},[156,371,173],{"class":162},[156,373,316],{"class":176},[156,375,81],{"class":162},[156,377,378],{"class":169},"\"issuedOn\"",[156,380,173],{"class":162},[156,382,383],{"class":176},"\"2026-05-23\"",[156,385,81],{"class":162},[156,387,321],{"class":169},[156,389,173],{"class":162},[156,391,326],{"class":169},[156,393,300],{"class":162},[156,395,396,399],{"class":158,"line":195},[156,397,398],{"class":169},"  \"items\"",[156,400,401],{"class":162},": [\n",[156,403,404,407,410,412,415,417,420,422,425,427,430,432,434],{"class":158,"line":208},[156,405,406],{"class":162},"    { ",[156,408,409],{"class":169},"\"label\"",[156,411,173],{"class":162},[156,413,414],{"class":176},"\"Pro plan\"",[156,416,81],{"class":162},[156,418,419],{"class":169},"\"qty\"",[156,421,173],{"class":162},[156,423,424],{"class":169},"1",[156,426,81],{"class":162},[156,428,429],{"class":169},"\"amount\"",[156,431,173],{"class":162},[156,433,326],{"class":169},[156,435,329],{"class":162},[156,437,438],{"class":158,"line":220},[156,439,440],{"class":162},"  ],\n",[156,442,443,446,448],{"class":158,"line":232},[156,444,445],{"class":169},"  \"paid\"",[156,447,173],{"class":162},[156,449,450],{"class":169},"true\n",[156,452,453],{"class":158,"line":244},[156,454,335],{"class":162},[14,456,457],{},"The other strings (\"Invoice\", \"Billed to\", \"Total\", \"PAID\") live in the HTML as plain text.",[23,459,461],{"id":460},"multi-language-is-the-exception","Multi-language is the exception",[14,463,464],{},"If the same template needs to render in multiple languages, then yes — promote the labels:",[147,466,468],{"className":149,"code":467,"language":151,"meta":152,"style":152},"{\n  \"labels\": {\n    \"invoice\": \"Facture\",\n    \"billedTo\": \"Adressé à\",\n    \"total\": \"Total\",\n    \"paid\": \"PAYÉ\"\n  },\n  \"customer\": { \"name\": \"Customer SAS\" },\n  \"invoice\": { \"number\": \"INV-001\", \"total\": 100 }\n}\n",[135,469,470,474,482,494,506,517,527,532,546,568],{"__ignoreMap":152},[156,471,472],{"class":158,"line":159},[156,473,163],{"class":162},[156,475,476,479],{"class":158,"line":166},[156,477,478],{"class":169},"  \"labels\"",[156,480,481],{"class":162},": {\n",[156,483,484,487,489,492],{"class":158,"line":183},[156,485,486],{"class":169},"    \"invoice\"",[156,488,173],{"class":162},[156,490,491],{"class":176},"\"Facture\"",[156,493,180],{"class":162},[156,495,496,499,501,504],{"class":158,"line":195},[156,497,498],{"class":169},"    \"billedTo\"",[156,500,173],{"class":162},[156,502,503],{"class":176},"\"Adressé à\"",[156,505,180],{"class":162},[156,507,508,511,513,515],{"class":158,"line":208},[156,509,510],{"class":169},"    \"total\"",[156,512,173],{"class":162},[156,514,252],{"class":176},[156,516,180],{"class":162},[156,518,519,522,524],{"class":158,"line":220},[156,520,521],{"class":169},"    \"paid\"",[156,523,173],{"class":162},[156,525,526],{"class":176},"\"PAYÉ\"\n",[156,528,529],{"class":158,"line":232},[156,530,531],{"class":162},"  },\n",[156,533,534,536,538,540,542,544],{"class":158,"line":244},[156,535,286],{"class":169},[156,537,289],{"class":162},[156,539,292],{"class":169},[156,541,173],{"class":162},[156,543,297],{"class":176},[156,545,300],{"class":162},[156,547,548,550,552,554,556,558,560,562,564,566],{"class":158,"line":257},[156,549,306],{"class":169},[156,551,289],{"class":162},[156,553,311],{"class":169},[156,555,173],{"class":162},[156,557,316],{"class":176},[156,559,81],{"class":162},[156,561,321],{"class":169},[156,563,173],{"class":162},[156,565,326],{"class":169},[156,567,329],{"class":162},[156,569,570],{"class":158,"line":270},[156,571,335],{"class":162},[14,573,574,575,578,579,582,583,585,586,589],{},"But group them under a ",[135,576,577],{},"labels"," (or ",[135,580,581],{},"i18n",") key so the rest of ",[135,584,137],{}," stays clean. Don't sprinkle individual ",[135,587,588],{},"*Label"," keys at the top level.",[23,591,593],{"id":592},"naming-conventions","Naming conventions",[44,595,596,602,622,637],{},[47,597,598,601],{},[18,599,600],{},"camelCase"," keys. The template is JavaScript-land; match it.",[47,603,604,173,607,610,611,614,615,81,618,621],{},[18,605,606],{},"Group related fields under an object",[135,608,609],{},"customer.name"," not ",[135,612,613],{},"customerName",". It scales better when you add ",[135,616,617],{},"customer.email",[135,619,620],{},"customer.address",".",[47,623,624,173,627,630,631,81,634,621],{},[18,625,626],{},"Arrays for repeatable items",[135,628,629],{},"items: [{...}, {...}]",", not ",[135,632,633],{},"item1",[135,635,636],{},"item2",[47,638,639,173,642,630,645,648],{},[18,640,641],{},"Booleans express state, not display",[135,643,644],{},"paid: true",[135,646,647],{},"showPaidBadge: true",". Let the template decide what to render.",[23,650,652],{"id":651},"sample-variables-in-the-editor","Sample variables in the editor",[14,654,655,656,659],{},"The dashboard's editor has a ",[18,657,658],{},"Variables"," panel. Seed it with realistic example data so the live preview is meaningful:",[147,661,663],{"className":149,"code":662,"language":151,"meta":152,"style":152},"{\n  \"customer\": { \"name\": \"Acme Corp\" },\n  \"invoice\": {\n    \"number\": \"INV-2026-0142\",\n    \"issuedOn\": \"2026-05-23\",\n    \"dueOn\": \"2026-06-22\",\n    \"total\": 1280.50\n  },\n  \"items\": [\n    { \"label\": \"Pro subscription\", \"qty\": 1, \"amount\": 1200 },\n    { \"label\": \"Top-up — 1k PDFs\", \"qty\": 1, \"amount\": 80.50 }\n  ],\n  \"paid\": false\n}\n",[135,664,665,669,684,690,702,713,725,734,738,744,774,804,808,817],{"__ignoreMap":152},[156,666,667],{"class":158,"line":159},[156,668,163],{"class":162},[156,670,671,673,675,677,679,682],{"class":158,"line":166},[156,672,286],{"class":169},[156,674,289],{"class":162},[156,676,292],{"class":169},[156,678,173],{"class":162},[156,680,681],{"class":176},"\"Acme Corp\"",[156,683,300],{"class":162},[156,685,686,688],{"class":158,"line":183},[156,687,306],{"class":169},[156,689,481],{"class":162},[156,691,692,695,697,700],{"class":158,"line":195},[156,693,694],{"class":169},"    \"number\"",[156,696,173],{"class":162},[156,698,699],{"class":176},"\"INV-2026-0142\"",[156,701,180],{"class":162},[156,703,704,707,709,711],{"class":158,"line":208},[156,705,706],{"class":169},"    \"issuedOn\"",[156,708,173],{"class":162},[156,710,383],{"class":176},[156,712,180],{"class":162},[156,714,715,718,720,723],{"class":158,"line":220},[156,716,717],{"class":169},"    \"dueOn\"",[156,719,173],{"class":162},[156,721,722],{"class":176},"\"2026-06-22\"",[156,724,180],{"class":162},[156,726,727,729,731],{"class":158,"line":232},[156,728,510],{"class":169},[156,730,173],{"class":162},[156,732,733],{"class":169},"1280.50\n",[156,735,736],{"class":158,"line":244},[156,737,531],{"class":162},[156,739,740,742],{"class":158,"line":257},[156,741,398],{"class":169},[156,743,401],{"class":162},[156,745,746,748,750,752,755,757,759,761,763,765,767,769,772],{"class":158,"line":270},[156,747,406],{"class":162},[156,749,409],{"class":169},[156,751,173],{"class":162},[156,753,754],{"class":176},"\"Pro subscription\"",[156,756,81],{"class":162},[156,758,419],{"class":169},[156,760,173],{"class":162},[156,762,424],{"class":169},[156,764,81],{"class":162},[156,766,429],{"class":169},[156,768,173],{"class":162},[156,770,771],{"class":169},"1200",[156,773,300],{"class":162},[156,775,776,778,780,782,785,787,789,791,793,795,797,799,802],{"class":158,"line":283},[156,777,406],{"class":162},[156,779,409],{"class":169},[156,781,173],{"class":162},[156,783,784],{"class":176},"\"Top-up — 1k PDFs\"",[156,786,81],{"class":162},[156,788,419],{"class":169},[156,790,173],{"class":162},[156,792,424],{"class":169},[156,794,81],{"class":162},[156,796,429],{"class":169},[156,798,173],{"class":162},[156,800,801],{"class":169},"80.50",[156,803,329],{"class":162},[156,805,806],{"class":158,"line":303},[156,807,440],{"class":162},[156,809,810,812,814],{"class":158,"line":332},[156,811,445],{"class":169},[156,813,173],{"class":162},[156,815,816],{"class":169},"false\n",[156,818,820],{"class":158,"line":819},14,[156,821,335],{"class":162},[14,823,824],{},"The integration docs panel reads this same shape and embeds it verbatim in the code snippets it generates — so the snippets your developers copy already match your contract.",[23,826,828],{"id":827},"discovering-the-shape-from-code","Discovering the shape from code",[14,830,831,832,835,836,838],{},"If you're integrating from an unfamiliar template, ",[135,833,834],{},"GET \u002Fv1\u002Fdocuments\u002F{id}"," returns the ",[135,837,137],{}," field with the sample shape. Use that as the canonical schema:",[147,840,844],{"className":841,"code":842,"language":843,"meta":152,"style":152},"language-ts shiki shiki-themes github-light github-dark","const doc = await fetch(`https:\u002F\u002Fapi.transactional.dev\u002Fv1\u002Fdocuments\u002F${id}`, {\n  headers: {'x-api-token': process.env.TRANSACTIONAL_API_TOKEN!},\n}).then(r => r.json())\n\nconsole.log(JSON.stringify(doc.variables, null, 2))\n\u002F\u002F Now you know exactly what to pass to \u002Fv1\u002Fgenerate.\n","ts",[135,845,846,880,900,925,931,963],{"__ignoreMap":152},[156,847,848,852,855,858,861,865,868,871,874,877],{"class":158,"line":159},[156,849,851],{"class":850},"szBVR","const",[156,853,854],{"class":169}," doc",[156,856,857],{"class":850}," =",[156,859,860],{"class":850}," await",[156,862,864],{"class":863},"sScJk"," fetch",[156,866,867],{"class":162},"(",[156,869,870],{"class":176},"`https:\u002F\u002Fapi.transactional.dev\u002Fv1\u002Fdocuments\u002F${",[156,872,873],{"class":162},"id",[156,875,876],{"class":176},"}`",[156,878,879],{"class":162},", {\n",[156,881,882,885,888,891,894,897],{"class":158,"line":166},[156,883,884],{"class":162},"  headers: {",[156,886,887],{"class":176},"'x-api-token'",[156,889,890],{"class":162},": process.env.",[156,892,893],{"class":169},"TRANSACTIONAL_API_TOKEN",[156,895,896],{"class":850},"!",[156,898,899],{"class":162},"},\n",[156,901,902,905,908,910,914,917,920,922],{"class":158,"line":183},[156,903,904],{"class":162},"}).",[156,906,907],{"class":863},"then",[156,909,867],{"class":162},[156,911,913],{"class":912},"s4XuR","r",[156,915,916],{"class":850}," =>",[156,918,919],{"class":162}," r.",[156,921,151],{"class":863},[156,923,924],{"class":162},"())\n",[156,926,927],{"class":158,"line":195},[156,928,930],{"emptyLinePlaceholder":929},true,"\n",[156,932,933,936,939,941,944,946,949,952,955,957,960],{"class":158,"line":208},[156,934,935],{"class":162},"console.",[156,937,938],{"class":863},"log",[156,940,867],{"class":162},[156,942,943],{"class":169},"JSON",[156,945,621],{"class":162},[156,947,948],{"class":863},"stringify",[156,950,951],{"class":162},"(doc.variables, ",[156,953,954],{"class":169},"null",[156,956,81],{"class":162},[156,958,959],{"class":169},"2",[156,961,962],{"class":162},"))\n",[156,964,965],{"class":158,"line":220},[156,966,968],{"class":967},"sJ8bj","\u002F\u002F Now you know exactly what to pass to \u002Fv1\u002Fgenerate.\n",[14,970,971,972,975],{},"The AI assistant in the editor and the MCP ",[135,973,974],{},"get_document"," tool do exactly this to learn what variables a template expects.",[23,977,979],{"id":978},"next-steps","Next steps",[44,981,982,992],{},[47,983,984,991],{},[18,985,986],{},[987,988,990],"a",{"href":989},"\u002Fdocs\u002Fguides\u002Fauthoring\u002Fhandlebars","Handlebars cheat sheet →"," — what works inside templates.",[47,993,994,621],{},[18,995,996],{},[987,997,999],{"href":998},"\u002Fdocs\u002Fguides\u002Fauthoring\u002Fdesign-for-pdf","Designing templates that survive PDF rendering →",[1001,1002,1003],"style",{},"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}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 .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"title":152,"searchDepth":166,"depth":166,"links":1005},[1006,1007,1008,1009,1010,1011,1012,1013,1014],{"id":25,"depth":166,"text":26},{"id":38,"depth":166,"text":39},{"id":67,"depth":166,"text":68},{"id":141,"depth":166,"text":142},{"id":460,"depth":166,"text":461},{"id":592,"depth":166,"text":593},{"id":651,"depth":166,"text":652},{"id":827,"depth":166,"text":828},{"id":978,"depth":166,"text":979},"authoring","When to make something a variable vs. inline. Keep the API contract small, your templates portable, and your integration code boring.","md","brackets",{},"\u002Fdocs\u002Fguides\u002Fauthoring\u002Fmodeling-variables",{"title":5,"description":1016},"docs\u002Fguides\u002Fauthoring\u002Fmodeling-variables","EAHW3GB-TpkcG_Vif2HQg1zHeZemo6NLEm-zmYTOKPY",[1025,1030,1034,1038,1042,1046,1050,1054,1057,1060,1061,1065,1070,1075,1079,1083,1088],{"path":1026,"title":1027,"description":1028,"category":1029,"order":208},"\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":1031,"title":1032,"description":1033,"category":1029,"order":183},"\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":1035,"title":1036,"description":1037,"category":1029,"order":166},"\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":1039,"title":1040,"description":1041,"category":1029,"order":195},"\u002Fdocs\u002Fguides\u002Fai-mcp\u002Fcursor","Cursor","Wire Transactional into Cursor's MCP support so you can generate PDFs from inside your editor.",{"path":1043,"title":1044,"description":1045,"category":1029,"order":220},"\u002Fdocs\u002Fguides\u002Fai-mcp\u002Fgemini","Gemini Code Assist \u002F Gemini CLI","Connect Transactional to Google's Gemini agents through their MCP support.",{"path":1047,"title":1048,"description":1049,"category":1029,"order":232},"\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":1051,"title":1052,"description":1053,"category":1029,"order":159},"\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":998,"title":1055,"description":1056,"category":1015,"order":166},"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":989,"title":1058,"description":1059,"category":1015,"order":159},"Handlebars cheat sheet","The exact subset of Handlebars supported in Transactional templates — variables, conditionals, loops, and what NOT to reach for.",{"path":1020,"title":5,"description":1016,"category":1015,"order":183},{"path":1062,"title":1063,"description":1064,"category":1015,"order":195},"\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":1066,"title":1067,"description":1068,"category":1069,"order":159},"\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":1071,"title":1072,"description":1073,"category":1074,"order":159},"\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":1076,"title":1077,"description":1078,"category":1074,"order":166},"\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":1080,"title":1081,"description":1082,"category":1074,"order":183},"\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":1084,"title":1085,"description":1086,"category":1087,"order":159},"\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":1089,"title":1090,"description":1091,"category":1087,"order":166},"\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.",1780347733853]