Templates & Merge Variables
This page explains Keelstone's template object model — the three Salesforce objects that back every template — and how merge data flows from Salesforce records into your Office documents.
Template Object Model
Keelstone templates are managed through three related custom objects in the kstone namespace.
Keelstone_Template__c
The root object. Each record represents one document template and provides a stable identifier that you can reference in flows without hardcoding a file ID.
| Field | Type | Description |
|---|---|---|
Name | Text | Human-readable label (e.g. "Welcome Packet") |
Template_Key__c | Text (80), Unique | Developer slug referenced in flows and embedded in generated documents. Stable across org migrations. Example: "welcome-packet" |
Active__c | Checkbox | Inactive templates are excluded from all lookups |
Document_Type__c | Picklist | Word / Docs, Excel / Sheets, or PowerPoint / Slides — informational only; filtering is done via template key |
The template file (.docx, .xlsx, or .pptx) is attached as a standard Salesforce File. KS: Generate Document always uses the most recently attached file.
Using a template in a flow:
KS: Build Merge Context record → {!Get_Contact} → contextJson
KS: Generate Document
templateKey → "welcome-packet"
contextJson → {!contextJson}
filename → "Welcome Packet.docx"
linkedEntityId → {!recordId}
Using templateKey means your flows are portable — they work in any org where a Keelstone_Template__c record with that key exists.
Keelstone_Template_Action__c
Junction object between Keelstone_Template__c and Keelstone_Action__c. Each record links one action to one template, controlling which action tiles appear in the taskpane when a generated document is open.
| Field | Type | Description |
|---|---|---|
Template__c | Lookup (Keelstone_Template__c) | The template |
Action__c | Lookup (Keelstone_Action__c) | The action tile to show for that template |
Visibility rules:
- An action with no
Keelstone_Template_Action__crecords is global — it appears in the taskpane for all open documents - An action with one or more junction records is template-scoped — it only appears when the open document was generated from a matching template
How matching works:
When KS: Generate Document generates a document using a templateKey, it embeds _ks_template_key in the document's custom properties. When the taskpane next opens, it reads that key and sends it to the server. The server then shows only actions that are either global or linked to that template.
Example:
| Action | Junction Records | Shows when |
|---|---|---|
Generate Itinerary | Linked to welcome-packet | Document was generated from the welcome-packet template |
Export to PDF | None | All documents (global) |
Merge Placeholder Syntax
Placeholders use single curly braces. The name inside matches the field path passed in the merge context.
Simple fields
{FirstName} → Contact.FirstName
{Level__c} → Contact.Level__c
{Account.Name} → Contact.Account.Name (relationship field)
{Owner.Email} → Contact.Owner.Email
Field names are case-sensitive and must match the Salesforce API name exactly, including __c for custom fields. The field must be included in the Get Records SOQL query — fields not queried are unavailable at merge time.
Loop blocks (repeating rows or sections)
Use {#listName} / {/listName} to repeat content for each item in a collection. In Excel, rows between the tags are duplicated; in Word, the enclosed block (paragraph, table row, or multiple paragraphs) is repeated.
{#bookings}
{Experience_Name__c} | {Date__c} | {Number_of_Guests__c}
{/bookings}
The listName matches the tableName you set in the KS: Add Table flow action (or the key name in custom Apex / LWC context JSON).
Conditional blocks (Word only)
Show or hide content based on a truthy/falsy value:
{#isPremiumMember}
As a Premium member, you enjoy complimentary transfers.
{/isPremiumMember}
{^isPremiumMember}
Upgrade to Premium for exclusive member benefits.
{/isPremiumMember}
{#field} renders the block when the value is truthy (non-blank, non-zero, non-false). {^field} renders it when falsy.
Building merge data in a flow
Pass merge data to KS: Generate Document via contextJson. There are three ways to build it.
Path 1 — Pure admin (KS: Build Merge Context + KS: Add Table)
Get Records → Contact (Id, FirstName, LastName, Level__c, Account.Name)
│
▼
KS: Build Merge Context record → {!Get_Contact} → contextJson
KS: Generate Document
templateKey → "welcome-packet"
contextJson → {!contextJson}
filename → "Welcome Letter.docx"
linkedEntityId → {!recordId}
Template:
Dear {FirstName} {LastName},
Welcome to {Level__c} member.
Your account: {Account.Name}
With related lists
Get Records → Contact
Get Records → Booking__c (filter: Contact__c = recordId)
Get Records → Credit__c (filter: Contact__c = recordId)
│
▼
KS: Build Merge Context record → {!Get_Contact} → contextJson
KS: Add Table records → {!Get_Bookings} → contextJson
tableName → "bookings"
KS: Add Table records → {!Get_Credits} → contextJson
tableName → "credits"
KS: Generate Document templateKey → "welcome-packet"
contextJson → {!contextJson}
filename → "Welcome Packet.docx"
Chain as many KS: Add Table calls as needed — there is no limit.
Path 2 — Custom Apex (cross-object fields, multiple lists in one step)
Write an @InvocableMethod that queries cross-object data (e.g. Owner.Name) and returns a contextJson String. Eliminates the need for separate Get Records elements and supports any data shape.
See the Developer Guide for a complete example.
Path 3 — LWC JavaScript
Build the context map in a headless Flow Screen LWC and pass the JSON string to KS: Generate Document via a flow variable.
Supplementing context with mergeData
mergeData is merged on top of contextJson at the highest priority. Use it from a Flow formula to inject computed values:
KS: Generate Document
templateKey → "pipeline-report"
contextJson → {!varContextJson}
mergeData → '{"generatedDate":"' & TEXT(TODAY()) & '"}'
filename → "Pipeline Report.xlsx"
Further reading
- Template Creation Guide — step-by-step admin setup for templates, fields, and scoped actions
- Template Builder — point-and-click tool for inserting merge tokens directly in Office
- KS: Generate Document — the
keelstoneGenerateDocumentFlow Screen component