Understanding the Upsell Workflow

How to retrieve available upsells for a quote, apply selected upsells, and troubleshoot missing upsell fees.

Overview


Use this workflow to offer optional services, such as an extra bed, baby crib, welcome basket, early check-in, or late checkout, before creating a reservation through the Booking Engine API.

In Guesty, upsells are optional additional fees on a reservation quote. Retrieve the upsells available for the current quote, let the guest choose from that list, then update the quote with the selected upsell fee IDs before creating the reservation.


🚧

Guesty currently documents the upsell operations as Pilot endpoints. Confirm that your account can use them before you build this workflow into production.


Prerequisites


Before you retrieve or apply upsells, make sure you have:

  • A valid Booking Engine API bearer token.
  • An active Booking Engine API setup.
  • At least one Booking Engine API reservation created, so that Guesty can initialize the BE-API source.
  • Active upsells are assigned to the relevant listing.
  • Related fees enabled for the BE-API source.

📘

The Booking Engine website source and the Booking Engine API source are separate sources. For API-created reservations, configure fees for BE-API.


Endpoints


ActionMethodEndpoint
Create a reservation quotePOST/api/reservations/quotes
Retrieve available upsellsGET/api/reservations/upsell/{inquiryId}/{listingId}/fee
Update upsells in a quotePOST/api/reservations/upsell/{quoteId}
Retrieve a quoteGET/api/reservations/quotes/{quoteId}

Workflow


1. Create a quote


Create a quote for the listing, dates, and guest count:


curl --request POST 'https://booking.guesty.com/api/reservations/quotes' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header 'Authorization: Bearer {{token}}' \
--data {
  "checkInDateLocalized": "2026-07-12",
  "checkOutDateLocalized": "2026-07-15",
  "listingId": "65b8cfa6b8f1a90012d93f41",
  "guestsCount": 2
}

The quote response includes the quote _id, rate plans, pricing, and a per-rate-plan inquiryId.


🚧

The inquiryId is not the quote ID. It identifies the financial quote for a specific rate plan. If the quote returns multiple rate plans, use the inquiryId for the rate plan the guest selects.


2. Retrieve available upsells


Use the selected rate plan's inquiryId and the quote's listingId:


curl --request GET 'https://booking.guesty.com/api/reservations/upsell/{inquiryId}/{listingId}/fee' \
--header 'accept: application/json' \
--header 'Authorization: Bearer {{token}}' 

Guesty returns the upsells available for that quote context. Use this response as the source of truth; do not show cached upsells unless you validate them against the current quote.


{
  "_id": "61f984538b908351a18d2c75",
  "name": "Baby crib",
  "isUpsell": true,
  "upsell": {
    "description": "Add a baby crib to the property before check-in."
  },
  "multiplier": "PER_STAY",
  "price": 35
}

3. Update the quote


After the guest selects one or more upsells, update the quote by attaching the selected additional fee and rate plan ID(s):


curl --request POST 'https://booking.guesty.com/api/reservations/upsell/{quoteId}'\
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header 'Authorization: Bearer {{token}}' \
--data {
"additionalFeeIds": [
    "61f984538b908351a18d2c75"
  ],
  "ratePlanIds": [
    "65b8d0b2b8f1a90012d93f59"
  ]
}

A successful request returns:


{
  "success": true
}

4. Retrieve the quote again


Retrieve the quote before creating the reservation:


curl --retrieve GET 'https://booking.guesty.com/api/reservations/quotes/{quoteId}' \
--header 'accept: application/json' \
--header 'Authorization: Bearer {{token}}' 

Use the refreshed quote to confirm the updated pricing. The quote response can include financial fields such as invoiceItems, totalFees, subTotalPrice, and totalTaxes.


Troubleshooting missing upsells


If an expected upsell does not appear in the Retrieve Upsell response, check the configuration and request context in this order:


CheckWhat to confirm
Upsell setupHave you configured the offer as an upsell and activated it, priced it, and assigned it to the relevant Guest Apps?
Fee poolDoes the underlying fee exist at the account level or the listing level?
Listing assignmentDoes the upsell apply to the listing directly, to all properties, or through a city or tag rule?
SourceHave you enabled the fee for BE-API, not only for the Booking Engine website source or another manual source?
Source initializationHave activated your BEAPI instance by creating at least one test Booking Engine API reservation, so BE-API appears in the fee settings?
Fresh quoteDid you refresh the quote after adding the upsell?
inquiryIdDid you request the upsell list using the selected rate plan's inquiryId, not the quote ID?
Listing IDDoes your listingId match the listing used to create the quote?
Token contextAre you using a valid access token to access the Booking Engine API instance and listing?

The correct Retrieve Upsell request uses inquiryId:


curl --request GET 'https://booking.guesty.com/api/reservations/upsell/{inquiryId}/{listingId}/fee' \
--header 'accept: application/json' \
--header 'Authorization: Bearer {{token}}' 

Do not call it with the quote ID:


curl --request GET 'https://booking.guesty.com/api/reservations/upsell/{quoteId}/{listingId}/fee' \
--header 'accept: application/json' \
--header 'Authorization: Bearer {{token}}' 

The upsell endpoints can return 400, 401, 403, or 429 depending on the operation and failure case.


👍

Tips

  • Store selected upsell fee IDs only after Guesty returns them for the current quote.
  • Availability can depend on the listing, rate plan, dates, guest count, source configuration, and upsell assignment.
  • After you update the fee or upsell settings in Guesty, create a new quote before testing the Retrieve Upsell endpoint again.

If your issue persists after completing all the troubleshooting steps, please contact Guesty API Support and provide a description of your workflow, the failed cURL request, and any other pertinent information so they can assist you.


Explore further