Demand & Capacity Pricing — Frontend API Guide
This guide describes how a frontend or booking client requests demand-capacity
pricing from Pricing Engine. It is based on the current public API contract and
does not require a new pricing_context response.
1. Integration rules
- Use the existing date and time pricing endpoints.
- Send
adultwith the actual requested party size whenever the client needs a demand-capacity price. - Do not calculate booked seats in the frontend. Pricing Engine reads capacity snapshots and adds the requested seats once.
- Do not convert percentage or fixed values. Apply the returned value exactly once using the existing book-bite/Pegasus pricing behavior.
- Treat an empty
pricing_rulesarray as normal price for that package and slot. - The public response remains compact:
id,action_type,value_type, andvalue.
2. Request parameters
2.1 Common parameters
| Field | Required | Notes |
|---|---|---|
restaurant_id | Yes | Restaurant being priced. |
restaurant_package_ids | Yes | One or more package IDs. |
adult | No at HTTP level; required for capacity selection | Alias for requested_seats. Send the actual party size. |
requested_seats | No | Internal alias. Takes precedence over adult when both are supplied. |
projection_mode | No | Defaults to add_requested_seats. |
The request remains valid without adult or requested_seats, but the engine
cannot infer party size from booked capacity. In that case, demand-capacity
modifiers are omitted and only non-capacity rules can be returned.
adult: 0 is accepted for local tools and simulations. Customer booking flows
should send a positive adult count when evaluating capacity tiers.
2.2 Projection modes
Use the default mode for quotes and validation before the requested seats are represented in the capacity snapshot:
{
"projection_mode": "add_requested_seats"
}
The evaluated value is:
projected_seats = capacity_snapshot.seats_booked + requested_seats
Use requested_seats_already_held only for final validation after the hold is
already included in capacity:
{
"projection_mode": "requested_seats_already_held"
}
In that mode, the snapshot is used directly and the same adult count is not added again. An unsupported projection mode or malformed seat value returns HTTP 400.
3. Date pricing
Endpoint
POST /api/v1/get_available_rules_by_date?restaurant_id=123
Content-Type: application/json
Request
{
"restaurant_id": "123",
"start_date": "2026-08-01",
"end_date": "2026-08-10",
"restaurant_package_ids": ["4300"],
"adult": 2
}
The date endpoint evaluates each date in the requested range and preserves its existing date-summary response. The frontend should request the selected time again from the time endpoint before displaying or locking a final slot price.
The response shape remains the existing compact shape:
{
"success": true,
"status": true,
"message": null,
"data": [
{
"date": "2026-08-01",
"packages": [
{
"restaurant_package_id": "4300",
"currency": "THB",
"pricing_rules": [
{
"id": 501,
"action_type": "decrease",
"value_type": "percentage",
"value": 20.0
}
]
}
]
}
]
}
4. Time-slot pricing
Endpoint
POST /api/v1/get_available_rules_by_time?restaurant_id=123
Content-Type: application/json
Request
{
"restaurant_id": "123",
"date": "2026-08-01",
"restaurant_package_ids": ["4300"],
"adult": 2
}
Response
The endpoint returns the existing 15-minute slot list. Demand-capacity rules
are included inside the existing packages[].pricing_rules array:
{
"success": true,
"status": true,
"message": null,
"data": [
{
"start_time": "18:00",
"packages": [
{
"restaurant_package_id": "4300",
"currency": "THB",
"pricing_rules": [
{
"id": 501,
"action_type": "decrease",
"value_type": "percentage",
"value": 20.0
}
]
}
]
}
]
}
The frontend must not assume that a modifier applies to every slot. Inspect the
pricing_rules array for each package and each start_time.
5. Tier selection example
Given one parent rule with these tiers:
| Projected booked seats | Adjustment |
|---|---|
| 1–10 | 20% decrease |
| 11–20 | 10% decrease |
| Outside both ranges | No demand-capacity modifier |
If the snapshot has seats_booked = 9:
adult | Projected seats | Expected result |
|---|---|---|
| 1 | 10 | 20% tier |
| 2 | 11 | 10% tier |
| 12 | 21 | Normal price |
The frontend sends the party size and consumes the returned modifier. It does not select the tier itself.
6. Date-type behavior
Demand-capacity conditions use the same six date types as the pricing rule contract:
date_type | Schedule match | Capacity observation |
|---|---|---|
everyday | Every date within the parent rule period | All snapshots for the date. |
specific_date | The condition’s date window | All snapshots for the date; this is date-only even when the time endpoint returns slots. |
specific_time | Requested time inside the condition time window | Snapshots inside the matching time window. |
specific_date_time | Requested date and time inside the condition window | Snapshots inside the matching time window on the matching date. |
day_of_week | Requested weekday | All snapshots for the date. |
day_time_of_week | Requested weekday and time window | Snapshots inside the matching time window. |
Time ranges are half-open: 12:00–17:00 includes 12:00 through 16:45 and
excludes 17:00. A single condition with equal start and end time matches only
that start time. An open-ended end date or end time continues the same authored
definition without requiring the frontend to create future modifiers.
For a condition with multiple time windows, the engine evaluates the window that matches the requested slot. The frontend should continue treating each slot response independently.
7. Missing capacity snapshots
When adult is supplied but the filtered aggregation set is empty because no
snapshot is available for the requested date or condition window, Pricing Engine
uses seats_booked = 0 as the default state:
total_seats_bookedcan still be evaluated as0 + adult;remaining_seatscannot be evaluated withouttotal_capacity; and- percentage metrics cannot be evaluated without
total_capacity.
This is different from omitting adult: without a requested party size, all
demand-capacity candidates are skipped. The frontend should not display a
capacity diagnostic because the compact public response does not expose one.
8. Package-level endpoint
GET /api/v1/packages_pricing_rules/:restaurant_id
This endpoint has no date, time, or party-size context. It is suitable for
context-free package-level pricing rules, but it does not select
demand-capacity modifiers. Use the date or time endpoint with adult for
capacity-aware pricing.
9. Applying the returned adjustment
Use the existing adjustment pipeline:
value_type | Meaning | Example |
|---|---|---|
percentage | Direct percentage value | 10.0 means 10%, not 0.1% or 1000 basis points. |
fixed | Existing smallest currency unit contract | 500.0 is passed through unchanged. |
Do not multiply percentages by 100, divide them by 100, or convert them to
basis points. Apply action_type exactly once.
10. Recommended frontend flow
- Send the date request with
adultwhen loading available dates. - Send the time request with the same
adultwhen a date is selected. - Read modifiers from the selected package’s slot-level
pricing_rules. - Recalculate if the party size, date, time, or package changes.
- Before final booking, verify the selected rules with
requested_seats_already_heldonly when the hold is already reflected in capacity. - Treat an empty result as normal price and do not invent a modifier on the frontend.