Skip to content

8.5 × 11 in

Quotes & estimates

Product bundle quote

A US Letter sales quote for hardware bundles with SKUs, services and volume discount lines shown as negative amounts. Totals include a shipping estimate and optional tax exemption, and a QR code links to the online acceptance page.

Letter portraitLocale en-USHTML + JinjaHeader & footer

Opens Dynamic Document API with this template preloaded in a free workspace.

Template language features

  • Loops
  • Conditionals
  • Macros
  • Filters
  • QR code
  • Currency formatting
  • Date formatting
  • Number formatting
  • Repeating table headers
  • Header & footer
  • Page numbers

Filters such as format_currency and qrcode are described in the template language reference.

Variables

Derived from the sample data: 7 top-level fields, 41 paths in total. Send the same shape as data.

PathTypeExample
supplierobject
supplier.namestring"Lumen & Slate Learning Supply Co."
supplier.addressstring"8800 Foundry Park Road, Building B ⏎ Columbus,…"
supplier.phonestring"+1 202-555-0163"
supplier.emailstring"quotes@lumenslate.example.com"
supplier.websitestring"lumenslate.example.com"
sales_repobject
sales_rep.namestring"Terrence Boateng"
sales_rep.titlestring"Education Account Manager"
sales_rep.emailstring"t.boateng@lumenslate.example.com"
sales_rep.phonestring"+1 202-555-0177"
customerobject
customer.namestring"Cedar Hollow Unified School District"
customer.contactstring"Marisol Etheridge, Director of Instructional T…"
customer.billing_addressstring"District Office ⏎ 410 Schoolhouse Lane ⏎ Cedar…"
customer.shipping_addressstring"Receiving Dock, Cedar Hollow Middle School ⏎ 1…"
quoteobject
quote.numberstring"LSQ-2026-24817"
quote.issue_datedate"2026-09-17"
quote.valid_for_daysnumber45
quote.currencystring"USD"
quote.localestring"en-US"
quote.projectstring"Grade 6–8 classroom display refresh, 12 rooms"
quote.accept_urlstring"https://quotes.example.com/accept/LSQ-2026-248…"
quote.tax_exemptbooleantrue
quote.tax_exemption_idstring"EX-OH-000417"
quote.tax_ratenumber0.0725
linesarray<object> · 9
lines[].typestring"product"
lines[].skustring"LS-IFP-75K"
lines[].namestring"75-inch interactive flat panel, 4K"
lines[].detailsstring"20-point touch, built-in Wi-Fi 6, two stylus p…"
lines[].quantity?number12
lines[].unit_price?number2849
lines[].amountnumber34188
lines[].rate?number0.08
shippingobject
shipping.methodstring"LTL freight with liftgate delivery"
shipping.estimatenumber1180
shipping.lead_timestring"3–4 weeks after order"
termsarray<string> · 4"Payment is due net 30 from the invoice date an…"

Sample data

Fictional records used for previews. Replace them with your own data when you call the API.

data.json
{
  "supplier": {
    "name": "Lumen & Slate Learning Supply Co.",
    "address": "8800 Foundry Park Road, Building B\nColumbus, OH 43219",
    "phone": "+1 202-555-0163",
    "email": "quotes@lumenslate.example.com",
    "website": "lumenslate.example.com"
  },
  "sales_rep": {
    "name": "Terrence Boateng",
    "title": "Education Account Manager",
    "email": "t.boateng@lumenslate.example.com",
    "phone": "+1 202-555-0177"
  },
  "customer": {
    "name": "Cedar Hollow Unified School District",
    "contact": "Marisol Etheridge, Director of Instructional Technology",
    "billing_address": "District Office\n410 Schoolhouse Lane\nCedar Hollow, OH 45601",
    "shipping_address": "Receiving Dock, Cedar Hollow Middle School\n1275 Ridgeview Road\nCedar Hollow, OH 45601"
  },
  "quote": {
    "number": "LSQ-2026-24817",
    "issue_date": "2026-09-17",
    "valid_for_days": 45,
    "currency": "USD",
    "locale": "en-US",
    "project": "Grade 6–8 classroom display refresh, 12 rooms",
    "accept_url": "https://quotes.example.com/accept/LSQ-2026-24817",
    "tax_exempt": true,
    "tax_exemption_id": "EX-OH-000417",
    "tax_rate": 0.0725
  },
  "lines": [
    {
      "type": "product",
      "sku": "LS-IFP-75K",
      "name": "75-inch interactive flat panel, 4K",
      "details": "20-point touch, built-in Wi-Fi 6, two stylus pens",
      "quantity": 12,
      "unit_price": 2849.0,
      "amount": 34188.0
    },
    {
      "type": "discount",
      "sku": null,
      "name": "Volume discount: 10 or more panels",
      "details": "Applied to LS-IFP-75K",
      "rate": 0.08,
      "amount": -2735.04
    },
    {
      "type": "product",
      "sku": "LS-MNT-HWA",
      "name": "Height-adjustable wall mount",
      "details": "Manual lift with 400 mm of travel, fits 55 to 86-inch panels",
      "quantity": 12,
      "unit_price": 389.0,
      "amount": 4668.0
    },
    {
      "type": "product",
      "sku": "LS-DOC-8MP",
      "name": "Document camera, 8 MP",
      "details": "USB-C and HDMI output, LED arm light",
      "quantity": 12,
      "unit_price": 179.0,
      "amount": 2148.0
    },
    {
      "type": "product",
      "sku": "LS-CRT-36",
      "name": "Charging cart, 36 devices",
      "details": "Lockable doors, timed charging, rear cable management",
      "quantity": 3,
      "unit_price": 1249.0,
      "amount": 3747.0
    },
    {
      "type": "discount",
      "sku": null,
      "name": "Bundle discount: carts ordered with panels",
      "details": "Applied to LS-CRT-36",
      "rate": 0.05,
      "amount": -187.35
    },
    {
      "type": "service",
      "sku": "LS-WTY-3YR",
      "name": "Three-year on-site warranty extension",
      "details": "Per panel, next-business-day response",
      "quantity": 12,
      "unit_price": 210.0,
      "amount": 2520.0
    },
    {
      "type": "service",
      "sku": "LS-SVC-INST",
      "name": "Professional installation",
      "details": "Per classroom: mounting, cabling and removal of the old projector",
      "quantity": 12,
      "unit_price": 325.0,
      "amount": 3900.0
    },
    {
      "type": "service",
      "sku": "LS-SVC-TRN",
      "name": "Teacher training session",
      "details": "Half day on site for up to 20 staff",
      "quantity": 2,
      "unit_price": 650.0,
      "amount": 1300.0
    }
  ],
  "shipping": {
    "method": "LTL freight with liftgate delivery",
    "estimate": 1180.0,
    "lead_time": "3–4 weeks after order"
  },
  "terms": [
    "Payment is due net 30 from the invoice date and requires an approved purchase order.",
    "Freight is an estimate; the final freight charge is invoiced at cost.",
    "Installation is scheduled with the district after delivery and needs site access between 7 a.m. and 4 p.m.",
    "Unopened hardware can be returned within 30 days, subject to a 10% restocking fee."
  ]
}

Source

The body markup with Jinja, the stylesheet placed in <head> and the header and footer settings.

{#- Product quote with SKUs. Discount lines have "type": "discount" and a negative amount; the
    subtotal, total savings, sales tax (unless the customer is tax-exempt) and total are derived from
    the lines. The QR code opens the online acceptance page. -#}
{%- set locale = quote.locale | default("en-US") -%}
{%- set currency = quote.currency -%}
{%- set gross = lines | rejectattr("type", "equalto", "discount") | sum_by("amount") -%}
{%- set savings = lines | selectattr("type", "equalto", "discount") | sum_by("amount") -%}
{%- set net = gross + savings -%}
{%- set tax = 0 if quote.tax_exempt else (net * quote.tax_rate) | round(2) -%}
{%- set total = net + shipping.estimate + tax -%}
{%- set valid_until = quote.issue_date | date_add(days=quote.valid_for_days) -%}

{%- macro money(value) -%}{{ value | format_currency(currency, locale) }}{%- endmacro -%}

<header class="top">
  <div class="brand">
    <svg class="mark" viewBox="0 0 44 44" aria-hidden="true">
      <rect x="2" y="6" width="40" height="30" rx="4" fill="#141a2e"/>
      <rect x="6" y="10" width="32" height="22" rx="1.5" fill="#2447c9"/>
      <path d="M22 13.5l1.9 4.6 4.6 1.9-4.6 1.9-1.9 4.6-1.9-4.6-4.6-1.9 4.6-1.9z" fill="#ffffff"/>
      <path d="M16 40h12" stroke="#141a2e" stroke-width="3" stroke-linecap="round"/>
    </svg>
    <div>
      <div class="brand-name">{{ supplier.name }}</div>
      <div class="brand-meta">{{ supplier.address | replace("\n", " · ") }}</div>
      <div class="brand-meta">{{ supplier.phone }} · {{ supplier.email }}</div>
    </div>
  </div>
  <div class="quote-tag">
    <h1 class="quote-kind">Quote</h1>
    <div class="quote-number">{{ quote.number }}</div>
  </div>
</header>

<section class="banner">
  <div>
    <p class="banner-k">Project</p>
    <p class="banner-v">{{ quote.project }}</p>
  </div>
  <div>
    <p class="banner-k">Quote date</p>
    <p class="banner-v">{{ quote.issue_date | format_date("medium", locale) }}</p>
  </div>
  <div>
    <p class="banner-k">Valid until</p>
    <p class="banner-v">{{ valid_until | format_date("medium", locale) }}</p>
  </div>
</section>

<section class="parties">
  <div>
    <p class="label">Prepared for</p>
    <p class="strong">{{ customer.name }}</p>
    <p>{{ customer.contact }}</p>
    <p class="muted">{{ customer.billing_address | nl2br }}</p>
  </div>
  <div>
    <p class="label">Ship to</p>
    <p>{{ customer.shipping_address | nl2br }}</p>
  </div>
  <div>
    <p class="label">Your account manager</p>
    <p class="strong">{{ sales_rep.name }}</p>
    <p>{{ sales_rep.title }}</p>
    <p class="muted">{{ sales_rep.email }}<br>{{ sales_rep.phone }}</p>
  </div>
</section>

<table class="lines">
  <thead>
    <tr>
      <th class="sku" scope="col">SKU</th>
      <th scope="col">Item</th>
      <th class="num" scope="col">Qty</th>
      <th class="num" scope="col">Unit price</th>
      <th class="num" scope="col">Amount</th>
    </tr>
  </thead>
  <tbody>
    {% for line in lines %}
    {% if line.type == "discount" %}
    <tr class="discount">
      <td class="sku">
        <svg class="tag" viewBox="0 0 16 16" aria-hidden="true">
          <path d="M2 2h5.5l6.5 6.5-5.5 5.5L2 7.5z" fill="none" stroke="#12805c" stroke-width="1.4" stroke-linejoin="round"/>
          <circle cx="5" cy="5" r="1.2" fill="#12805c"/>
        </svg>
      </td>
      <td>
        <span class="item-name">{{ line.name }}</span>
        {% if line.details %}<span class="item-details">{{ line.details }}</span>{% endif %}
      </td>
      <td class="num">−{{ line.rate | format_percent(locale) }}</td>
      <td></td>
      <td class="num">{{ money(line.amount) }}</td>
    </tr>
    {% else %}
    <tr class="{{ line.type }}">
      <td class="sku">{{ line.sku }}</td>
      <td>
        <span class="item-name">{{ line.name }}</span>
        {% if line.type == "service" %}<span class="pill">Service</span>{% endif %}
        {% if line.details %}<span class="item-details">{{ line.details }}</span>{% endif %}
      </td>
      <td class="num">{{ line.quantity }}</td>
      <td class="num">{{ money(line.unit_price) }}</td>
      <td class="num">{{ money(line.amount) }}</td>
    </tr>
    {% endif %}
    {% endfor %}
  </tbody>
</table>

<section class="summary">
  <div class="accept">
    <div class="qr">{{ quote.accept_url | qrcode(size=220, margin=0, ecc="M", alt="QR code to accept this quote online") }}</div>
    <div>
      <p class="accept-title">Accept this quote online</p>
      <ol>
        <li>Scan the code or open the link below.</li>
        <li>Review the items and add your purchase order number.</li>
        <li>Choose an installation window.</li>
      </ol>
      <p class="accept-url">{{ quote.accept_url }}</p>
      <p class="muted small">Prefer paper? Sign this page and email it to {{ sales_rep.email }}.</p>
    </div>
  </div>
  <div class="totals-card">
    <table class="totals">
      <tr><th scope="row">Products and services</th><td class="num">{{ money(gross) }}</td></tr>
      {% if savings < 0 %}<tr class="saving"><th scope="row">Discounts</th><td class="num">{{ money(savings) }}</td></tr>{% endif %}
      <tr><th scope="row">Shipping estimate</th><td class="num">{{ money(shipping.estimate) }}</td></tr>
      <tr>
        {% if quote.tax_exempt %}
        <th scope="row">Sales tax <span class="muted small">exempt · {{ quote.tax_exemption_id }}</span></th><td class="num">{{ money(0) }}</td>
        {% else %}
        <th scope="row">Sales tax {{ quote.tax_rate | format_percent(locale, 2) }}</th><td class="num">{{ money(tax) }}</td>
        {% endif %}
      </tr>
      <tr class="grand"><th scope="row">Quote total</th><td class="num">{{ money(total) }}</td></tr>
    </table>
    {% if savings < 0 %}
    <p class="you-save">You save {{ money(savings | abs) }} with volume and bundle pricing</p>
    {% endif %}
  </div>
</section>

<section class="fine">
  <div>
    <h2>Delivery</h2>
    <p>{{ shipping.method }}, typically {{ shipping.lead_time }}.</p>
    <p class="muted">Ships to the receiving dock listed above.</p>
  </div>
  <div>
    <h2>Terms</h2>
    <ul>
      <li>Prices are valid until {{ valid_until | format_date("long", locale) }}.</li>
      {% for term in terms %}<li>{{ term }}</li>{% endfor %}
    </ul>
  </div>
</section>

<section class="signature">
  <div class="sig-field"><span>Authorized signature</span></div>
  <div class="sig-field"><span>Name and title</span></div>
  <div class="sig-field"><span>Date</span></div>
  <div class="sig-field"><span>PO number</span></div>
</section>

Render it with the API

After adding the template to your workspace, render it by ID and pass your data. Arrays are shortened here.

curl -X POST https://api-eu.dynamicdocumentapi.com/v1/renders \
  -H "Authorization: Bearer $DYNAMIC_DOCUMENT_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "input": {
    "type": "template",
    "template_id": "tpl_01J9ZK3M7Q8V5W2X4Y6Z8A0B1C"
  },
  "data": {
    "supplier": {
      "name": "Lumen & Slate Learning Supply Co.",
      "address": "8800 Foundry Park Road, Building B\nColumbus, OH 43219",
      "phone": "+1 202-555-0163",
      "email": "quotes@lumenslate.example.com",
      "website": "lumenslate.example.com"
    },
    "sales_rep": {
      "name": "Terrence Boateng",
      "title": "Education Account Manager",
      "email": "t.boateng@lumenslate.example.com",
      "phone": "+1 202-555-0177"
    },
    "customer": {
      "name": "Cedar Hollow Unified School District",
      "contact": "Marisol Etheridge, Director of Instructional Technology",
      "billing_address": "District Office\n410 Schoolhouse Lane\nCedar Hollow, OH 45601",
      "shipping_address": "Receiving Dock, Cedar Hollow Middle School\n1275 Ridgeview Road\nCedar Hollow, OH 45601"
    },
    "quote": {
      "number": "LSQ-2026-24817",
      "issue_date": "2026-09-17",
      "valid_for_days": 45,
      "currency": "USD",
      "locale": "en-US",
      "project": "Grade 6–8 classroom display refresh, 12 rooms",
      "accept_url": "https://quotes.example.com/accept/LSQ-2026-24817",
      "tax_exempt": true,
      "tax_exemption_id": "EX-OH-000417",
      "tax_rate": 0.0725
    },
    "lines": [
      {
        "type": "product",
        "sku": "LS-IFP-75K",
        "name": "75-inch interactive flat panel, 4K",
        "details": "20-point touch, built-in Wi-Fi 6, two stylus pens",
        "quantity": 12,
        "unit_price": 2849,
        "amount": 34188
      },
      {
        "type": "discount",
        "sku": null,
        "name": "Volume discount: 10 or more panels",
        "details": "Applied to LS-IFP-75K",
        "rate": 0.08,
        "amount": -2735.04
      }
    ],
    "shipping": {
      "method": "LTL freight with liftgate delivery",
      "estimate": 1180,
      "lead_time": "3–4 weeks after order"
    },
    "terms": [
      "Payment is due net 30 from the invoice date and requires an approved purchase order.",
      "Freight is an estimate; the final freight charge is invoiced at cost."
    ]
  },
  "output": {
    "format": "pdf",
    "filename": "quote-product-bundle.pdf"
  }
}'