Skip to content

8.5 × 11 in

Purchase orders

Blanket purchase order

A US Letter blanket purchase order: an agreed price list with committed quantities, a month-by-item delivery schedule built with nested loops, the total committed value against a not-to-exceed ceiling, release conditions in Markdown and signature lines.

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
  • Currency formatting
  • Date formatting
  • Markdown
  • 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: 8 top-level fields, 47 paths in total. Send the same shape as data.

PathTypeExample
buyerobject
buyer.namestring"Wrenhaven Café Group, Inc."
buyer.addressstring"300 Alder Mill Road, Suite 410 ⏎ Portland, OR …"
buyer.contactstring"Marisol Achterberg"
buyer.contact_titlestring"Purchasing Manager"
buyer.emailstring"purchasing@wrenhaven.example.com"
buyer.phonestring"+1 202-555-0118"
supplierobject
supplier.namestring"Kettlebrook Roasting Collective"
supplier.addressstring"1880 Sawmill Creek Rd ⏎ Eugene, OR 97402"
supplier.vendor_numberstring"V-10233"
supplier.contactstring"Desmond Arkwright"
supplier.emailstring"wholesale@kettlebrook.example.net"
ship_toobject
ship_to.namestring"Wrenhaven Central Kitchen"
ship_to.addressstring"77 Foundry Loop, Dock 2 ⏎ Portland, OR 97210"
ship_to.hoursstring"Tuesdays, 6:00–10:00 AM"
agreementobject
agreement.numberstring"BPO-2026-014"
agreement.issue_datedate"2026-09-15"
agreement.start_datedate"2026-10-01"
agreement.monthsnumber6
agreement.currencystring"USD"
agreement.not_to_exceednumber56000
agreement.payment_termsstring"Net 30 from each delivery"
agreement.freightstring"Delivered, freight included"
price_listarray<object> · 6
price_list[].codestring"KRC-ESP-5"
price_list[].namestring"House espresso blend, whole bean"
price_list[].short_namestring"Espresso"
price_list[].packstring"5 lb bag"
price_list[].unit_pricenumber52.5
price_list[].committed_quantitynumber372
price_list[].committed_valuenumber19530
schedulearray<object> · 6
schedule[].monthdate"2026-10-01"
schedule[].releasestring"R01"
schedule[].delivery_datesarray<date> · 2"2026-10-06"
schedule[].deliveriesarray<object> · 6
schedule[].deliveries[].codestring"KRC-ESP-5"
schedule[].deliveries[].quantitynumber60
schedule[].deliveries[].amountnumber3150
release_conditionsstring"1. **Releases.** Wrenhaven confirms each month…"
signaturesarray<object> · 2
signatures[].labelstring"Authorized for the buyer"
signatures[].namestring"Marisol Achterberg"
signatures[].titlestring"Purchasing Manager"

Sample data

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

data.json
{
  "buyer": {
    "name": "Wrenhaven Café Group, Inc.",
    "address": "300 Alder Mill Road, Suite 410\nPortland, OR 97209",
    "contact": "Marisol Achterberg",
    "contact_title": "Purchasing Manager",
    "email": "purchasing@wrenhaven.example.com",
    "phone": "+1 202-555-0118"
  },
  "supplier": {
    "name": "Kettlebrook Roasting Collective",
    "address": "1880 Sawmill Creek Rd\nEugene, OR 97402",
    "vendor_number": "V-10233",
    "contact": "Desmond Arkwright",
    "email": "wholesale@kettlebrook.example.net"
  },
  "ship_to": {
    "name": "Wrenhaven Central Kitchen",
    "address": "77 Foundry Loop, Dock 2\nPortland, OR 97210",
    "hours": "Tuesdays, 6:00–10:00 AM"
  },
  "agreement": {
    "number": "BPO-2026-014",
    "issue_date": "2026-09-15",
    "start_date": "2026-10-01",
    "months": 6,
    "currency": "USD",
    "not_to_exceed": 56000.0,
    "payment_terms": "Net 30 from each delivery",
    "freight": "Delivered, freight included"
  },
  "price_list": [
    { "code": "KRC-ESP-5", "name": "House espresso blend, whole bean", "short_name": "Espresso", "pack": "5 lb bag", "unit_price": 52.5, "committed_quantity": 372, "committed_value": 19530.0 },
    { "code": "KRC-DRP-5", "name": "Daily drip blend, whole bean", "short_name": "Drip", "pack": "5 lb bag", "unit_price": 46.25, "committed_quantity": 248, "committed_value": 11470.0 },
    { "code": "KRC-DEC-5", "name": "Water-process decaf, whole bean", "short_name": "Decaf", "pack": "5 lb bag", "unit_price": 58.75, "committed_quantity": 50, "committed_value": 2937.5 },
    { "code": "KRC-SO-2", "name": "Seasonal single origin, whole bean", "short_name": "Single origin", "pack": "2 lb bag", "unit_price": 31.8, "committed_quantity": 130, "committed_value": 4134.0 },
    { "code": "KRC-CB-5", "name": "Cold brew blend, coarse ground", "short_name": "Cold brew", "pack": "5 lb bag", "unit_price": 44.0, "committed_quantity": 98, "committed_value": 4312.0 },
    { "code": "KRC-RTL-12", "name": "Retail bags, 12 oz, mixed blends", "short_name": "Retail 12 oz", "pack": "case of 12", "unit_price": 118.8, "committed_quantity": 72, "committed_value": 8553.6 }
  ],
  "schedule": [
    {
      "month": "2026-10-01",
      "release": "R01",
      "delivery_dates": ["2026-10-06", "2026-10-20"],
      "deliveries": [
        { "code": "KRC-ESP-5", "quantity": 60, "amount": 3150.0 },
        { "code": "KRC-DRP-5", "quantity": 40, "amount": 1850.0 },
        { "code": "KRC-DEC-5", "quantity": 8, "amount": 470.0 },
        { "code": "KRC-SO-2", "quantity": 20, "amount": 636.0 },
        { "code": "KRC-CB-5", "quantity": 24, "amount": 1056.0 },
        { "code": "KRC-RTL-12", "quantity": 10, "amount": 1188.0 }
      ]
    },
    {
      "month": "2026-11-01",
      "release": "R02",
      "delivery_dates": ["2026-11-03", "2026-11-17"],
      "deliveries": [
        { "code": "KRC-ESP-5", "quantity": 64, "amount": 3360.0 },
        { "code": "KRC-DRP-5", "quantity": 42, "amount": 1942.5 },
        { "code": "KRC-DEC-5", "quantity": 8, "amount": 470.0 },
        { "code": "KRC-SO-2", "quantity": 24, "amount": 763.2 },
        { "code": "KRC-CB-5", "quantity": 16, "amount": 704.0 },
        { "code": "KRC-RTL-12", "quantity": 14, "amount": 1663.2 }
      ]
    },
    {
      "month": "2026-12-01",
      "release": "R03",
      "delivery_dates": ["2026-12-01", "2026-12-15"],
      "deliveries": [
        { "code": "KRC-ESP-5", "quantity": 70, "amount": 3675.0 },
        { "code": "KRC-DRP-5", "quantity": 48, "amount": 2220.0 },
        { "code": "KRC-DEC-5", "quantity": 10, "amount": 587.5 },
        { "code": "KRC-SO-2", "quantity": 30, "amount": 954.0 },
        { "code": "KRC-CB-5", "quantity": 12, "amount": 528.0 },
        { "code": "KRC-RTL-12", "quantity": 22, "amount": 2613.6 }
      ]
    },
    {
      "month": "2027-01-01",
      "release": "R04",
      "delivery_dates": ["2027-01-05", "2027-01-19"],
      "deliveries": [
        { "code": "KRC-ESP-5", "quantity": 58, "amount": 3045.0 },
        { "code": "KRC-DRP-5", "quantity": 40, "amount": 1850.0 },
        { "code": "KRC-DEC-5", "quantity": 8, "amount": 470.0 },
        { "code": "KRC-SO-2", "quantity": 18, "amount": 572.4 },
        { "code": "KRC-CB-5", "quantity": 12, "amount": 528.0 },
        { "code": "KRC-RTL-12", "quantity": 8, "amount": 950.4 }
      ]
    },
    {
      "month": "2027-02-01",
      "release": "R05",
      "delivery_dates": ["2027-02-02", "2027-02-16"],
      "deliveries": [
        { "code": "KRC-ESP-5", "quantity": 58, "amount": 3045.0 },
        { "code": "KRC-DRP-5", "quantity": 38, "amount": 1757.5 },
        { "code": "KRC-DEC-5", "quantity": 8, "amount": 470.0 },
        { "code": "KRC-SO-2", "quantity": 18, "amount": 572.4 },
        { "code": "KRC-CB-5", "quantity": 14, "amount": 616.0 },
        { "code": "KRC-RTL-12", "quantity": 8, "amount": 950.4 }
      ]
    },
    {
      "month": "2027-03-01",
      "release": "R06",
      "delivery_dates": ["2027-03-02", "2027-03-16"],
      "deliveries": [
        { "code": "KRC-ESP-5", "quantity": 62, "amount": 3255.0 },
        { "code": "KRC-DRP-5", "quantity": 40, "amount": 1850.0 },
        { "code": "KRC-DEC-5", "quantity": 8, "amount": 470.0 },
        { "code": "KRC-SO-2", "quantity": 20, "amount": 636.0 },
        { "code": "KRC-CB-5", "quantity": 20, "amount": 880.0 },
        { "code": "KRC-RTL-12", "quantity": 10, "amount": 1188.0 }
      ]
    }
  ],
  "release_conditions": "1. **Releases.** Wrenhaven confirms each monthly release in writing by the 20th of the previous month. A release fixes the delivery dates and quantities for that month.\n2. **Flexibility.** A release may move up to 15% above or below the scheduled quantity for any item at the agreed unit price. Larger changes need written agreement from both parties.\n3. **Prices.** Unit prices in the price list stay fixed for the whole agreement period.\n4. **Ceiling.** The total of all releases must stay within the not-to-exceed amount. The supplier should not ship quantities that would take the agreement above it.\n5. **Freshness.** Every bag shows its roast date, and coffee arrives no more than 7 days after roasting.\n6. **Invoicing.** Invoice each delivery separately and quote both the agreement number and the release number.",
  "signatures": [
    { "label": "Authorized for the buyer", "name": "Marisol Achterberg", "title": "Purchasing Manager" },
    { "label": "Accepted for the supplier", "name": "Desmond Arkwright", "title": "Wholesale Director" }
  ]
}

Source

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

{#- Blanket purchase order: an agreed price list plus a monthly delivery schedule (months × items). -#}
{%- set locale = "en-US" -%}
{%- set currency = agreement.currency -%}
{%- set end_date = agreement.start_date | date_add(months=agreement.months) | date_add(days=-1) -%}
{%- set committed = price_list | sum_by("committed_value") -%}
{%- set headroom = agreement.not_to_exceed - committed -%}
{%- set used_share = (committed / agreement.not_to_exceed * 100) | round(1) -%}

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

<header class="masthead">
  <div>
    <p class="kicker">{{ buyer.name }}</p>
    <h1>Blanket purchase order</h1>
    <p class="subtitle">Framework agreement for scheduled monthly releases</p>
  </div>
  <div class="doc-number">
    <span>Agreement</span>
    <strong>{{ agreement.number }}</strong>
    <span>Issued {{ agreement.issue_date | format_date("long", locale) }}</span>
  </div>
</header>

<section class="parties">
  <div>
    <p class="label">Buyer</p>
    <p class="name">{{ buyer.name }}</p>
    <p>{{ buyer.address | nl2br }}</p>
    <p class="muted">{{ buyer.contact }}, {{ buyer.contact_title }}<br>{{ buyer.email }} · {{ buyer.phone }}</p>
  </div>
  <div>
    <p class="label">Supplier</p>
    <p class="name">{{ supplier.name }}</p>
    <p>{{ supplier.address | nl2br }}</p>
    <p class="muted">Vendor {{ supplier.vendor_number }} · {{ supplier.contact }}<br>{{ supplier.email }}</p>
  </div>
  <div>
    <p class="label">Ship to</p>
    <p class="name">{{ ship_to.name }}</p>
    <p>{{ ship_to.address | nl2br }}</p>
    <p class="muted">Receiving: {{ ship_to.hours }}</p>
  </div>
</section>

<section class="terms-strip">
  <div><span>Agreement period</span><strong>{{ agreement.start_date | format_date("medium", locale) }} – {{ end_date | format_date("medium", locale) }}</strong></div>
  <div><span>Term</span><strong>{{ agreement.months }} months</strong></div>
  <div><span>Payment terms</span><strong>{{ agreement.payment_terms }}</strong></div>
  <div><span>Freight</span><strong>{{ agreement.freight }}</strong></div>
</section>

<h2 class="section-title"><span>1</span>Agreed price list</h2>
<table class="grid prices">
  <thead>
    <tr>
      <th scope="col">Item code</th>
      <th scope="col">Description</th>
      <th scope="col">Pack</th>
      <th class="num" scope="col">Unit price</th>
      <th class="num" scope="col">Committed qty</th>
      <th class="num" scope="col">Committed value</th>
    </tr>
  </thead>
  <tbody>
    {%- for item in price_list %}
    <tr>
      <td class="code">{{ item.code }}</td>
      <td>{{ item.name }}</td>
      <td class="muted">{{ item.pack }}</td>
      <td class="num">{{ money(item.unit_price) }}</td>
      <td class="num">{{ item.committed_quantity }}</td>
      <td class="num">{{ money(item.committed_value) }}</td>
    </tr>
    {%- endfor %}
  </tbody>
</table>

<section class="commitment">
  <div class="figures">
    <div><span>Total committed value</span><strong>{{ money(committed) }}</strong></div>
    <div><span>Not-to-exceed amount</span><strong>{{ money(agreement.not_to_exceed) }}</strong></div>
    <div><span>Headroom for variations</span><strong>{{ money(headroom) }}</strong></div>
  </div>
  <div class="meter" aria-hidden="true">
    <span class="meter-fill" style="width: {{ used_share }}%"></span>
  </div>
  <p class="meter-note">{{ (committed / agreement.not_to_exceed) | format_percent(locale, 1) }} of the not-to-exceed amount is scheduled below; {{ (headroom / agreement.not_to_exceed) | format_percent(locale, 1) }} remains for approved variations.</p>
</section>

<h2 class="section-title"><span>2</span>Monthly delivery schedule</h2>
<table class="grid schedule">
  <thead>
    <tr>
      <th class="rel" scope="col">Release</th>
      <th class="month" scope="col">Month and deliveries</th>
      {%- for item in price_list %}
      <th class="num qty" scope="col">{{ item.short_name }}</th>
      {%- endfor %}
      <th class="num value" scope="col">Value</th>
    </tr>
  </thead>
  <tbody>
    {%- for month in schedule %}
    <tr>
      <td class="rel">{{ agreement.number }}-{{ month.release }}</td>
      <td class="month">
        <strong>{{ month.month | format_date("%B %Y", locale) }}</strong>
        <span class="drops">
          {%- for day in month.delivery_dates %}{{ day | format_date("%m/%d", locale) }}{{ " · " if not loop.last else "" }}{% endfor -%}
        </span>
      </td>
      {%- for item in price_list %}
      {%- set delivery = month.deliveries | selectattr("code", "eq", item.code) | first %}
      <td class="num qty">{% if delivery %}{{ delivery.quantity }}{% else %}<span class="muted">–</span>{% endif %}</td>
      {%- endfor %}
      <td class="num value">{{ money(month.deliveries | sum_by("amount")) }}</td>
    </tr>
    {%- endfor %}
  </tbody>
  <tfoot>
    <tr>
      <th colspan="2" scope="row">Total, {{ schedule | length }} monthly releases</th>
      {%- for item in price_list %}
      <td class="num qty">{{ item.committed_quantity }}</td>
      {%- endfor %}
      <td class="num value">{{ money(committed) }}</td>
    </tr>
  </tfoot>
</table>
<p class="table-note">Quantities are in packs as listed in the price list. Each release number is quoted on delivery notes and invoices.</p>

<section class="conditions">
  <h2 class="section-title"><span>3</span>Release conditions</h2>
  <div class="conditions-body">{{ release_conditions | markdown }}</div>
</section>

<section class="signatures">
  {%- for signer in signatures %}
  <div class="signature">
    <p class="label">{{ signer.label }}</p>
    <div class="sign-line"></div>
    <p class="signer">{{ signer.name }}, {{ signer.title }}</p>
    <p class="muted">Date</p>
  </div>
  {%- endfor %}
</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": {
    "buyer": {
      "name": "Wrenhaven Café Group, Inc.",
      "address": "300 Alder Mill Road, Suite 410\nPortland, OR 97209",
      "contact": "Marisol Achterberg",
      "contact_title": "Purchasing Manager",
      "email": "purchasing@wrenhaven.example.com",
      "phone": "+1 202-555-0118"
    },
    "supplier": {
      "name": "Kettlebrook Roasting Collective",
      "address": "1880 Sawmill Creek Rd\nEugene, OR 97402",
      "vendor_number": "V-10233",
      "contact": "Desmond Arkwright",
      "email": "wholesale@kettlebrook.example.net"
    },
    "ship_to": {
      "name": "Wrenhaven Central Kitchen",
      "address": "77 Foundry Loop, Dock 2\nPortland, OR 97210",
      "hours": "Tuesdays, 6:00–10:00 AM"
    },
    "agreement": {
      "number": "BPO-2026-014",
      "issue_date": "2026-09-15",
      "start_date": "2026-10-01",
      "months": 6,
      "currency": "USD",
      "not_to_exceed": 56000,
      "payment_terms": "Net 30 from each delivery",
      "freight": "Delivered, freight included"
    },
    "price_list": [
      {
        "code": "KRC-ESP-5",
        "name": "House espresso blend, whole bean",
        "short_name": "Espresso",
        "pack": "5 lb bag",
        "unit_price": 52.5,
        "committed_quantity": 372,
        "committed_value": 19530
      },
      {
        "code": "KRC-DRP-5",
        "name": "Daily drip blend, whole bean",
        "short_name": "Drip",
        "pack": "5 lb bag",
        "unit_price": 46.25,
        "committed_quantity": 248,
        "committed_value": 11470
      }
    ],
    "schedule": [
      {
        "month": "2026-10-01",
        "release": "R01",
        "delivery_dates": [
          "2026-10-06",
          "2026-10-20"
        ],
        "deliveries": [
          {
            "code": "KRC-ESP-5",
            "quantity": 60,
            "amount": 3150
          },
          {
            "code": "KRC-DRP-5",
            "quantity": 40,
            "amount": 1850
          }
        ]
      },
      {
        "month": "2026-11-01",
        "release": "R02",
        "delivery_dates": [
          "2026-11-03",
          "2026-11-17"
        ],
        "deliveries": [
          {
            "code": "KRC-ESP-5",
            "quantity": 64,
            "amount": 3360
          },
          {
            "code": "KRC-DRP-5",
            "quantity": 42,
            "amount": 1942.5
          }
        ]
      }
    ],
    "release_conditions": "1. **Releases.** Wrenhaven confirms each monthly release in writing by the 20th of the previous month. A release fixes the delivery dates and quantities for that month.\n2. **Flexibility.** A release may move up to 15% above or below the scheduled quantity for any item at the agreed unit price. Larger changes need written agreement from both parties.\n3. **Prices.** Unit prices in the price list stay fixed for the whole agreement period.\n4. **Ceiling.** The total of all releases must stay within the not-to-exceed amount. The supplier should not ship quantities that would take the agreement above it.\n5. **Freshness.** Every bag shows its roast date, and coffee arrives no more than 7 days after roasting.\n6. **Invoicing.** Invoice each delivery separately and quote both the agreement number and the release number.",
    "signatures": [
      {
        "label": "Authorized for the buyer",
        "name": "Marisol Achterberg",
        "title": "Purchasing Manager"
      },
      {
        "label": "Accepted for the supplier",
        "name": "Desmond Arkwright",
        "title": "Wholesale Director"
      }
    ]
  },
  "output": {
    "format": "pdf",
    "filename": "purchase-order-blanket.pdf"
  }
}'