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

# Quantity discount

**Scope:** PIT and POT, all quantity strategies.

## The six configuration decisions

| # | Question                                   | Phase 1 status | Notes                                                            |
| - | ------------------------------------------ | -------------- | ---------------------------------------------------------------- |
| 1 | How many discounted units?                 | Available      | e.g., 1,000 discounted API calls                                 |
| 2 | How often are they refreshed?              | Available      | Monthly, daily, quarterly                                        |
| 3 | What happens to unused units?              | Not available  | Always use-it-or-lose-it in Phase 1                              |
| 4 | When do you pay for overages?              | Available      | Prepaid or postpaid                                              |
| 5 | When do discounted units become available? | Not available  | Follows the line item's lifecycle; no independent start/end date |
| 6 | Total lifetime cap?                        | Available      | e.g., max 1,000 discounted units ever                            |

## Configuration fields

| Field            | Description                                           | Required | Default           |
| ---------------- | ----------------------------------------------------- | -------- | ----------------- |
| `value`          | Discounted units per cadence cycle                    | Yes      | —                 |
| `cadence`        | Refresh frequency (P1M, P1D, P3M, etc.)               | No       | None (per-period) |
| `max_per_period` | Cap on discounted units within a cadence window       | No       | Unlimited         |
| `max_lifetime`   | Cumulative cap on discounted units ever consumed      | No       | Unlimited         |
| `prorate_stub`   | Reduce pool for partial cadence windows               | No       | false             |
| `rounding`       | Rounding for prorated pool (`floor`/`ceil`/`half_up`) | No       | —                 |
| `label`          | Display label on invoice                              | No       | —                 |
| `order`          | Execution order when stacking multiple discounts      | No       | —                 |

## Core calculation

1. **Pool created** — fresh pool of `value` discounted units at each cadence boundary.
2. **Deplete chronologically** — periods within the cadence window consume from the pool in order.
3. **Bill the remainder** — usage beyond the pool is billable.

Resolution formula: `discounted_units = min(value, remaining_pool, max_per_period_remaining, remaining_lifetime)`.

## Cadence behavior

| Relationship                | Example                         | Behavior                                                                                                                               |
| --------------------------- | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| Cadence = billing period    | Monthly cadence, monthly bill   | Each billing period gets its own pool                                                                                                  |
| Cadence > billing period    | Quarterly cadence, monthly bill | Single pool shared across months; depletes chronologically                                                                             |
| Cadence \< billing period   | Daily cadence, monthly bill     | Each day gets its own pool; month-end is the sum of daily overages                                                                     |
| No cadence (`cadence=None`) | —                               | Functionally the same as cadence = billing period: each billing period gets `value` discounted units, but `prorate_stub` doesn't apply |

## Proration

| Scenario                           | Proration?                                    |
| ---------------------------------- | --------------------------------------------- |
| Contract starts or ends mid-window | Yes, if `prorate_stub=true`                   |
| `prorate_stub=false` (default)     | No — full pool for partial windows            |
| Full cadence window                | No — full pool                                |
| `cadence=None`                     | Not applicable — no cadence window to prorate |

```
pool = value × (window_days / full_cadence_days)
1,000 discounted/month, contract starts Jan 15 (17 of 31 days):
Prorated pool = 1,000 × (17/31) = 548.39
```

| Rounding  | 548.39 → | Use case            |
| --------- | -------- | ------------------- |
| `floor`   | 548      | Favors the business |
| `ceil`    | 549      | Favors the customer |
| `half_up` | 548      | Standard rounding   |

For POT, pricing proration operates on the dollar amount for a partial period, while discount proration (`prorate_stub`) operates on the quantity pool — these are different axes and aren't expected to interact. *(Open question: needs eng confirmation.)*

## Lifetime caps

Caps total discounted units **ever consumed**, not pool size. Unused or wasted units don't count toward the cap.

```
100 discounted/month, max 1,000 ever
Month 1:  500 calls. Discounted: 100. Lifetime: 100.
Month 2:  80 calls.  Discounted: 80.  Lifetime: 180. (20 unused ≠ counted)
...
Month 10: 150 calls. Discounted: 100. Lifetime: 980.
Month 11: 200 calls. Discounted: 20 (only 20 left). Lifetime: 1,000.
Month 12+: All billable.
```

| Mechanism      | Axis        | Controls                    |
| -------------- | ----------- | --------------------------- |
| Cadence reset  | Time        | When the pool refreshes     |
| `max_lifetime` | Consumption | Total discounted units ever |

These are orthogonal and can be combined.

## Discount stacking

Multiple discounts coexist via the `order` field. Quantity discounts reduce units first; dollar and percent discounts apply to the resulting amount afterward.

```
50 discounted (order=1) + 20% off (order=2), 200 calls @ $0.01
Step 1: 200 − 50 = 150 billable units
Step 2: 150 × $0.01 = $1.50
Step 3: $1.50 × 80% = $1.20
```

## Interaction with pricing models

| Model               | Quantity discount applicable? | Notes                                                                                       |
| ------------------- | ----------------------------- | ------------------------------------------------------------------------------------------- |
| Per-unit (linear)   | Yes                           | Straightforward — discount reduces units, remainder priced at flat rate                     |
| Volume (non-linear) | Yes                           | Discounted units can shift which bracket the customer lands in, sometimes raising the total |
| Tiered (non-linear) | Yes                           | Fewer units fill fewer tiers; total is always less than or equal to without the discount    |
| Package             | Yes                           | Fewer units means fewer packages                                                            |
| Flat fee            | No                            | Fixed amount regardless of quantity                                                         |
| Percent             | No                            | Based on monetary input, not units                                                          |
| Step                | Yes                           | Fewer units means fewer steps triggered                                                     |

## Invoice presentation

```
API Calls (Jan 1–31, 2026)
  Usage:              3,500 calls
  Quantity Discount:  −1,000 calls (First 1,000 discounted)
  Billable:           2,500 calls
  Rate:               $0.001/call
  Amount:             $2.50
```

With a lifetime cap shown:

```
API Calls (Nov 1–30, 2026)
  Usage:              200 calls
  Quantity Discount:  −20 calls (20 of 1,000 lifetime remaining)
  Billable:           180 calls
  Rate:               $0.001/call
  Amount:             $0.18
  Lifetime discounted: 1,000 / 1,000 (exhausted)
```

Each period produces a breakdown record with: quantity before and after discount, discount applied, pool before and after, lifetime used, and whether any cap was hit.

## Risks and edge cases

| Scenario                                    | Handling                                                           |
| ------------------------------------------- | ------------------------------------------------------------------ |
| Cadence > billing period = budget depletion | "500/quarter" depletes across 3 months, not 500/month              |
| Discount order                              | Quantity discounts reduce units first, then dollar discounts apply |

## Glossary

| Term              | Definition                                                                   |
| ----------------- | ---------------------------------------------------------------------------- |
| Quantity discount | Discounted units that offset billable consumption or allocation              |
| Pool              | Discounted units available within a cadence window; depletes chronologically |
| Cadence           | Refresh frequency for the pool (daily, monthly, quarterly)                   |
| Cadence window    | Time span covered by one pool instance                                       |
| `max_per_period`  | Cap on discounted units within a single cadence window                       |
| `max_lifetime`    | Cumulative cap on discounted units ever consumed                             |
| Prorate stub      | Proportional pool reduction for partial cadence windows                      |
| Discount stacking | Multiple discounts on one product, ordered by the `order` field              |
| Breakdown         | Per-period audit record: pool state, discount applied, cap status            |

## Out of scope / deferred

| Feature                 | Description                                                                 |
| ----------------------- | --------------------------------------------------------------------------- |
| Carryover               | `percentage`, `all`, `fixed` strategies with `max_balance` caps             |
| Expiry models           | `end_of_grant_period`, `end_of_billing_period`, `end_of_contract`, `custom` |
| Grant timing            | `on_purchase`/`on_payment` triggers; `delay` for trials                     |
| Per-event scope         | `scope="per_event"` — "5 discounted per purchase"                           |
| `max_per_event`         | Per-event cap (requires event-level data)                                   |
| Prepaid entitlements    | Grant records, dashboard balance, real-time tracking                        |
| Batch-based expiry      | Independent batches with FIFO consumption                                   |
| Faucet-and-bucket       | Separate grant cadence from expiry boundary                                 |
| Cross-product discounts | Shared pool across multiple products                                        |

## Open questions

| # | Question                                                                                                              | Status               |
| - | --------------------------------------------------------------------------------------------------------------------- | -------------------- |
| 1 | Does the discount need an independent validity period, or does it always follow the line item's lifecycle?            | Needs clarification  |
| 2 | Is `cadence=None` meant to be identical to cadence = billing period, or a distinct one-time discount concept?         | Needs clarification  |
| 3 | For POT amendments mid-period, is the full discount `value` applied independently to each segment?                    | Needs eng validation |
| 4 | Does POT need a time-limited discount concept (e.g., "50 discounted seats for 6 months, then full price")?            | Needs clarification  |
| 5 | Can it be confirmed that POT pricing proration (dollar amount) and discount proration (pool quantity) never interact? | Needs eng validation |

*(Placeholder: status of open questions should be confirmed before this doc is published externally.)*
