# Quotes and B2B

> Turn the cart into a quote request that reaches Shopify as a draft order, and show business customers their company, their quantity rules and their prices.

Status: Ready (Smootify 2.0)  
Plan: Server plan  
Add-on: Draft Orders  
URL: https://www.smootify.io/docs/astro/features/quotes  
Updated: 2026-10-21

With quotes, the cart does not go to checkout: it sends a request. You receive a draft order in Shopify, with the lines, variants and quantities the customer chose. You set your price, send the invoice, and the customer pays it in Shopify’s checkout. This page builds the quote cart and covers what Smootify shows to business (B2B) customers.

> [!NOTE]
> Quotes need the **Server** plan and **Draft Orders** turned on in the Smootify dashboard. They run on the site's licensed domain.

## How it fits together

A quote is a cart. You build it as in [Build the cart](https://www.smootify.io/docs/astro/build/cart), then choose one of two ways:

| Way | Built with | Use it when |
|---|---|---|
| A quote cart | `data-draft="true"` on `smootify-cart`: every submit of its form sends a quote | the store sells only on quote, or on a quote page of its own |
| A quote button in a normal cart | a `button` with `type="submit"` and `name="draft-order"`, next to the checkout button, which keeps working | some customers buy and others ask |

What Smootify needs:

- a `smootify-cart` with its `<form>`, as for any cart;
- an `input` whose `name` is `email`, so the draft order has an address to send the invoice to.

What is up to you: the layout, the other fields you ask for, and the texts. Write them as a request, not as an order.

## 1. Build a quote cart

```html
<smootify-cart data-draft="true">
  <div cart-condition="no-items-in-quote">Your quote is empty</div>
  <form>
    <cart-item>
      <div cart-item="title">Product</div>
      <div cart-item="variant-title">Red / M</div>
      <quantity-input><button data-action="minus">-</button><input name="quantity"><button data-action="plus">+</button></quantity-input>
      <button data-action="remove">Remove</button>
    </cart-item>
    <input name="email" type="email">
    <button type="submit" data-wait="Sending…">Send request</button>
  </form>
  <div form-done hidden>Thank you. We will send you a quote by email.</div>
  <div form-fail hidden>Something went wrong</div>
</smootify-cart>
```

In a quote cart, `[form-done]` is not the empty cart: it shows once the request is sent. Two conditions work inside `smootify-cart`, `cart-condition="items-in-quote"` and `cart-condition="no-items-in-quote"`. The cart’s four states:

| State | What shows |
|---|---|
| The quote has lines | the `<form>`: the lines, the email field and the submit button that sends the request; `cart-condition="items-in-quote"` shows |
| The request is sent | `[form-done]`: write it as “request received”, so the customer does not think they have bought; Smootify empties the cart, and `cart-condition="no-items-in-quote"` stays hidden |
| The quote is empty | `cart-condition="no-items-in-quote"`, outside the form; the form and `[form-done]` are hidden, and `smootify-cart` has the class `has-empty-quote` |
| Shopify refuses the request | `[form-fail]`, with Shopify’s errors, as in any cart |

## 2. Or add a quote button to a normal cart

In a cart without `data-draft`, add a `button` with `type="submit"` and `name="draft-order"`, inside the `<form>` next to the checkout button. The email field goes in the same form.

```html
<button type="submit" data-wait="Please wait…">Check out</button>
<button type="submit" name="draft-order">Ask for a quote</button>
```

A link cannot do this: it does not submit the form. Use a `button`.

## 3. What the draft order holds

Each field of the form has its place in the draft order:

| In the quote cart’s form | In the draft order |
|---|---|
| the lines, each with its variant, quantity and properties (such as an engraving) | **Products**: the same lines, variants, quantities and properties |
| an `input` with the name `email` | **Customer**: the Shopify customer with that email, created when there is none |
| a `textarea` with the name `note` | **Notes**: the note of the draft order |
| any other field, such as `Company` or `Phone` | **Additional details**, with the field’s name as the label |
| the currency the customer saw | the currency of the draft order |

- **The lines** keep their properties, such as an engraving or an uploaded file. A Magic Box arrives as the products inside it. A Shopify bundle arrives as its components, with a “Bundle” detail listing them.
- **The customer** is the Shopify customer with the email in the form. If there is none, Shopify creates one with that email. Without an email field, a logged-in customer’s account is used.

Subscription lines are left out: a draft order does not carry the selling plan. See [Subscriptions](https://www.smootify.io/docs/astro/features/subscriptions).

## 4. Send the quote from Shopify

In your Shopify admin, the request is under **Orders > Drafts**, with the discount codes the customer had applied to the cart. Change the prices or add a discount, then send the invoice. The customer gets an email with a link to Shopify’s checkout, at the price you set. Discount codes can still be used there.

To get an email for each new request, import the ready-made [Quote request notification](https://www.smootify.io/flows/draft-order-notification) workflow in the free **Shopify Flow** app. It reacts when a draft order is created: after importing it, replace the default email with the address that should receive the requests.

## 5. Business customers (B2B)

Shopify’s B2B features, with companies, catalogs and quantity rules, are on every paid Shopify plan. Outside Shopify Plus, a store can have at most 3 active B2B catalogs, and it needs Shopify’s new Markets: see [Shopify’s B2B plans](https://help.shopify.com/en/manual/b2b/getting-started/plan-features). When a customer who belongs to a company logs in with [customer accounts](https://www.smootify.io/docs/astro/build/account), Smootify asks Shopify for products and the cart as that company’s buyer, using the company’s first location. The prices and quantity rules Shopify sets for that company then apply on the site.

**Show the company.** `company="name"` shows the name of the customer’s company, anywhere on the page. `company-metafield="…"` shows a metafield of the company, such as a customer code or the name of their sales contact, and `if-company-metafield` shows an element only when that metafield has a value. For a customer without a company, these elements are removed, and so are the `if-company-metafield` elements for a visitor who is not logged in. `unless-company-metafield` does the opposite: it shows its element when the company has no value for that metafield, and to guests, who have no company. Use it for the guest’s Add to cart next to the company’s Add to quote list. See [customer attributes](https://www.smootify.io/docs/astro/reference/attributes/customer).

**Show the quantity rules.** Inside `smootify-product`:

- `variant="quantity-min"`: the smallest quantity that can be ordered;
- `variant="quantity-max"`: the largest, hidden when there is no maximum;
- `variant="quantity-increment"`: the pack size the quantity must be a multiple of.

**Buy for some, quote for others.** Put the quote button inside an element with `customer-tagged="wholesale"` (use your own tag). Only logged-in customers with that tag see it. Everyone else keeps the checkout button.

```html
<button type="submit" data-wait="Please wait…">Check out</button>
<div customer-tagged="wholesale"><button type="submit" name="draft-order">Ask for a quote</button></div>
```

To order the same list again later, customers can use **Buy again** on a past order: see [Orders and buy again](https://www.smootify.io/docs/astro/build/orders). For a minimum order value, or products sold in packs, use [purchase rules](https://www.smootify.io/docs/astro/features/purchase-rules).

Customers also see the quotes you send them in their account, with a link to pay each one: see [Orders and buy again](https://www.smootify.io/docs/astro/build/orders#6-quotes).

## 6. Volume prices for companies

A B2B catalog in Shopify can lower the price as the quantity grows: €10.00 each from 1, €9.00 from 10, €8.50 from 50. Smootify shows these price breaks as a table on the product page, and the price follows the quantity in the form. Volume prices need neither the Server plan nor Draft Orders.

**Where the prices come from.** In Shopify, you set the price breaks of a variant in the price list of a B2B catalog. Outside Shopify Plus, Shopify attaches that catalog to a B2B market made of the company’s locations. A catalog assigned directly to company locations is a Shopify Plus feature. Only the contacts of a company in that catalog get the breaks: guests and customers without a company see none.

**Build the table.** Inside `smootify-product`:

- `variant="price-breaks"` on a `div` is the template of one row. Smootify repeats it once per row: the variant’s price from its minimum quantity, then each price break.
- Inside the row, `price-break="range"` writes `1–9`, `10–49`, `50+`. `price-break="price"` writes the price of one, `"savings"` the saving, such as `-10%` (hidden on the first row), and `"total"` the row’s first quantity at its price. `"min"` and `"max"` write the row’s first and last quantity (`max` is hidden on the last row). A row with none of these writes `10+ €9.00`.
- `condition="has-price-breaks"` on the section around it hides it for buyers without breaks.
- `variant="price-at-quantity"` on a `span` writes the price of one at the form’s quantity, and follows it.

```html
<div condition="has-price-breaks">
  <div variant="price-breaks">
    <div price-break="range">1–9</div>
    <div price-break="price">€10.00</div>
    <div price-break="savings">-10%</div>
  </div>
  <div>Price each: <span variant="price-at-quantity">€10.00</span></div>
</div>
```

**A row is a choice.** A click on a row sets the form’s quantity to the row’s first quantity. The row of the current quantity gets the class `is-active`: style it in the component’s CSS. For the click to work, the add-to-cart form needs its `quantity` field.

**Add a row to the cart.** Optionally, put a `button` with `price-break="add"` inside the row. It adds the row’s first quantity to the cart without changing the form’s quantity. It goes through the product’s `smootify-add-to-cart`, with its add-ons, so that form must be on the page. To make it read “Add 10”, write `Add ` in it followed by an element with `price-break="min"`: `<button price-break="add">Add <span price-break="min"></span></button>`.

Example: a café orders mugs at its company price, with the quantity field at 12.

| Quantity | Price | Savings | Total | |
|---|---|---|---|---|
| 1–9 | €14.20 | | €14.20 | Add 1 |
| **10–49** (the current quantity, `is-active`) | **€12.80** | **-10%** | **€128.00** | Add 10 |
| 50+ | €11.40 | -20% | €570.00 | Add 50 |

Under the quantity: "€12.80 per piece at this quantity".

| Part | Attribute | What it shows |
|---|---|---|
| a row | `variant="price-breaks"` | one row, repeated once per price break; the row of the current quantity gets `is-active`, and a click sets the quantity to the row's first quantity |
| Quantity | `price-break="range"` | 1–9, 10–49, 50+ |
| Price | `price-break="price"` | the price of one piece in that row |
| Savings | `price-break="savings"` | the saving on the first row's price, hidden on the first row |
| Total | `price-break="total"` | the row's first quantity at its price: 10 × €12.80 |
| Add 10 | `price-break="add"` | a button with "Add " and `price-break="min"`, the row's first quantity; it adds that quantity to the cart, and the quantity field stays as it is |
| €12.80 per piece | `variant="price-at-quantity"` | the price of one piece at the form's quantity; it follows the quantity |

**With purchase rules.** The first row starts at the variant’s minimum: the higher of the B2B catalog’s minimum and the minimum of the [purchase rules](https://www.smootify.io/docs/astro/features/purchase-rules). Price breaks at or below that minimum are left out.

## Before you publish

On your `*.workers.dev` address or in the dev server, press Alt+Shift+D (Option+Shift+D on a Mac) to turn on Smootify’s [debugger](https://www.smootify.io/docs/astro/start/debugger), then send a test request and open it in Shopify.

> [!STUCK]
> - **The draft order has no email.** The field's `name` is not exactly `email`. Set the `name` back to `email`.
> - **The quote cart goes to checkout.** Draft Orders is not available on this page: check the Server plan, that Draft Orders is turned on in the dashboard, and that the page is on the licensed domain. Without it, Smootify turns a quote cart back into a normal cart, and a quote button does nothing.
> - **Customers think they have ordered.** `[form-done]` still reads like an order confirmation. Rewrite it as a request received.
> - **"Your quote is empty" never shows.** The element with `cart-condition="no-items-in-quote"` is inside the `<form>`, which is hidden while the cart is empty. Move it outside the form, inside `smootify-cart`.
> - **The quote button opens a page or does nothing.** It is a link. Use a `button` with `type="submit"`.
> - **A subscription is missing from the draft order.** Smootify leaves subscription lines out of a quote.
> - **The volume price table never shows.** The customer is not a contact of a company whose B2B catalog has price breaks for that variant. Outside Shopify Plus, the catalog must be attached to a B2B market of the company's locations.
