A rental product has no single price — it has a set of tiers, and what a customer pays depends on the dates they picked, how long that is, how many they want, what group they are in, and whether their dates land on a special or surge period. Two queries expose that: rentalProductPrice quotes one specific set of dates, and rentalProductPriceList returns the configured tiers so you can render a pricing card. Neither needs a token.
Quoting a set of dates #
query Quote {
rentalProductPrice(input: {
sku: "CANON-R6"
start_date: "2026-12-24 09:00:00"
end_date: "2026-12-28 17:00:00"
qty: 2
}) {
price
row_total
currency
has_special_pricing
duration { minutes hours days weeks months }
breakdown {
label
period_type
period_quantity
start_date
end_date
price
is_special
}
}
}
{
"data": {
"rentalProductPrice": {
"price": 265.00,
"row_total": 530.00,
"currency": "GBP",
"has_special_pricing": true,
"duration": { "minutes": 5880, "hours": 98, "days": 4, "weeks": 0.5833, "months": 0.1361 },
"breakdown": [
{
"label": "Christmas surge",
"period_type": null,
"period_quantity": null,
"start_date": "2026-12-24 09:00:00",
"end_date": "2026-12-26 23:59:59",
"price": 150.00,
"is_special": true
},
{
"label": "2 days",
"period_type": "day",
"period_quantity": 2,
"start_date": "2026-12-27 00:00:00",
"end_date": "2026-12-28 17:00:00",
"price": 115.00,
"is_special": false
}
]
}
}
}
priceis the unit price for the whole period, excluding tax.row_totalisprice × qty.breakdownshows how the engine carved the period up: one entry for each date-based pricing period that matched (labelled with that period’s name), plus one for each stretch left over that the standard tiers priced. The entries sum toprice.has_special_pricingis true only when a special or surge period actually contributed to the total. Where a special would have made the hire more expensive than the plain tiers, the engine keeps the cheaper plain price — and then this stays false and the breakdown shows the plain tiers, so it never claims credit for something that is not in the number.currencyis the store’s display currency.
The dates that come back may not be the dates you sent #
start_date and end_date in the response are the dates the pricing engine actually priced, which are not always the ones you asked about. A product that does not use times has its end pushed to the end of the day; a single-day product is collapsed to one day; products configured to add time to the calculation get their end moved accordingly. duration describes that same normalised span, so the two always agree with each other and with price. For ordinary inputs on an ordinary product they are identical to what you sent.
Reading duration #
minutes, hours and days are whole elapsed units rounded down; weeks and months are fractional, with a month counted as 30 days — the same arithmetic the tiers themselves use, so a duration of weeks: 1.0 is exactly the span a one-week tier covers.
Turning parts of the calculation off #
include_specials: false ignores date-based pricing periods and include_price_rules: false ignores catalog price rules. Both default to true. They are useful for showing a customer what they saved, or for a back-office screen that needs the list price:
rentalProductPrice(input: {
sku: "CANON-R6"
start_date: "2026-12-24 09:00:00"
end_date: "2026-12-28 17:00:00"
include_specials: false
}) { price }
The price list #
For a pricing card on a product page — the tiers themselves, with no dates involved.
query PricingCard {
rentalProductPriceList(sku: "CANON-R6") {
currency
customer_group_id
items {
period_type
period_quantity
price
additional_price
additional_period_type
qty_start
qty_end
is_special
special_name
}
}
}
{
"items": [
{ "period_type": "day", "period_quantity": 1, "price": 65.00, "additional_price": 45.00,
"additional_period_type": "day", "qty_start": 1, "qty_end": null,
"is_special": false, "special_name": null },
{ "period_type": "week", "period_quantity": 1, "price": 260.00, "additional_price": null,
"additional_period_type": null, "qty_start": 1, "qty_end": null,
"is_special": false, "special_name": null },
{ "period_type": "day", "period_quantity": 1, "price": 95.00, "additional_price": null,
"additional_period_type": null, "qty_start": 1, "qty_end": null,
"is_special": true, "special_name": "Christmas surge" }
]
}
additional_priceis what each period beyond the tier costs — the first row above reads “£65 for the first day, £45 for each further day”.qty_start/qty_endbound the quantity a tier applies to, for volume pricing. Anullqty_endmeans no upper bound.is_special: truerows belong to a date-based pricing period named byspecial_name. They only apply on that period’s dates, so label them accordingly rather than showing them as if they were always available.period_typeisminute,hour,day,week,monthoryear.- Rows come back shortest period first, then by length, with base tiers ahead of special tiers of the same length — which reads top-to-bottom the way a pricing card should.
- A product with no tiers configured returns an empty
itemslist rather than an error.rentalProductPriceon such a product returnsprice: 0with an empty breakdown.
Customer groups #
Both queries price for the calling customer’s group by default — send a customer token and trade pricing follows automatically, with no customer_group_id needed.
You can pass customer_group_id explicitly, but a customer may only pass their own; anything else is refused. Quoting an arbitrary group is a back-office capability and needs a token with back-office permission. Without that rule, any visitor could read your trade prices by guessing group ids.
Quote, then book #
These queries price dates; they do not hold them. A quote is a statement about the tiers, not a reservation, and nothing stops another customer taking the last unit a second later. Check availability alongside the price, and treat the booking as real only once addRentalProductsToCart has accepted it — that is the point at which the dates are re-checked and the line is priced for real.
