Pricing Rules by Capacity & Demand
Adjust package prices based on real-time booking demand and seat availability.
Note: Past-performance rules (Total GMV / Total Cover / Total Booking over a historical period) are a separate rule type (
performance_based) and are documented separately. This PRD covers only demand and capacity signals derived from seat availability.
Demand & Capacity-Based Rule
Automatically adjusts prices according to real-time booking demand and seat availability.
| Aspect | Behavior |
|---|---|
| Condition Check | Real-time |
| Seat Scope | Per time window (aggregate across 15-minute slots) |
| Approval | Auto-approve or Always require approval (user choice) |
Condition Options
| Metric | Description | Relation |
|---|---|---|
| Total Seats Booked (absolute) | Total seats already booked across all 15-minute slots in the rule’s time window for a given date | >, <, >=, <=, =, between |
| Total Seats Booked (%) | Percentage of total capacity booked across all 15-minute slots in the rule’s time window for a given date | >, <, >=, <=, =, between |
| Total Seats Remaining (absolute) | Total seats still available across all 15-minute slots in the rule’s time window for a given date | >, <, >=, <=, =, between |
| Total Seats Remaining (%) | Percentage of total capacity still available across all 15-minute slots in the rule’s time window for a given date | >, <, >=, <=, =, between |
Action
By Percentage (%) or By Fixed Amount.
Scenarios
| Scenario | Condition | Behavior |
|---|---|---|
| A | Total Seats Booked > N (absolute) | Increase price when aggregate bookings across the window exceed N |
| B | Total Seats Remaining < N (absolute) | Increase price when aggregate remaining seats across the window fall below N |
| C | Total Seats Booked > N% (%) | Increase price when aggregate % booked across the window exceeds N% |
| D | Total Seats Remaining < N% (%) | Increase price when aggregate % remaining across the window falls below N% |
| E | Total Seats Booked between N% and M% | Apply tiered pricing for mid-demand range across the window |
| F | Total Seats Remaining between N and M | Apply discount when aggregate availability is in a specific range |
Scenario Examples
The tables below use hourly labels for readability. The actual capacity data is stored and evaluated at 15-minute granularity (e.g., 9:00, 9:15, 9:30, 9:45, …). The hourly values represent the aggregate of the underlying 15-minute records.
Scenario 1 — High-demand lunch window
- Rule: Jan 1-15, 9am-12pm, Mon-Sun
- Condition: Total Seats Booked > 48 pax
- Action: Increase price by 10%
- Result: When aggregate bookings across the 9am-12pm window exceed 48 pax, every API slot within the window is priced at +10%.
| Date | 9am-9:59 | 10am-10:59 | 11am-11:59 | Window total (9am-12pm) | Price for slots in [9:00, 12:00) |
|---|---|---|---|---|---|
| 1 Jan | 10 | 20 | 20 | 50 | 110 |
| 2 Jan | 5 | 0 | 5 | 10 | 100 |
| 3 Jan | 0 | 2 | 4 | 6 | 100 |
Window 9am-12pm includes all 15-minute slots whose start time is
>= 09:00and< 12:00(e.g., 9:00, 9:15, …, 11:45). Slots starting at 12:00 are outside the window.
Scenario 2 — Low-demand weekday window
- Rule: Mon-Fri, 11am-3pm
- Condition: Total Seats Booked < 20 pax
- Action: Decrease price by 20%
- Result: When aggregate bookings across the 11am-3pm window are below 20 pax, every API slot within the window is priced at -20%.
| Day | 10am-10:59 | 11am-11:59 | 12pm-12:59 | 1pm-1:59 | 2pm-2:59 | Window total (11am-3pm) | Price for slots in [11:00, 15:00) |
|---|---|---|---|---|---|---|---|
| Sunday | 10 | 20 | 20 | 30 | 40 | — | 100 |
| Monday | 5 | 0 | 5 | 0 | 5 | 10 | 80 |
| Tuesday | 0 | 20 | 4 | 30 | 2 | 56 | 100 |
Window 11am-3pm includes all 15-minute slots whose start time is
>= 11:00and< 15:00(e.g., 11:00, 11:15, …, 14:45). Slots starting at 15:00 are outside the window.
Note on Scenario 2: The “Between 10-20 pax” note in the Excel refers to a separate
betweenscenario/condition type, not the< 20 paxrule shown above.
Scope of Seat (Demand & Capacity)
- Per time window — Capacity is aggregated across all 15-minute time slots that fall within the rule’s configured time window for a given date.
- Time slot granularity — 15 minutes, matching the
hh-serverAPI v5available_start_times_based_on_packages.jsonresponse format. - Window boundary semantics — A 15-minute slot is included in the window if its start time is
>= window_start_timeand< window_end_time([start, end)). For example, a rule “11am-3pm” includes all 15-minute slots starting at 11:00, 11:15, …, 14:45, but excludes slots starting at 15:00. - API slot price adjustment — The price adjustment applies only to API slots whose
start_timefalls within the rule window. Adjacent 15-minute records are aggregated for evaluation, but the visible time-picker slot must lie inside the window to receive the adjusted price. - Time slot allotment — Uses total allotment count, not remaining inventory after cancellations.
When seat scope is per time window, the system:
- Sums the relevant capacity metric across all 15-minute slots in the window for the date.
- Compares the aggregate value against the rule’s threshold.
- Applies the price adjustment uniformly to every API slot whose
start_timefalls within the window if the condition matches.
Threshold Relations
gt— greater than (>)gte— greater than or equal (>=)lt— less than (<)lte— less than or equal (<=)eq— equal (=)between— inclusive range[value_min, value_max]
A single Demand & Capacity rule can contain multiple conditions and/or condition items, enabling tiered pricing such as:
- 0–50% booked: base price
- 51–80% booked: +5%
- 81–100% booked: +10%
Composition with Date & Time Rules
A Demand & Capacity rule is a single pricing_rule record that combines two
checks on the same rule:
- Date & time eligibility — the rule’s
date_time_conditions_attributeswindow (same vocabulary as Specific Date & Time:everyday,specific_date,specific_time,specific_date_time,day_of_week,day_time_of_week) determines when the rule is eligible. - Capacity threshold — the aggregate capacity across the rule’s time window determines whether the rule fires for the requested date.
Both checks must pass for the rule to apply to a slot. This is an AND relationship within the rule.
Within-rule: multiple demand conditions
A single Demand & Capacity rule may contain multiple
demand_capacity_conditions_attributes. If more than one condition matches the
aggregate capacity, all matching conditions apply cumulatively (see
PricingEngine/013-DEMAND-CAPACITY-CONDITIONS.md).
Cross-rule: interaction with other pricing_rule records
Demand & Capacity rules and Specific Date & Time rules are sibling rule
types stored as separate pricing_rule records. When a diner opens the time
picker, pricing-engine evaluates all active rules whose date/time window
contains the requested slot.
The end-to-end resolution happens in two layers:
-
pricing-engine customer API (
get_available_rules_by_time)- Per package, per slot, selects up to 2 rules: one
percentageand onefixed. - Selection order: lowest
priority→ highestweight→ newestcreated_at. - Decrease rules are preferred over increase rules when both are available.
- See
PricingEngine/016-CUSTOMER-BOOKING-API.mdandPricingEngine/014-PRICE-MODIFIER.mdfor the exact algorithm.
- Per package, per slot, selects up to 2 rules: one
-
hh-pegasus FE (
getDynamicPricingV2Rule)- Receives the up-to-2 rules from the API.
- Picks exactly ONE rule to display and book:
- If any
decreaserule exists, pick the one with the biggest discount (best for the diner). - Otherwise, pick the
increaserule with the smallest surcharge.
- If any
- Therefore, the diner sees only one price adjustment per slot/package at a time, even when multiple backend rules match.
A standalone Specific Date & Time rule and a standalone Demand & Capacity rule that both match the same slot do not stack multiplicatively. Priority/value resolution at the engine layer, followed by the FE’s best-for-diner selection, determines which single adjustment is shown.
Example
- Rule A (Specific Date & Time): every Friday, +10%,
value_type=percentage,priority= 10. - Rule B (Demand & Capacity): Friday 7pm–9pm, if total seats booked ≥ 20,
+5%,
value_type=percentage,priority= 5.
For a Friday 7:30pm slot when 25 seats are already booked:
- Both Rule A and Rule B match.
- The engine returns both (same
value_type, so up to 2 rules possible). - The engine priority resolution selects Rule B (lower
prioritynumber = higher precedence). - hh-pegasus
getDynamicPricingV2Ruleconfirms Rule B is the best increase rule and displays the slot at 105. - If Rule B had
priority= 15, Rule A would win and the price would be 110.
Date/time window vs. capacity aggregation window
Do not confuse the two windows:
- Date/time eligibility window — defined by the rule’s
date_typeandcondition_items. It determines which calendar dates and clock times the rule is eligible to run. A slot must lie inside this window to be considered. - Capacity aggregation window — for the requested date, the rule aggregates
capacity across all 15-minute slots whose
start_timefalls inside the rule’sstart_time/end_time. This aggregate is what the threshold compares against.
In most configurations these windows are the same time range, but the model allows them to differ if future rule types need it.
Customer-Facing Behaviour
Demand & Capacity rules are evaluated per time window in the booking picker. The result is surfaced to the diner as:
- Per-slot price label in the time picker (
packages/shared-ui/src/components/time-picker/TimePickerButton2.vue) — every API slot whosestart_timelies within the matched window shows the same adjusted price. low-price/high-demandstyling based on whether the adjusted price is lower or higher than the base price.- Real-time evaluation every time the customer opens the time picker for a date, via
POST /api/v1/get_available_rules_by_time.
Because evaluation is per time window, multiple adjacent API slots on the same date share the same adjusted price when demand conditions are met.
See the full customer flow in Dynamic Pricings 2.0 — Customer Booking Flow (HH Pegasus).
Related
- Customer-facing flow (HH Pegasus): Dynamic Pricings 2.0 — Customer Booking Flow
- HH Server integration: Dynamic Pricings 2.0 — HH Server Integration
- pricing-engine customer API: Customer Booking API
- Implementation plan: Capacity & Demand Implementation Plan
- Engineering spec:
PricingEngine/013-DEMAND-CAPACITY-CONDITIONS.md - Sibling PRDs: Date & Time, AI (Rapidcanvas)