Quotes
POST /v1/quotes prices a stay or a time slot. It doesn’t hold anything —
it’s a read, just a priced one. A quote is valid for 15 minutes; hold it
before expiresAt or ask for a new one.
For an hourly space, send the exact start and end of a slot from
GET /v1/resources/{id}/slots, and leave out ratePlanId. See
Hourly spaces and services.
Request
Section titled “Request”| Field | Required | Notes |
|---|---|---|
resourceId | yes | |
ratePlanId | if the resource has a room type | Get it from GET /v1/resources/{id} — see Resources, room types, rate plans. Leave it out for an hourly space. |
from, to | yes | ISO 8601 datetimes; from must be strictly before to. At most 366 nights apart. For an hourly space, the exact startsAt and endsAt of a slot. |
partySize | yes | positive integer |
currency | no | Display currency, an uppercase ISO 4217 code such as IDR; defaults to the rate plan’s own currency (no conversion) |
curl -X POST https://api.<domain>/v1/quotes \ -H "Authorization: Bearer sk_test_..." \ -H "Content-Type: application/json" \ -d '{ "resourceId": "<RESOURCE_ID>", "ratePlanId": "<RATE_PLAN_ID>", "from": "2026-08-01T00:00:00Z", "to": "2026-08-04T00:00:00Z", "partySize": 2 }'const { data: quote, error } = await client.POST("/v1/quotes", { body: { resourceId: "<RESOURCE_ID>", ratePlanId: "<RATE_PLAN_ID>", from: "2026-08-01T00:00:00Z", to: "2026-08-04T00:00:00Z", partySize: 2, },});if (error) throw error;Response (trimmed)
Section titled “Response (trimmed)”{ "quoteId": "...", "priceBreakdown": { "unit": "night", "lines": [ { "startsAt": "2026-08-01T00:00:00.000Z", "endsAt": "2026-08-02T00:00:00.000Z", "unit": "night", "durationMinutes": 1440, "unitAmountMinorUnits": "1500000", "baseAmountMinorUnits": "1500000", "seasonalMultiplierBps": 10000, "dayOfWeekMultiplierBps": 10000, "amountMinorUnits": "1500000" } ], "nights": [ { "date": "2026-08-01", "baseAmountMinorUnits": "1500000", "amountMinorUnits": "1500000", "seasonalMultiplierBps": 10000, "dayOfWeekMultiplierBps": 10000 } ], "subtotalMinorUnits": "4500000", "lengthOfStayAdjustment": null, "leadTimeAdjustment": null, "totalMinorUnits": "4500000", "currency": "IDR" }, "fx": null, "displayTotal": { "currency": "IDR", "amountMinorUnits": "4500000" }, "signedQuoteToken": "eyJhbGciOi...", "expiresAt": "2026-07-16T03:15:00.000Z"}Price lines
Section titled “Price lines”priceBreakdown.lines[] is the price, one line per priced unit. Read it in
new code.
unitisnightfor a hotel stay (one line per night),hourfor an hourly space priced per hour, andslotfor an hourly space with a fixed price for that length.priceBreakdown.unitrepeats it.- A multiplier of
10000means no change (100%).12000means 20% more. nights[]is the older shape. It stays for hotel stays and is empty for hourly spaces. It is removed only in a new API version.lengthOfStayAdjustmentandleadTimeAdjustmentarenullwhen no rule applied. They never apply to an hourly space.
Money on the wire
Section titled “Money on the wire”null when no currency conversion happened — you didn’t ask for one, or it
already matched the rate plan’s own currency. When it’s present,
displayTotal is the converted amount the guest actually sees;
priceBreakdown.totalMinorUnits/.currency always stays in the rate
plan’s native currency either way.
signedQuoteToken
Section titled “signedQuoteToken”Hand this to hold creation unchanged (see Quickstart) — whoever confirms the hold trusts this token’s price, never a re-typed number.
Errors
Section titled “Errors”| Status | code | Meaning |
|---|---|---|
| 400 | invalid_window | from isn’t strictly before to |
| 400 | validation_failed | A field is wrong, or the window is longer than 366 nights |
| 400 | rate_plan_required | The resource has a room type; you omitted ratePlanId |
| 400 | invalid_duration | Hourly space: the window length is not one of the space’s durations |
| 404 | resource_not_found / rate_plan_not_found | Check the ID, and check you’re using the right tenant’s key |
| 409 | unavailable | See reasons — same vocabulary as Availability. For an hourly space, the window is not one of the bookable slots. |
| 422 | no_pricing_rule | No price configured for one or more nights (missingDates) — an operator-side gap, not something your integration can fix |
| 422 | fx_rate_unavailable | No FX rate for the currency you asked for |
Both sk_ and pk_ keys can call this endpoint — it’s the widget’s
pricing surface too. Both need the quote:read scope.