Skip to main content
An order form is the document Veles generates from an Order: the agreement the customer signs. You build the template once as a Google Doc, place variables in it, and Veles fills them with the order’s data each time it generates the form. Order form templates use their own set of variables. They read from the order — its phases, lines, billing details, and dates — not from the quote, so the variables on the Document Generation overview (options, calculations, title_block, and so on) don’t apply here. The {{ }} syntax is the same.

Setting up a template

Admins pick order form templates in Admin > Contracts > Order Forms & E-signature. There is one template per deal type: Connect Google Docs first, then use Pick from Drive to choose the template for each deal type. Order form templates are Google Docs; Microsoft Word templates are not available for order forms yet.

Template syntax

Loops repeat table rows, so place a loop inside a table: the rows between #each and /each print once per item. Outside a loop, reach into a list by position, starting at 0: {{ phases.0.total }} is the first phase’s total. A blank value reads as false in #if, so a conditional around a field hides its section when the field is empty.
“Term” means two different things on an order form. contract_term is the length of the contract, in months. term.<key> is a legal clause from your Terms library. They are unrelated variables — see Contract length and Terms.

Variable reference

A variable marked nullable can be blank. Dates print as words, for example “January 15, 2026”. Amounts print formatted in the order’s currency, for example “$12,000.00”.

Order

Whole-contract totals

Terms

Billing

Owner

The user who owns the order. Empty when the order has no owner, so wrap it in {{ #if(owner) }} if that can happen.

Company

The customer company on the order. Empty when no company is linked.

Option

The quote option the order was converted from.

CRM

The CRM record (Salesforce or HubSpot) linked to the order’s opportunity. Every field prints blank when the opportunity has no CRM link.

Phases

phases is the order’s list of phases, in sequence order. Loop it with {{ #each(phases) as phase }}, or reach one by position with phases.0, phases.1, and so on.

Lines

Each item in phase.lines, phase.one_time_lines, phase.recurring_lines, or a bundle’s lines. The examples loop them as line.

Contract length

{{ contract_term }} prints the contract length in months, as a number: write the unit in the template ({{ contract_term }} months). It prints the same length the order page shows, worked out from the order’s start and end dates. A 12-month order from January 1, 2026 to December 31, 2026 prints 12; a partial month counts as a full one. When the order has a contract term stored on it, the stored term wins over the dates. It is blank only when the order has no stored term and is missing a start or end date. contract_term has nothing to do with the Terms library. To print a legal clause, use term.<key>, below.

Terms

Each term in your Terms library has a variable, term.<key>, named by the term’s template variable key. It prints that term’s copy on its own, so you can place one term anywhere in the order form and show a whole section only when the term is on the order:
The syntax works the same way as on quote templates; Placing individual terms is the full reference. Three things are specific to order forms:
  • The option’s terms, not the whole quote’s. term.<key> on an order form covers the terms on the option the order was converted from. A term on another option of the same quote is blank.
  • Read from the published version. The terms come from the same published snapshot of the quote as the rest of the order. Editing the term’s copy in Admin, or editing the quote after the order is created, does not change what the order form prints.
  • Give each term a paragraph of its own. A term’s copy is rich text, so place {{ term.payment_terms }} in its own paragraph, outside a table row loop.

All terms at once

To print every term the option carries in one place, use {{ terms_html }}. Each term prints with its number and name as a bold heading, followed by its copy, in the same order the quote lists them:
The same rules apply as for term.<key>: it covers only the option the order was converted from, it reads from the published snapshot, and it needs a paragraph of its own. Use terms_html when the order form should carry whatever terms the rep chose; use term.<key> when the template places specific terms in specific sections. special_terms is separate: it prints the order’s special terms field, as plain text.

Custom fields

Replace <key> with the custom field’s key, for example {{ company.custom_fields.region }}. Single and multi-select fields print their labels; multi-select labels are joined with ; . A field with no value prints blank, so {{ #if(company.custom_fields.region) }} … {{ /if }} hides a section when the field is unset. Inside a line loop, write {{ line.custom_fields.po_line }} or {{ line.product.custom_fields.sku_family }}.

Product descriptions

To print what each product includes, loop the lines and print each product’s name and description:
The description prints as plain text. Bold, italics, and links lose their formatting, line breaks are kept, and list items print on their own lines with a bullet or a number in front. A product with no description prints blank, so {{ #if(line.product.description) }} … {{ /if }} hides whatever sits between them for that product.

List price and discounts

An order line holds the price it sold at and the published quote line it was converted from. Its list price and discount are read from that quote line, so a products table can print them beside the price:
The list price is the system price — the price pricing rules left the line at — and the discount is the rep’s alone, the one the quote prints. On every row, list_price less the discount is unit_price. A line sold at its list price prints “0%” and a zero amount; a line sold above it prints a negative discount. For totals, print phase.total_discount and total_savings rather than adding up line rows: they count a bundle once and follow the phase totals, so a partial year is prorated. A row with no quote line — an order not converted from a published quote — prints its list price and discount blank, and so do the totals when there is no quote year to read them from. {{ #if(line.list_price) }} … {{ /if }} hides whatever sits between them.

Bundles

Looping phase.lines prints one row per bundle and per standalone line. To print a bundle’s components, loop its lines inside that loop. Standalone lines have no lines, so this rate list prints only components:
Every row shows the price Veles shows for it, so a bundle and its components each carry the bundle’s money. For totals, print phase.annual_contract_value, phase.recurring_total, or phase.one_time_total rather than adding up line rows, and total_contract_value for the whole order.

One-time and recurring lines

To print one-time and recurring charges in separate tables, loop phase.one_time_lines and phase.recurring_lines instead of phase.lines. Together they hold the same top-level rows as phase.lines, each exactly once. A line is one-time when its billing type is one_time; every other line, usage included, is recurring. Only the top-level rows are split: a one-time bundle with a recurring component stays in one_time_lines, and the component stays in the bundle’s own lines.
A usage line’s unit_price and total_price print its per-unit rate (for example “$2.00 per API Call”), and phase.recurring_total does not include it.

Example

Put the loops in a table, with each #each and /each in the rows it repeats.

What’s next

Document Generation

Quote templates, the full syntax reference, and placing individual terms.

Terms

Manage the legal clauses an order form can print by key.

Order Overview

Understand the order an order form is generated from.

Order Phase

How an order’s phases split the contract into periods.