Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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 adult with 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_rules array as normal price for that package and slot.
  • The public response remains compact: id, action_type, value_type, and value.

2. Request parameters

2.1 Common parameters

FieldRequiredNotes
restaurant_idYesRestaurant being priced.
restaurant_package_idsYesOne or more package IDs.
adultNo at HTTP level; required for capacity selectionAlias for requested_seats. Send the actual party size.
requested_seatsNoInternal alias. Takes precedence over adult when both are supplied.
projection_modeNoDefaults 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 seatsAdjustment
1–1020% decrease
11–2010% decrease
Outside both rangesNo demand-capacity modifier

If the snapshot has seats_booked = 9:

adultProjected seatsExpected result
11020% tier
21110% tier
1221Normal 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_typeSchedule matchCapacity observation
everydayEvery date within the parent rule periodAll snapshots for the date.
specific_dateThe condition’s date windowAll snapshots for the date; this is date-only even when the time endpoint returns slots.
specific_timeRequested time inside the condition time windowSnapshots inside the matching time window.
specific_date_timeRequested date and time inside the condition windowSnapshots inside the matching time window on the matching date.
day_of_weekRequested weekdayAll snapshots for the date.
day_time_of_weekRequested weekday and time windowSnapshots 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_booked can still be evaluated as 0 + adult;
  • remaining_seats cannot be evaluated without total_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_typeMeaningExample
percentageDirect percentage value10.0 means 10%, not 0.1% or 1000 basis points.
fixedExisting smallest currency unit contract500.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.

  1. Send the date request with adult when loading available dates.
  2. Send the time request with the same adult when a date is selected.
  3. Read modifiers from the selected package’s slot-level pricing_rules.
  4. Recalculate if the party size, date, time, or package changes.
  5. Before final booking, verify the selected rules with requested_seats_already_held only when the hold is already reflected in capacity.
  6. Treat an empty result as normal price and do not invent a modifier on the frontend.