Introduction
Holding confirmations and payroll statements are stakeholder-level documents that provide an annual summary of a stakeholder's equity holdings. Both use the same template-based approach in Ledgy — the key difference is which data they loop through:
Holding Confirmations — summarise a stakeholder's stock (and optionally convertible) holdings, typically for investor confirmations or tax annexes.
Payroll Statements or Salary Annexes — summarise a stakeholder's grants and equity settlements, typically for employee payroll annexes or tax statements.
Both document types use the same templating engine: you create a .docx template with variables, upload it to Ledgy, and generate documents per stakeholder.
Step-by-step guide
Step 1: Create your template
Create a Word document (.docx) and add the variables listed below. You can also download Ledgy's example templates:
Step 2: Upload the template
Go to Documents > Templates > Upload Template
Upload the
.docxfile into the Template File boxName your template and click Add template
Step 3: Generate the document
Go to Documents > Templates > Create from template
Select the date (all data up until this date will be used)
Select your template
Add the stakeholders (individually or by Group)
Optionally tick the checkbox to share with stakeholders immediately
Click Create
Variables reference
How variables work
Variables are placeholders in your .docx template that Ledgy automatically replaces with real data when generating documents. They are written in curly braces, e.g. {stakeholder.name}.
There are three types:
Global variables — work anywhere in the template
Stakeholder variables — work anywhere in the template; pull data from the stakeholder's profile
Looping (array) variables — work only inside a looping block like
{#stakeholder.stocks}...{/stakeholder.stocks}; pull data from each individual transaction row
Global variables
These work anywhere in your template.
{today}— Today's date (the date the document is generated){date}— The date you selected in the generation form{currency}— The currency set in Company Settings
Stakeholder variables
These work anywhere in your template. They pull data from the stakeholder's profile.
Personal details
{stakeholder.name}— The stakeholder's full name{stakeholder.email}— The stakeholder's email address{stakeholder.nationality}— The stakeholder's nationality{stakeholder.birthdate}— The stakeholder's date of birth{stakeholder.notes}— Any notes stored on the stakeholder's profile{stakeholder.identifier}— The stakeholder's unique identifier (e.g. national ID, passport number, or company registration number)
Address
{stakeholder.address.line1}— First line of the stakeholder's address{stakeholder.address.line2}— Second line of the stakeholder's address (e.g. apartment, suite number){stakeholder.address.postcode}— Postal/ZIP code{stakeholder.address.city}— City{stakeholder.address.county}— County, state, or region
Stakeholder custom fields
{stakeholder.X}— whereXis the name of your custom stakeholder fieldExample: If you have a custom field called "Cost Center" with value "7237-234", then
{stakeholder.Cost Center}→7237-234
Holding totals (outside looping blocks)
These variables work anywhere in your template — inside or outside looping blocks — and give aggregate totals for the stakeholder. They work for both Holding Confirmations and Payroll Statements, so use whichever ones are relevant to your template.
{stakeholder.issued}— Total number of shares issued (directly held) by the stakeholder{stakeholder.granted}— Total number of instruments (options, phantoms, etc.) granted to the stakeholder{stakeholder.stockVested}— Total number of vested shares the stakeholder holds{stakeholder.grantVested}— Total number of vested instruments across all grants{stakeholder.stockValue}— Total value of the stakeholder's stock holdings (Diluted shares × Latest share price){stakeholder.grantValue}— Total current value of all grants{stakeholder.vestedStockValue}— Total value of vested stock{stakeholder.vestedGrantValue}— Total value of vested grants{stakeholder.grantNetValue}— Total net value of all grants{stakeholder.ownershipPercentage}— The stakeholder's ownership percentage of the company{stakeholder.votingPercentage}— The stakeholder's voting rights percentage{stakeholder.shareCapital}— Total share capital (Issued shares × Nominal share price){stakeholder.dilutedShareCapital}— Total diluted share capital (Issued shares × Latest share price)
Stock variables
Use these inside the {#stakeholder.stocks}...{/stakeholder.stocks} looping block. Each row in the generated table represents one share class held by the stakeholder.
Structure in your template
Share Class | Issued | Nominal Share Price ({currency}) | Stock Value ({currency}) |
{#stakeholder.stocks} {class} | {issued} | {nominalSharePrice} | {stockValue}{/stakeholder.stocks} |
Variables inside the stocks loop
{issued}— Number of shares issued to the stakeholder in this share class{investment}— Total investment amount (Share price paid × Number of shares at issuance){stockValue}— Current value of the stock holding (Diluted shares × Latest share price){class}— Name of the share class{nominalSharePrice}— The nominal (par) share price for this share class{shareCapital}— Share capital for this holding (Issued shares × Nominal share price){dilutedShareCapital}— Diluted share capital (Issued shares × Latest share price){stockVested}— Number of vested shares in this share class
Convertible variables
Use these inside the {#stakeholder.convertibles}...{/stakeholder.convertibles} looping block. Each row represents one convertible instrument.
Structure in your template
Date | Investment ({currency}) | Cap ({currency}) | Discount | Interest |
{#stakeholder.convertibles} {date} | {investment} | {cap} | {discount} | {interest}{/stakeholder.convertibles} |
Variables inside the convertibles loop
{date}— Date the convertible was issued{investment}— Amount invested in the convertible loan{cap}— Valuation cap of the convertible{discount}— Discount rate applied upon conversion{interest}— Interest rate on the convertible loan
Grant variables
Use these inside the {#stakeholder.grants}...{/stakeholder.grants} looping block. Each row represents one active grant the stakeholder holds.
Structure in your template
Grant Date | Type | Granted | Outstanding | Exercise Price ({currency}) | Vesting |
{#stakeholder.grants}{date} | {grantType} | {granted} | {outstanding} | {strikePrice} | {vesting}{/stakeholder.grants} |
Variables inside the grants loop
{grantType}— Type of grant (e.g. Stock Option, Phantom, Warrant, RSU){poolName}— Name of the equity pool the grant was issued from{granted}— Number of instruments granted{grantValue}— Current value of this grant{grantVested}— Number of instruments that have vested in this grant{outstanding}— Number of instruments still outstanding (not yet exercised or settled){class}— Share class associated with this grant{date}— Date the grant was made{strikePrice}— Exercise/strike price per instrument{vesting}— Vesting schedule summary text{vesting.StartDate}— Start date of the vesting schedule{shareCapital}— Share capital value for this grant{dilutedShareCapital}— Diluted share capital value for this grant{equityPlanName}— Name of the equity plan this grant belongs to{expiryDate}— Expiry date of the grant{grantNetValue}— Net value of the grant{securityType}— Security type of the grant
Settlement variables
Use these inside the {#stakeholder.settlements}...{/stakeholder.settlements} looping block. Each row represents one equity settlement (exercise) transaction.
Structure in your template
Settled Date | Grant Date | Amount Exercised | Fair Market Value ({currency}) | Exercise price ({currency}) | Total Fair Market Value ({currency}) | Total Taxable Gain ({currency}) |
{#stakeholder.settlements}{date} | {grantDate} | {exercised} | {fmvAtExercise} | {exercisePrice} | {totalFmvAtExercise} | {totalGainLoss}{/stakeholder.settlements} |
Variables inside the settlements loop
{date}— Date the settlement/exercise occurred{grantDate}— Date of the original grant that was exercised{exercised}— Number of instruments exercised in this settlement{fmvAtExercise}— Fair market value per share at the time of exercise{exercisePrice}— Price paid per instrument to exercise{totalFmvAtExercise}— Total fair market value at exercise (FMV × Number exercised){totalGainLoss}— Total gain or loss from the exercise ((FMV − Exercise price) × Number exercised){totalStrikePrice}— Total strike price paid (Exercise price × Number exercised)
Transaction custom field variables
Transaction custom fields let you add your own data points to transactions (e.g. "Tax Treatment", "Board Approval Status"). You can then pull those values into your templates.
Setup: Go to Company Settings > Data Management > Transaction custom fields to create custom fields.
Syntax: {customField.X} — where X is the exact name of your custom field.
Example: If you have a custom field named "Board approval status", use {customField.Board approval status} → Result: "Approved"
⚠️ Important: Transaction custom field variables only work inside looping blocks ({#stakeholder.grants}...{/stakeholder.grants}, {#stakeholder.stocks}...{/stakeholder.stocks}, {#stakeholder.settlements}...{/stakeholder.settlements}, or {#stakeholder.convertibles}...{/stakeholder.convertibles}). They cannot be used outside of these loops because they are tied to individual transactions, not to the stakeholder as a whole.
Example — using a custom field inside the grants loop
Share Class | Issued | Tax Value ({currency}) |
{#stakeholder.stocks} {class} | {issued} | {customField.Tax Value}{/stakeholder.stocks} |
How values are resolved: When transactions are grouped (e.g. multiple transactions under the same grant), the custom field value is taken from the first transaction in the sequence.
See Custom fields for transactions for setup instructions.
Conditional display variables
Use these to show or hide entire sections of your template based on whether a stakeholder has certain types of holdings. Wrap the content you want to conditionally show between the opening tag and {/}.
{#stakeholder.hasStocks}...{/}— Only shows the enclosed content if the stakeholder holds shares{#stakeholder.hasConvertibles}...{/}— Only shows if the stakeholder has convertible instruments{#stakeholder.hasGrants}...{/}— Only shows if the stakeholder has active grants{#stakeholder.hasSettlements}...{/}— Only shows if the stakeholder has equity settlements
FAQs
What is the difference between a Holding Confirmation and a Payroll Statement?
Both are stakeholder-level documents generated from templates. The difference is which looping block you use in your template:
Holding Confirmations use
{#stakeholder.stocks}(and optionally{#stakeholder.convertibles}) to loop through share holdings — typically used for investors.Payroll Statements use
{#stakeholder.grants}and{#stakeholder.settlements}to loop through grants and equity exercises — typically used for employees.
You can combine both in a single template if needed.
Can I use stakeholder variables and totals outside of looping blocks?
Yes. Stakeholder variables (like {stakeholder.name}, {stakeholder.email}) and holding totals (like {stakeholder.grantValue}, {stakeholder.stockValue}) work anywhere in the template — inside or outside looping blocks.
Only looping variables (like {issued}, {granted}, {date} within arrays) and transaction custom field variables ({customField.X}) must be used inside their respective looping blocks.
What happened to the built-in Holding Confirmations feature?
Ledgy previously offered a built-in Holding Confirmations feature that generated documents automatically without requiring a custom template. This feature has since been deprecated and replaced by the more flexible template-based approach described in this article.
As a result of this deprecation, some variables that were part of the old built-in feature — such as the Tax Value variable — are no longer available.
How can I include tax value information in my templates now?
Since the Tax Value variable from the old built-in feature is no longer available, the recommended workaround is to use a transaction custom field:
Step 1 — Create a custom field: Go to Company Settings > Data Management > Transaction custom fields and create a new field (e.g. name it "Tax Value").
Step 2 — Populate the values: For each stakeholder's relevant transactions, manually enter the tax value in the custom field. You can do this:
One at a time: Open each transaction on the Transactions page and fill in the custom field value
In bulk: Use Ownership > Transactions > Bulk Edit, download the spreadsheet, fill in the custom field column, and re-upload
Step 3 — Add the variable to your template: Use {customField.Tax Value} inside the relevant looping block in your template.
Example — showing tax value in a grants table
{#stakeholder.grants}
| {grantType} | {granted} | {grantValue} | {customField.Tax Value} |
{/stakeholder.grants}⚠️ Important: Transaction custom field variables like {customField.Tax Value} only work inside looping blocks — they cannot be placed outside of {#stakeholder.grants}...{/stakeholder.grants} or other array loops. This is because custom fields are attached to individual transactions, not the stakeholder overall.
Where do I set up custom fields?
Go to Company Settings > Data Management > Transaction custom fields. See our dedicated article: Custom fields for transactions.
Need further support? Please feel free to reach out to our Support team via chat or email.





