> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getveles.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Order Form Templates

> Build Google Docs order form templates with the variables Veles fills from an order: dates, contract length, billing details, phases, lines, prices, discounts, and terms.

An order form is the document Veles generates from an [Order](/orders/order.md): 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](/get-started/document-generation/overview.md) (`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:

| Deal type | Used for |
| - | - |
| **New Logo** | First-time customer deals |
| **Renewal** | Existing customer renewals |
| **Amendment** | Mid-term changes and co-terms |

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

| Operation | Syntax |
| - | - |
| **Simple value** | `{{ order_number }}` |
| **Nested value** | `{{ company.name }}` |
| **Loop start** | `{{ #each(phases) as phase }}` |
| **Loop variable** | `{{ phase.total }}` |
| **Loop end** | `{{ /each }}` |
| **Conditional start** | `{{ #if(purchase_order) }}` |
| **Else if** | `{{ #elseif(billing_email) }}` |
| **Else** | `{{ #else }}` |
| **Conditional end** | `{{ /if }}` |

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.

> [!NOTE]
>
> "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](/get-started/calculator/terms.md). They are unrelated variables -- see [Contract length](#contract-length) and [Terms](#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

| Variable | Type | Description |
| - | - | - |
| `order_number` | Integer, nullable | The order number. |
| `purchase_order` | String, nullable | The customer's purchase order number. |
| `status` | String | The order status: `draft`, `finalized`, `pending_signature`, `signed`, `executed`, or `cancelled`. |
| `contract_term` | Integer, nullable | The contract length in months. See [Contract length](#contract-length). |
| `start_date` | Date, nullable | The start date of the order. |
| `end_date` | Date, nullable | The end date of the order. |
| `expiration_date` | Date, nullable | The date the order form expires. |
| `currency` | String | The ISO code of the order's currency, for example `USD`. Every amount on the order form is formatted in this currency. |
| `currency_symbol` | String | The symbol of the order's currency, for example `$`. |
| `special_terms` | String, nullable | The order's special terms, as plain text (formatting is dropped). |

### Whole-contract totals

| Variable | Type | Description |
| - | - | - |
| `total_contract_value` | Currency | The total of the whole order: every phase's total added up. Print it in a "Total Fees" cell on a multi-year contract. |
| `recurring_total_contract_value` | Currency | The recurring total of the whole order: every phase's `recurring_total` added up. |
| `one_time_total_contract_value` | Currency | The one-time total of the whole order: every phase's `one_time_total` added up. |
| `total_savings` | Currency, nullable | The rep's discount on the whole order: every phase's `total_discount` added up. Print it in a "Total Savings" cell. Blank when no phase has one, for example on an order not converted from a published quote. |

### Terms

| Variable | Type | Description |
| - | - | - |
| `term.<key>` | Rich text, nullable | The copy of one legal term, by the term's [template variable key](/get-started/calculator/terms.md#template-variable-key), with its formatting. Blank when the order's option does not carry that term. See [Terms](#terms). |
| `terms_html` | Rich text, nullable | Every term on the order's option, in reference number order, each headed by its number and name. Blank when the option carries no terms. See [All terms at once](#all-terms-at-once). |

### Billing

| Variable | Type | Description |
| - | - | - |
| `billing_name` | String, nullable | Billing contact name. |
| `billing_email` | String, nullable | Billing contact email. |
| `billing_address_line1` | String, nullable | Billing address line 1. |
| `billing_address_line2` | String, nullable | Billing address line 2. |
| `billing_address_line3` | String, nullable | Billing address line 3. |
| `billing_city` | String, nullable | Billing city. |
| `billing_state` | String, nullable | Billing state. |
| `billing_postal_code` | String, nullable | Billing postal code. |
| `billing_country` | String, nullable | Billing country. |

### Owner

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

| Variable | Type | Description |
| - | - | - |
| `owner.name` | String | The owner's name. |
| `owner.email` | String | The owner's email. |
| `owner.phone` | String | The owner's phone number. |
| `owner.job_title` | String | The owner's job title. |

### Company

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

| Variable | Type | Description |
| - | - | - |
| `company.name` | String | The company name. |
| `company.domain` | String, nullable | The company domain. |
| `company.industry` | String, nullable | The company industry. |
| `company.custom_fields.<key>` | String, nullable | A company custom field, by its key. |

### Option

The quote option the order was converted from.

| Variable | Type | Description |
| - | - | - |
| `option.custom_fields.<key>` | String, nullable | An option custom field, by its key. |

### CRM

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

| Variable | Type | Description |
| - | - | - |
| `crm.custom_fields.<key>` | String, nullable | A CRM custom field, by its key. |

### Phases

`phases` is the order's list of [phases](/orders/order-phase.md), in sequence order. Loop it with `{{ #each(phases) as phase }}`, or reach one by position with `phases.0`, `phases.1`, and so on.

| Variable | Type | Description |
| - | - | - |
| `phase.sequence` | Integer | The phase sequence number, starting at 1. |
| `phase.start_date` | Date, nullable | The start date of the phase. |
| `phase.end_date` | Date, nullable | The end date of the phase. |
| `phase.annual_contract_value` | Currency | The total of the phase. |
| `phase.total` | Currency | The same value as `annual_contract_value`, kept for existing templates. |
| `phase.recurring_total` | Currency | The total of the phase's recurring lines. Usage lines are not included. |
| `phase.one_time_total` | Currency | The total of the phase's one-time lines. |
| `phase.total_discount` | Currency, nullable | The rep's discount on the phase, from the quote year it was converted from: its lines at list price less its total, prorated as the total is, with a bundle counted once and usage lines left out. On a full-year phase this is the lines' `discount_amount` added up. Blank when none of its lines has a quote line. |
| `phase.lines` | Array | The phase's top-level lines -- bundles and standalone lines -- in position order. See [Lines](#lines). |
| `phase.one_time_lines` | Array | The top-level lines whose billing type is `one_time`, in position order. |
| `phase.recurring_lines` | Array | The other top-level lines, recurring and usage, in position order. |
| `phase.uom_fields.<key>` | String, nullable | The phase's unit-of-measure value for a UoM key, from the quote the order was converted from, with its scale suffix (`{{ phases.0.uom_fields.ftl }}` prints "250 K"). Blank when the quote year has no value for that key. |

### Lines

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

| Variable | Type | Description |
| - | - | - |
| `line.product_name` | String | The product name. |
| `line.product_sku` | String, nullable | The product SKU. |
| `line.billing_type` | String | `recurring`, `one_time`, or `usage`. |
| `line.billing_frequency` | String | The billing frequency: `monthly`, `quarterly`, `semi_annual`, or `annual`. |
| `line.quantity` | String | The quantity. |
| `line.unit_price` | Currency | The unit price Veles shows for the line. A component of a parent-priced bundle shows its allocated rate for one unit in one bundle; a sum-of-parts bundle shows the sum of its components. A usage line shows its per-unit rate. |
| `line.total_price` | Currency | `unit_price` times `quantity`. A usage line shows its per-unit rate, for example "\$2.00 per API Call". Adding up line rows counts a bundle twice, so print the phase totals instead. |
| `line.list_price` | Currency, nullable | The price of one unit before the rep's discount: the system price, after pricing rules, from the published quote line the row was converted from, at the same grain as `unit_price`. Blank when the row has no quote line. |
| `line.discount_percent` | String, nullable | The rep's discount as a percent, from `list_price` to `unit_price` -- the one the quote prints as `line.formatted.discount`. A whole percent prints bare ("15%"), any other at one decimal, and a line sold at list price prints "0%". Blank when `list_price` is blank. |
| `line.discount_amount` | Currency, nullable | The rep's discount on the row: its total at `list_price` less `total_price`. A usage line prints its saving per unit. Blank when `list_price` is blank. |
| `line.start_date` | Date, nullable | The start date of the line. |
| `line.end_date` | Date, nullable | The end date of the line. |
| `line.custom_fields.<key>` | String, nullable | A quote line custom field, by its key, carried from the quote line the order line came from. |
| `line.product.name` | String | The product name, the same as `product_name`. |
| `line.product.description` | String, nullable | The product description as plain text. See [Product descriptions](#product-descriptions). |
| `line.product.custom_fields.<key>` | String, nullable | A product custom field, by its key. |
| `line.bundle` | Boolean | Whether the line is a bundle: other lines in the phase name it as their parent line. A bundle whose optional components were all left off has none, so it reads false. |
| `line.lines` | Array | The bundle's component lines, in position order. Each carries every field in this table. Empty for standalone lines and components; a bundle inside a bundle carries its own `lines`. |

***

## 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](/get-started/calculator/terms.md) has a variable, `term.<key>`, named by the term's [template variable key](/get-started/calculator/terms.md#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:

```text theme={null}
{{ #if(term.payment_terms) }}
Section 4 - Payment Terms
{{ term.payment_terms }}
{{ #else }}
Standard payment terms apply.
{{ /if }}
```

The syntax works the same way as on quote templates; [Placing individual terms](/get-started/document-generation/overview.md#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:

```text theme={null}
Terms and Conditions
{{ terms_html }}
```

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:

```text theme={null}
{{ #each(phases.0.lines) as line }}
{{ line.product.name }}
{{ line.product.description }}
{{ /each }}
```

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:

```text theme={null}
{{ #each(phases.0.lines) as line }}
{{ line.product_name }} {{ line.list_price }} {{ line.discount_percent }} {{ line.discount_amount }} {{ line.unit_price }} {{ line.total_price }}
{{ /each }}
Discount this year: {{ phases.0.total_discount }}
Total Savings: {{ total_savings }}
```

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:

```text theme={null}
{{ #each(phases.0.lines) as line }}
{{ #each(line.lines) as mode }}
{{ mode.unit_price }} per {{ mode.product_name }}
{{ /each }}
{{ /each }}
```

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`.

```text theme={null}
{{ #each(phases.0.one_time_lines) as line }}
{{ line.product_name }} {{ line.quantity }} {{ line.unit_price }} {{ line.total_price }}
{{ /each }}
One-time total: {{ phases.0.one_time_total }}

{{ #each(phases.0.recurring_lines) as line }}
{{ line.product_name }} {{ line.quantity }} {{ line.unit_price }} {{ line.total_price }}
{{ /each }}
Recurring total: {{ phases.0.recurring_total }}
```

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

```text theme={null}
Order #{{ order_number }}
Company: {{ company.name }}
Prepared by: {{ owner.name }} ({{ owner.email }})
Term: {{ contract_term }} months
Period: {{ start_date }} - {{ end_date }}
Total Fees: {{ total_contract_value }}

Bill to: {{ billing_name }}
{{ billing_address_line1 }}
{{ billing_city }}, {{ billing_state }} {{ billing_postal_code }}

{{ #each(phases) as phase }}
Year {{ phase.sequence }}: {{ phase.start_date }} - {{ phase.end_date }}
{{ #each(phase.lines) as line }}
{{ line.product_name }} | {{ line.quantity }} | {{ line.unit_price }} | {{ line.total_price }}
{{ /each }}
Year total: {{ phase.total }}
{{ /each }}

{{ #if(term.payment_terms) }}
Payment Terms
{{ term.payment_terms }}
{{ /if }}
```

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

***

## What's next

> **[Document Generation](/get-started/document-generation/overview.md)**
>
> Quote templates, the full syntax reference, and placing individual terms.

> **[Terms](/get-started/calculator/terms.md)**
>
> Manage the legal clauses an order form can print by key.

> **[Order Overview](/orders/order.md)**
>
> Understand the order an order form is generated from.

> **[Order Phase](/orders/order-phase.md)**
>
> How an order's phases split the contract into periods.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.