> This page is for Developer.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.bigcommerce.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.bigcommerce.com/_mcp/server.

# Quote Templates

Quote Templates control the layout and content of the quote emails sent to buyers and the PDF attached to them. B2B Edition ships with several built-in templates, and you can create custom templates to match your branding, tailor the product table for different customers or regions, translate every piece of text, and surface quote-module extra fields inside the document.

> **Info**
>
> This feature is available for the Quotes 2.0 experience. The template you select is used for the quote emails buyers receive and for the PDFs attached to those emails.

## Where to manage quote templates

Go to **Settings > Quotes** in your B2B Edition control panel to see the template list. Each row shows the template name, whether it is built-in or custom, and whether it is enabled.

* **Built-in legacy templates** - the templates pre-loaded with B2B Edition (including `Simple`, `Sky`, and `Dots` from the legacy quotes experience). They cover common layouts and don't need configuration. Built-in legacy templates can't be renamed, disabled, or deleted, but you can set one as the default template.
* **Default template** - the template used when a quote doesn't specify one. You can make any enabled template the default, including a legacy one. The default template can't be disabled or deleted until another template becomes the default.
* **Custom templates** - templates you create. You can rename, enable, disable, and delete these freely, except that a custom template can't be disabled or deleted while it is the default template.

To create a template, click **Add template**. Template names must be unique within the store and can be up to 200 characters long.

## The template editor

Each template has four tabs:

| Tab           | What you edit                                                          |
| ------------- | ---------------------------------------------------------------------- |
| Product Table | Which columns appear in the product table and their per-locale headers |
| Phrases       | Text labels used in the template, translated per locale                |
| Code          | The template's HTML and default subject                                |
| Preview       | A live preview of the rendered PDF                                     |

If your store has more than one storefront, choose the storefront first. Templates are assigned per storefront, so you can reuse one template across storefronts or give each storefront its own template.

## Product Table tab

The product table renders the quote's line items. You choose which columns appear, their order, and the header text for each column per locale.

| Column          | Description                              |
| --------------- | ---------------------------------------- |
| Image           | Product image                            |
| Product         | Product name                             |
| SKU             | Product SKU                              |
| Options         | Selected product options                 |
| Quantity        | Quantity ordered                         |
| Price           | Original base price                      |
| Quoted Price    | Price offered on the quote               |
| Discount        | Discount percentage applied to the line  |
| Subtotal        | Extended price before the quote discount |
| Quoted Subtotal | Extended price after the quote discount  |
| Notes           | Line item notes                          |

New templates start with the default column set: Image, Product, SKU, Options, Quantity, Quoted Price, Quoted Subtotal, and Notes.

> **Warning**
>
> When discount visibility is turned off in your quote settings, the Price, Discount, and Subtotal columns are hidden from the PDF, even if they're selected in the template. This setting applies to all quote templates.

Column headers are translatable. Select a locale, edit the header text, and buyers on that storefront see the translated header. Locale changes are cached for about five minutes.

## Phrases tab

Phrases are the text labels used throughout the template, such as column captions, section titles, and messages. In the template code a phrase renders where you place `{{ phrases.<phrase_name> }}`, so changing a phrase value updates every place that references it.

New templates come with these phrases pre-populated:

| Phrase name              | Default value                              |
| ------------------------ | ------------------------------------------ |
| `quote_number`           | Quote#:                                    |
| `date_created`           | Date created:                              |
| `valid_until`            | Valid until:                               |
| `reference_number`       | Reference number:                          |
| `contact_title`          | Contact                                    |
| `billing_address_title`  | Billing Address                            |
| `shipping_address_title` | Shipping Address                           |
| `notes_title`            | Notes                                      |
| `quote_details_title`    | Quote details                              |
| `terms_title`            | Terms and conditions                       |
| `original_total`         | Original total:                            |
| `discount`               | Discount:                                  |
| `quoted_total`           | Quoted total:                              |
| `shipping`               | Shipping:                                  |
| `tax`                    | Tax:                                       |
| `total`                  | Total:                                     |
| `thank_you`              | Thank you for your business!               |
| `contact_message`        | If you have any questions, please contact: |
| `checkout_button`        | Checkout                                   |
| `view_quote_detail`      | View quote detail                          |

You can add, edit, and delete phrase names. Phrase names must be unique within the template. Phrase names are merchant-defined, so any name works as long as the template references it with `{{ phrases.<name> }}`.

Use the locale selector to translate phrase values. Phrases stored under the **default** locale are the fallback when a buyer's storefront language has no translation for that phrase.

## Code tab

The Code tab holds the template's HTML and its default subject. The default subject is used when a quote email is sent without an explicit subject, and each template keeps its own default subject.

Template content is HTML with mustache-style variable holders. The renderer supports these categories:

### Fixed variables

Fixed variables are populated from the quote, company, store, or user data at render time. Variable names are lowercase snake_case. The B2B Ninja camel-case spellings, such as `{{ legalTerms }}`, are rejected; the supported forms are the snake_case names documented here.

**Quote details**

| Variable                    | Description                                                                      |
| --------------------------- | -------------------------------------------------------------------------------- |
| `{{ quote_number }}`        | Quote number                                                                     |
| `{{ quote_title }}`         | Quote title                                                                      |
| `{{ quote_amount }}`        | Quote total amount                                                               |
| `{{ quote_created_at }}`    | Date the quote was created                                                       |
| `{{ quote_expired_at }}`    | Quote expiration date                                                            |
| `{{ quote_contact_name }}`  | Quote contact name                                                               |
| `{{ quote_contact_email }}` | Quote contact email                                                              |
| `{{ quote_logo }}`          | Quote logo image URL, falling back to the store logo. Use it as an `<img>` `src` |
| `{{ quote_notes }}`         | Notes on the quote                                                               |
| `{{ quote_details_url }}`   | Link to the quote details page                                                   |
| `{{ quote_reminder_days }}` | Days until the quote reminder                                                    |
| `{{ reference_number }}`    | Quote reference number                                                           |
| `{{ order_number }}`        | Order number, when the quote is converted                                        |

**Quote totals**

| Variable                | Description                                                                                                                                                                |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `{{ subtotal }}`        | Line-item subtotal before the quote discount                                                                                                                               |
| `{{ discount_price }}`  | Quote discount amount                                                                                                                                                      |
| `{{ tax_total }}`       | Quote tax total                                                                                                                                                            |
| `{{ shipping_total }}`  | Quote shipping amount                                                                                                                                                      |
| `{{ shipping_method }}` | Quote shipping method name, the same name the built-in templates print next to the shipping amount. Renders `Customer choice at checkout` when the quote has no method yet |
| `{{ grand_total }}`     | Quote grand total                                                                                                                                                          |
| `{{ total_amount }}`    | Quote total amount after tax and shipping                                                                                                                                  |

The totals above are bare amounts, such as `1,000.00`. To show the currency symbol, use the formatted variant of each total. It places the store currency symbol on the correct side of the amount, and shows the amount without a symbol when the quote hides its prices. `{{ formatted_shipping_total }}` and `{{ formatted_tax_total }}` render `TBD` when the quote has no shipping method yet.

| Variable                         | Description                                     |
| -------------------------------- | ----------------------------------------------- |
| `{{ formatted_subtotal }}`       | `{{ subtotal }}` with the currency symbol       |
| `{{ formatted_discount_price }}` | `{{ discount_price }}` with the currency symbol |
| `{{ formatted_tax_total }}`      | `{{ tax_total }}` with the currency symbol      |
| `{{ formatted_shipping_total }}` | `{{ shipping_total }}` with the currency symbol |
| `{{ formatted_grand_total }}`    | `{{ grand_total }}` with the currency symbol    |
| `{{ formatted_total_amount }}`   | `{{ total_amount }}` with the currency symbol   |

**Company and buyer contact**

| Variable                   | Description                |
| -------------------------- | -------------------------- |
| `{{ company_name }}`       | Buyer company name         |
| `{{ company_phone }}`      | Buyer company phone number |
| `{{ customer_firstname }}` | Buyer first name           |
| `{{ customer_lastname }}`  | Buyer last name            |
| `{{ customer_phone }}`     | Buyer phone number         |
| `{{ customer_address }}`   | Buyer address, line 1      |
| `{{ customer_address_2 }}` | Buyer address, line 2      |
| `{{ customer_city }}`      | Buyer city                 |
| `{{ customer_state }}`     | Buyer state                |
| `{{ customer_zipcode }}`   | Buyer postal code          |

**Billing and shipping addresses**

Each field of the quote's billing and shipping address is available as `{{ billing_address.<field> }}` and `{{ shipping_address.<field> }}`. A field the quote doesn't have renders empty.

| Field         | Description     |
| ------------- | --------------- |
| `firstName`   | First name      |
| `lastName`    | Last name       |
| `address`     | Address, line 1 |
| `apartment`   | Address, line 2 |
| `city`        | City            |
| `state`       | State           |
| `zipCode`     | Postal code     |
| `country`     | Country         |
| `phoneNumber` | Phone number    |

For example, `{{ shipping_address.city }}` renders the shipping city. Field names are case-sensitive, and other fields are rejected.

**Store details**

| Variable                      | Description           |
| ----------------------------- | --------------------- |
| `{{ store_name }}`            | Store name            |
| `{{ store_secure_url }}`      | Storefront URL        |
| `{{ store_login_url }}`       | Storefront login URL  |
| `{{ store_logo_url }}`        | Store logo image URL  |
| `{{ store_email }}`           | Store contact email   |
| `{{ store_phone }}`           | Store phone number    |
| `{{ store_country }}`         | Store country         |
| `{{ store_currency }}`        | Store currency code   |
| `{{ store_currency_symbol }}` | Store currency symbol |
| `{{ store_weight_units }}`    | Store weight units    |
| `{{ store_street }}`          | Store street address  |

**People and shopping lists**

| Variable                                         | Description                                            |
| ------------------------------------------------ | ------------------------------------------------------ |
| `{{ submitter_name }}` / `{{ submitter_email }}` | Quote submitter                                        |
| `{{ approver_name }}` / `{{ approver_email }}`   | Quote approver                                         |
| `{{ inviter_name }}` / `{{ inviter_email }}`     | Company inviter                                        |
| `{{ user_name }}` / `{{ user_email }}`           | Recipient's user name and email                        |
| `{{ shopping_list_name }}`                       | Shopping list name, when the quote originated from one |
| `{{ shopping_list_url }}`                        | Link to the shopping list                              |

**Sales rep**

| Variable                | Description                     |
| ----------------------- | ------------------------------- |
| `{{ sales_rep_name }}`  | Sales rep assigned to the quote |
| `{{ sales_rep_email }}` | Sales rep email                 |
| `{{ sales_rep_phone }}` | Sales rep phone number          |

The sales rep variables come from the backend user assigned to the quote, and they render empty when the quote has no assigned sales rep. `{{ sales_rep_name }}` is the backend user's username, which can be a handle or an email address rather than a display name. You can use these variables in the default subject as well as in template content. In the Preview tab, they render sample values: `Sample Sales Rep`, `sales.rep@example.com`, and `555-0300`.

The base template footer lists the sales rep lines above the store email and phone line, so a quote without an assigned sales rep still shows the store contact details.

**Legal terms and date**

| Variable                 | Description                                                        |
| ------------------------ | ------------------------------------------------------------------ |
| `{{ legal_terms }}`      | Terms and conditions attached to the quote                         |
| `{{ store_conditions }}` | Same value as `{{ legal_terms }}`, under the B2B Ninja parity name |
| `{{ current_date }}`     | Current date at render time                                        |

> **Info**
>
> A few B2B Ninja parity names are accepted but render empty for now: `{{ store_city }}`, `{{ store_state }}`, `{{ store_zipcode }}`, `{{ store_hours }}`, and `{{ store_fax }}`. Names shared with other transactional-email contexts, such as the `invoice_*` variables, `newuser_email`, and `password_reset_url`, are also accepted by the editor but aren't populated in quote documents.

### The product table holder

`{{ product_table }}` renders the full product table configured on the Product Table tab. This is a single server-rendered holder: don't try to loop over products or rebuild the table yourself in template code. To change what the table shows, edit the Product Table tab.

### The checkout button holder

`{{ checkout_button }}` renders a styled **Checkout** link to the quote's checkout page. Its label comes from the `checkout_button` phrase. The link renders only when checkout is allowed on the quote; otherwise the holder renders empty, so templates don't need their own condition. It can only be used in template content, not in the default subject.

### The View quote detail link

The base template includes a **View quote detail** link in its header, matching the link in the built-in legacy templates:

```html showLineNumbers={false}
<a href="{{ quote_details_url }}" rel="noopener noreferrer">{{ phrases.view_quote_detail }}</a>
```

The link opens the quote on the storefront the quote belongs to. In the Preview tab, the sample link points to the storefront home page instead.

The link is ordinary template HTML, so you can change it on the Code tab:

* To restyle it, add an inline `style` attribute, for example `style="color: #3c64f4; font-weight: 600;"`. Inline styles follow the same [template rules](#template-rules) as the rest of the content.
* To move it, cut the `<a>` element and paste it anywhere else in the template content.
* To remove it, delete the `<a>` element.

The link text comes from the `view_quote_detail` phrase. To relabel or translate it, edit that phrase's value per locale in the [Phrases tab](#phrases-tab).

### Extra-field variables

Quote-module extra fields become template variables. See [Using extra fields as variables](#using-extra-fields-as-variables).

### Template rules

The editor validates content before saving and blocks invalid templates:

* Content must be HTML. Django template syntax, including `{% ... %}` statement tags and `{# ... #}` comments, isn't allowed.
* Only variables listed above, plus `{{ phrases.<name> }}`, `{{ extra_fields.<name> }}`, and the `{{ billing_address.<field> }}` / `{{ shipping_address.<field> }}` fields, are supported. Unknown variables are rejected.
* `{{ product_table }}` and `{{ checkout_button }}` render HTML, so place them in template content rather than the default subject. The default subject rejects `{{ checkout_button }}`.
* Link URLs support the `https` and `mailto` schemes only.
* Inline `style` attributes are sanitized: properties that can load external resources (such as anything carrying a `url()`) are stripped.
* Template content can be up to 100,000 characters, names up to 200 characters, and the default subject up to 1,300 characters.

## Preview tab

The Preview tab renders the template with sample quote data so you can check layout, translations, and variable output before saving. Preview respects the selected storefront and locale.

You can also send the rendered PDF to an email address with **Send test email** to see exactly what a buyer receives.

## Using extra fields as variables

Extra fields let you attach custom data to quotes and display that data inside the quote PDF.

1. Go to **Settings > Extra Fields** and create extra fields for the **Quote** module.
2. Supported value types are text, textarea, number, and dropdown.
3. Reference a field's value in the template as `{{ extra_fields.<variable_name> }}`.

The variable name is derived from the field name:

* Lowercase the name and replace spaces and symbols with underscores (for example, "Delivery Window" becomes `delivery_window`).
* If the name starts with a digit, the variable is prefixed with `field_` (for example, "2Day Ship" becomes `field_2day_ship`).
* If two fields slugify to the same name, later ones get a numeric suffix (`_2`, `_3`, and so on).

Use the **Code** tab's variable list in the control panel to copy the exact variable name for each field; it reflects the slugified name.

## Resources

* [Transactional Emails](/developer/docs/b2b-edition/admin/transactional-emails)
* [Buyer Portal Localization](/developer/docs/b2b-edition/storefront/buyer-portal/localization)