Introduction

This documentation covers the different ways you can integrate with the Quantum Suites Booking Engine. If you need assistance, we provide a full integration service. Contact us at: hello@quantumsuites.me

Before you start, you will need:

  • A Quantum Suites Account
  • Your public API key. This key is NOT secret and will be visible to your end users in URLs, so do not worry about keeping it private.
  • You can get your API key on your Settings Page once you log in.

After you've got that, you're ready to integrate. There are three ways to integrate:

  1. Basic Integration

    Pros:

    • No programming needed
    • Can be used with any website because you simply link to our reservation process.
    • Even works with no website; you can just email or text links to your customers to enable them to book if you wish.
    • You can be up and going right now.

    Cons:

    • No customization of the process
    • No branding - generic appearance
    • Minimal search features and no cross-promotion with your other units.
  2. Custom Integration

    Pros:

    • You control the whole process and presentation.
    • Embed it in your website, make it look branded and "part of" your user experience.
    • Enable advanced search features on your site and easily cross-promote your units; if one unit is booked, you can easily set up your site to direct customers to similar available units.
    • Incredibly flexible

    Cons:

    • A light amount of programming may be required. We provide some copy/paste-able examples, but it may be difficult for someone to set up without assistance.
    • Might not work with all hosting providers. Some basic hosting providers do not allow you to add custom code to your websites.
  3. Use Our Integration Plugins

    Pros:

    • Easy integration with common platforms
    • Almost as full featured as a custom integration, with minimal or no programming required.
    • The best of both options

    Cons:

    • Requires installation of a plugin or custom module on your site. Most providers will allow this, but some may not.
    • Only works if you're using one of the supported platforms. See the Integration Plugins section below for a list of supported platforms.

Basic Integration

The basic integration can be used by anyone. Once you have created your account and set up a unit, you can find the URL for the booking page for your units on this screen: Units List

You can use these links wherever and however you like. On your website, in emails, over text messages, it's all good.

You can also set up bookings for your customers by going to one of the links yourself, entering the customer's requested dates and number of guests, and submitting the form. The checkout screen's URL can be copy and pasted, then sent to your customer, to direct the customer straight to the end of the process.

If you wish to test this process without charging your credit card, you can use Stripe's Test Mode API Keys in your user settings to test the process.

Stripe has a list of test payment methods you can use while in test mode. Just remember to put your live API keys back when you are done trying it out!

Custom Integration

Custom integrations enable you to use our API to build your own integration. You have full control over how things are displayed and the overall user experience. However, this control also means it is a more difficult path.

We currently provide two API libraries; one for Javascript and one for PHP. Some Javascript is required to get this to work; Stripe's credit card intake process, used by our system, is powered by Javascript.

So, unfortunately, the PHP library cannot be used exclusively to power all features available. However, it can be used to power search and pricing which may can give your users a faster and better user experience.

Or, if you prefer, all features can be powered by the Javascript library with no PHP required whatsoever. It all depends on what makes the most sense in your particular situation.

Lifecycle of the Transaction

This section describes the lifecycle of the customer's transaction with your website. In other words, the flow that the user is expected to go through.

  1. First, the user will arrive at your site. You may either present them your units directly and allow them to click on them for more details and booking, and/or you may want to allow them to search for availability based on their desired checkin / checkout dates.

  2. If you want to allow people to search, then you will probably want to use the getAvailability call in either the PHP or the Javascript libraries. This search can then be used to direct the customer to a page with details about your unit.

  3. From the detail page, you will want to use the getPricing call in either the PHP or the Javascript libraries to get the final price of the unit. This can be used to display a checkout page.

  4. The checkout page will need the user to "login". The login is actually an email sent by Quantum Suites with a verification code in it. They will enter this verification code on your site to get a code to complete checkout.

  5. Your checkout page will receive the code sent via "login", and validate the code. Validating the code will return a Stripe customer ID which can be used to book the unit.

  6. Then you present the user the option to book the unit. If they chose to continue, you can present them with a Stripe form. Their reservation will be held for 10 minutes.

  7. After the have successfully booked the unit, we will automatically redirect them to your contract with the house rules in order for them to agree to it and complete their booking.

Importance of Unit URLs

When setting up a unit on Quantum Suites, you will there is a field for configuring the "URL for Unit Details" under the "Integrations" panel. This URL should be the URL on your site which will display details about the unit -- photos and such.

Quantum Suites uses this URL as 'connective tissue' between itself and your site. When you query units, such as with getAvailabilities, you will receive that URL as part of the results so that you can direct your customers to the detail page.

Additionally, you can use unitFromUrl to look up a Quantum Suites Unit ID based on your URL. It is recommended that you cache the Unit ID as it won't change unless you delete and re-create the unit in QSB.

Javascript API

Our Javascript API requires jQuery; almost any version of jQuery will work, as it is used in the most basic ways possible. In the future, we will try to remove this requirement if there is a demand to do so. Many sites, such as WordPress, already use jQuery and so our plugin should work with whatever jQuery is already there.

Right now, we do not have NPM support; again, this is something we can change if there is demand for it.

Here's some sample include code to set up our plugin:


<!-- Include jQuery if you aren't already using it -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>

<!-- Stripe is only needed on the checkout page -->
<script src="https://js.stripe.com/v3/"></script>

<!-- And the Quantum Suites API itself -->
<script src="https://qsb.quantumsuites.mejs/qsb.js"></script>
                

Our library provides the QSB class. It can be initalized with your API key (see the introduction section) like this:


<script>
    var qsb = new QSB('Your QuatumSuites Public API Key');
</script>
                

Once initialized, there are a number of methods you can use to query or book units.

Common Conventions

Most functions in the Javascript API work based on Ajax callbacks. As such, most of them take a success_callback and an error_callback parameter. These callbacks are always optional, but usually success_callback must be set to something in order for an action to happen after data is fetched.

success_callback will be called on a successful call, and it will be passed a single parameter returning the results of the operation (i.e. the return value of the Ajax call).

error_callback will be called on any kind of failure. This callback is passed straight to the jQuery.ajax call's 'error' parameter, and thus you can read the full documentation of what is passed into it on jQuery's API documentation site here.

There are only two likely reasons for error; if https://QuantumSuites.me isn't reachable at the time of the call, or if there is a misconfiguration such as an invalid Quantum Suites API key being used.

"Stripe Format" is referred to in this documentation for prices. Stripe only uses integers in prices; so $19.58 would be represented as 1958 in "Stripe Format". Anything mentioned as being in "Stripe Format" will need to be divided by 100 in order to get a decimal number for display to the end user.

Available Methods

qsb.getLocations (
  • callback: success_callback,
  • callback: error_callback
)

This method fetches available unit cities and states/provinces from the API. Once it is fetched, the location data is cached in qsb.locations; subsequent calls will use this cache instead of re-fetching from the QSB API server.

success_callback will be passed the following object structure:


{
    "NC": [
        "Cary",
        "Raleigh",
        ...
    ],
    "VA": [
        "Lynchburg",
        "Richmond",
        ...
    ],
    ...
}
                    

Where the object has a property for each state or province code the host has units in, and each property is a list array of cities in that state where units are located.

This data is provided alphabetically sorted.

qsb.bindStateCitySelect(
  • string/element/jQuery: state_select,
  • string/element/jQuery: city_select,
  • callback: success_callback,
  • callback: onchange_callback,
  • callback: error_callback
)

Frequently, one will want to make a progressive pair of select boxes where your potential guest will first choose a state and then choose the city. This call sets up a pair of select boxes and does the Ajax getLocations query so that you do not have to.

To use this, you need to place two select boxes in your HTML somewhere. The select boxes do not need to have anything in them; whatever is in them will be replaced when the location data is loaded from the Quantum Suites Booking Engine.

state_select and city_select should both be either a string with a jQuery compatible selector, a DOM element object, or a jQuery object that already has the select element loaded. These should be empty <select> elements.

success_callback is called after the location data has been loaded and both select boxes have been configured. Nothing is passed to it. This is usually used to reveal elements that are hidden during loading. If you wish to access the loaded location data, you can access it via the property qsb.locations.

onchange_callback is called after the 'state' select box has been changed. bindStateCitySelect will bind a change handler to the state_select box, and this callback allows you to chain something after state has been selected and city has been updated.

error_callback is passed to getLocations directly and functions as noted in the Common Conventions section above.

qsb.getAvailability (
  • string: from,
  • string: to,
  • string/integer: num_guests,
  • string: state,
  • string: city,
  • callback: success_callback,
  • callback: error_callback
)

This call is basically the unit search. It gets unit availabilities for start/end dates "from" and "to", for the indicated number of guests. State and city may optionally be provided to narrow down the results further.

from and to should be strings containing dates formated either "month/day/year" or "year-month-day"; either format is understood. Four digit years should be used, however 0 padding the month and day are not required. "2023-4-9" and "9/4/2023" are acceptable date formats as an example.

num_guests should either be an integer or a string containing an integer. This is the number of guests in the party. QSB does not distinguish between children/infants and adult guests at this time.

state can either be a two-character state code as obtained from getLocations, or it can be an empty string to not filter by state.

city can be either a city string as obtained from getLocations, or it can be an empty string to not filter by city.

success_callback is optional, and if provided, will be run with the following data structure as its only parameter:


[
    {
        "id": "uuid based ID for unit",
        "title": "unit title",
        "description": "a brief description",
        "url": "a URL for more information",
        "max_guests": maximum number of guests,
        "num_bedrooms": integer number of bedrooms,
        "num_bathrooms": decimal number of bedrooms,
        "price": integer price in 'stripe' format
        "nights": number of nights,
        "price_per_night": price per night in 'stripe' format,
        "latitude": latitude geo location
        "longitude": longitude geo location,
        "type": This will be a text such as "House", "Apartment", etc.,
        "square_feet": size of unit in square feet
        "neighborhood": some brief text description about the location
        "bed_info": [
            {
                "King": integer,
                "Queen": integer,
                ...  (keys will be missing if 0)
            },
            ...
        ]
    },
    ...
]
                    

Some notes about this return structure:

  • Most of these fields are set in the QSB unit editor. Title, description, url, max_guests, num_bedrooms, num_bathrooms, type, square_feet, neighborhood, and bed_info are directly powered by what is put in the unit editor.
  • price is a price estimate and should not be presented as a final price; it doesn't include fees and taxes. This is the estimated total for the stay.
  • nights is a count of the number of nights between the 'from' and 'to' dates, and is the total nights of the stay.
  • price_per_night is a simple division of price by nights to get a nightly rate. It is just an estimate value as well, not factoring in taxes or fees.
  • latitude and longitude are derived from the address you provide in the QSB unit editor. The resolution is intentionally low; if you use this to render a pin on a map, that pin will be somewhere within a couple miles of the house and not an exact location.

If invalid paramters are provided to the search, for example a date that does not exist or isn't properly formatted, you will get an error structure back instead:


{
    "error": true,
    "message": "a helpful message"
}
                    

If your user interface does not allow users to input invalid parameters -- for example, you use date pickers and don't allow arbitrary entry of random data -- you should never receive an error. However, if you do, please note that QSB will give a "200 OK" HTTP status but return the above error object.

As a final note, qsb.availability is set with the return value of getAvailability regardless of if success_callback is provided or not. This is not cached, so subsequenty calls to getAvailability will re-send the Ajax request.

error_callback is passed to jQuery.ajax directly and functions as noted in the Common Conventions section above.

qsb.getAvailability (
  • string: from,
  • string: to,
  • string/integer: num_guests,
  • string: query,
  • string: center,
  • callback: success_callback,
  • callback: error_callback
)

This call is a twist on getAvailability. Similar to the first call, it gets unit availabilities for start/end dates "from" and "to", for the indicated number of guests. The difference is that we will use the HERE geocoding API to resolve 'query' and return results sorted by distance to the located point.

from and to should be strings containing dates formated either "month/day/year" or "year-month-day"; either format is understood. Four digit years should be used, however 0 padding the month and day are not required. "2023-4-9" and "9/4/2023" are acceptable date formats as an example.

num_guests should either be an integer or a string containing an integer. This is the number of guests in the party. QSB does not distinguish between children/infants and adult guests at this time.

query is a string; it can be anything, be it a point of interest or a specific address. It is very flexible and most queries will return some kind of search.

center is a latitude and longitude point in the string format "lat,lng" such as "35.9050059,-78.7749791". This 'centers' the search near that point, so that you are less likely to get results outside of the state or even country that your units are in.

success_callback is optional, and if provided, will be run with the following data structure as its only parameter:


{
    found: {
        // results from HERE API, documented here:
        https://www.here.com/docs/bundle/geocoding-and-search-api-developer-guide/page/topics-api/code-geocode-spatial-reference.html
    },
    results: [
        {
            "id": "uuid based ID for unit",
            "title": "unit title",
            "distance": distance in meters to location
            "description": "a brief description",
            "url": "a URL for more information",
            "max_guests": maximum number of guests,
            "num_bedrooms": integer number of bedrooms,
            "num_bathrooms": decimal number of bedrooms,
            "price": integer price in 'stripe' format
            "nights": number of nights,
            "price_per_night": price per night in 'stripe' format,
            "latitude": latitude geo location
            "longitude": longitude geo location,
            "type": This will be a text such as "House", "Apartment", etc.,
            "square_feet": size of unit in square feet
            "neighborhood": some brief text description about the location
            "bed_info": [
                {
                    "King": integer,
                    "Queen": integer,
                    ...  (keys will be missing if 0)
                },
                ...
            ]
        },
        ...
    ]
}
                    

Some notes about this return structure:

  • Most of these fields are set in the QSB unit editor. Title, description, url, max_guests, num_bedrooms, num_bathrooms, type, square_feet, neighborhood, and bed_info are directly powered by what is put in the unit editor.
  • price is a price estimate and should not be presented as a final price; it doesn't include fees and taxes. This is the estimated total for the stay.
  • nights is a count of the number of nights between the 'from' and 'to' dates, and is the total nights of the stay.
  • price_per_night is a simple division of price by nights to get a nightly rate. It is just an estimate value as well, not factoring in taxes or fees.
  • latitude and longitude are derived from the address you provide in the QSB unit editor. The resolution is intentionally low; if you use this to render a pin on a map, that pin will be somewhere within a couple miles of the house and not an exact location.

If invalid paramters are provided to the search, for example a date that does not exist or isn't properly formatted, you will get an error structure back instead:


{
    "error": true,
    "message": "a helpful message"
}
                    

If your user interface does not allow users to input invalid parameters -- for example, you use date pickers and don't allow arbitrary entry of random data -- you should never receive an error. However, if you do, please note that QSB will give a "200 OK" HTTP status but return the above error object.

As a final note, qsb.availability is set with the return value of getAvailability regardless of if success_callback is provided or not. This is not cached, so subsequenty calls to getAvailability will re-send the Ajax request.

error_callback is passed to jQuery.ajax directly and functions as noted in the Common Conventions section above.

qsb.loginUser(
  • string: email,
  • callback: success_callback,
  • callback: error_callback
)

In order for a user to book a unit, they have to be "logged in". This call will cause QSB to send an email to the email address provided. That email will contain a code which you will in turn pass to validateUser to validate them and confirm the login.

email is the address where we will send their code. This is rate-limited so it cannot be used for SPAM.

success_callback will receive a single parameter of the form:


{
    "message": "some message",
    "success": true if success, false if failed, message has error
}
                    

'message' is safe to display to the user, and showing them the message is recommended as the error may be informative. This call will always return 200 unless you provided an incorrect QuantumSuites API key.

error_callback is passed to jQuery.ajax directly and functions as noted in the Common Conventions section above.

qsb.validateUser (
  • string: email,
  • string/integer: code,
  • callback: success_callback,
  • callback: error_callback
)

loginUser will send the user an email with a 6 digit code in it. This call takes the user's email address and that 6 digit code, and validates them.

email is the email that the code was sent to; it should be the same as what was passed to loginUser

code is either an integer or a string containing an integer with the six digit code.

success_callback will be passed a single parameter with the following object:


{
    "message": "some message",
    "success": true if success, false if failed, message has error
    "stripe_customer": stripe customer ID string (if success)
}
                    

'message' is usually irrelevant if this call is successful, but it will have an error message if something went wrong (such as an invalid code).

'stripe_customer' is their Stripe customer_id and is safe to reveal, unencrypted, to the user. You may store this in a cookie or some session variable if you wish, but that is not required.

'stripe_customer' is needed to book the unit, using bookUnit

'message' is safe to display to the user, and showing them the message is recommended as the error may be informative. This call will always return 200 unless you provided an incorrect QuantumSuites API key.

error_callback is passed to jQuery.ajax directly and functions as noted in the Common Conventions section above.

qsb.bookUnit(
  • string: unit_id,
  • string: from,
  • string: to,
  • string/integer: num_guests,
  • string/integer: dogs,
  • string/integer: cats,
  • string: customer_id,
  • string: city,
  • string: state,
  • callback: success_callback,
  • callback: error_callback
)

This call actually creates a reservation in the system. However, the reservation isn't confirmed until payment is completed.

When you call this, you will receive a Stripe "client_secret" that can be used to present a Stripe payment form. We provide examples of this in the examples section.

unit_id is a UUID-format string as received from getAvailabilities or unitFromUrl.

from and to are strings containing dates in the format described by getAvailabilities.

num_guests is either an integer or string containing integer number of guests staying at the property.

dogs is either an integer or string containing integer number of dogs staying at the property. This may be blank or 0.

cats is either an integer or string containing integer number of cats or other non-dog animals requiring a special deposit staying at the property. This may be blank or 0.

customer_id is the value obtained from validateUser.

city and state should be the unit's city and state as obtained from getAvailabilities. In a pinch, these can be blank strings; the purpose of passing these is to automatically query for alternative units if the unit was booked out from under the customer during the checkout process.

success_callback will be passed a single parameter. It can return one of three things. If we were able to place the reservation successfully, it will receive:


{
    'available' => true,
    'client_secret' => Stripe client secret for payment intent
    'expires' => expiration UNIX timestamp, in seconds
    'contract_url' => URL to send the customer to sign contract
                      AFTER payment is done.  Use this as the
                      stripe return URL.
}
                    

If the unit was booked while the customer was going through the checkout process, you will instead receive:


{
    "available": false,
    "alternatives": [
        // same structure as 'getAvailability'
    ]
}
                    

In case of an error, which would be if, for instance, the dates are invalid, you will receive this instead. If your form is properly validating user input, this should never happen.


{
    "error": true,
    "message": "a helpful message"
}
                    

This call will always return a 200 status code unless provided an invalid API key.

error_callback is passed to jQuery.ajax directly and functions as noted in the Common Conventions section above.

qsb.getNextAvailability (
  • string/integer: nights,
  • string/integer: num_guests,
  • string: state,
  • string: city,
  • callback: success_callback,
  • callback: error_callback
)

This call is used to fetch available units based on a number of days rather than specific dates. Specifically, it returns the next availabilities of all your units for a stay of 'nights' number of nights.

nights is the number of nights of availability required as an integer or string containing integer.

num_guests is the number of guests staying as an integer or string containing integer.

state contains a 2 letter state or province code as returned from getLocations. It is optional, if left off, all states will be queried.

city contains a city from getLocations. It is optional, if left off, all cities will be queried.

success_callback will be called on completion and, for this call, is required as you won't get any data from this if ignored. The structure passed to the callback will be:


[
    {
        "id": "uuid based ID for unit",
        "title": "unit title",
        "url": "a URL for more information",
        "neighborhood": some brief text description about the location,
        "nights_available": Number of nights available
        "starting": date the nights_available starts,
        "city": city,
        "province": province
        "num_bedrooms": number of bedrooms,
        "num_bathrooms": number of bathrooms
    },
    ...
]

If invalid paramters are passed, you can receive an error object. You should validate the user's input rather than allow this to happen.


{
    "error": true,
    "message": a helpful message but maybe not the best for the user
}

This call will always return a 200 status code unless provided an invalid API key.

error_callback is passed to jQuery.ajax directly and functions as noted in the Common Conventions section above.

qsb.getPricing(
  • string: unit_id,
  • string: from,
  • string: to,
  • string/integer: num_guests,
  • string/integer: num_dogs,
  • string/integer: num_cats,
  • string: city,
  • string: state,
  • string: customer_id,
  • callback: success_callback,
  • callback: error_callback
)

This call produces a full final price for a unit, completely broken down with taxes and fees. It is designed to be called when displaying the checkout screen.

unit_id is a UUID-format string as received from getAvailabilities or unitFromUrl.

from and to are strings containing dates in the format described by getAvailabilities.

num_guests is either an integer or string containing integer number of guests staying at the property.

dogs is either an integer or string containing integer number of dogs staying at the property. This may be blank or 0.

cats is either an integer or string containing integer number of cats or other non-dog animals requiring a special deposit staying at the property. This may be blank or 0.

city and state should be the unit's city and state as obtained from getAvailabilities. In a pinch, these can be blank strings; the purpose of passing these is to automatically query for alternative units if the unit was booked out from under the customer during the checkout process.

customer_id is the value obtained from validateUser. It is optional and may be an empty string or false if you don't have it. The reasoning for passing it here is so that, if a customer has a booking in progress, that booking won't count against availability if the getPricing is called during the checkout process.

success_callback will be passed a single parameter. It can return one of three things. If the unit is still available, you will receive:


{
    "available": true,
    "num_nights": integer number of nights in the stay,
    "pay_schedule": [
        {
            "charge_on": "YYYY-MM-DD",
            "amount": integer in stripe format
            "amount_tax": integer in stripe format
        },
        ...
    ],
    "totals": {
        "num_nights": integer number of nights of the stay
        "cat_deposit": integer amount in 'stripe' format
        "pet_fee": integer amount in 'stripe' format
        "authorize": integer amount in 'stripe' format
        "charge": integer amount in 'stripe' format
        "charge_tax": integer amount in 'stripe' format
        "monthly": integer amount in 'stripe' format
        "monthly_tax": integer amount in 'stripe' format
        "last_month": integer amount in 'stripe' format
        "last_month_tax": integer amount in 'stripe' format
        "total_cost": integer amount in 'stripe' format
        "total_tax": integer amount in 'stripe' format
        "utility_fee": integer amount in 'stripe' format
    },
    "title": "unit title",
    "description": "a brief description",
    "url": "a URL for more information",
    "price_per_night": price per night in 'stripe' format,
    "neighborhood": some brief text description about the location
}

Note about "pay_schedule"; this is a list of payments that will be made in the future, if the user has booked a reservation longer than 28 days and will thus be paying some kind of periodic rent instead of paying for the entire reservation up front.

Therefore, for reservations 28 days or shorter, this will be an empty list.

If the unit is not available because someone booked it before this call was made, you will receive:


{
    "available": false,
    "next_available": {  Next time the unit requested is available
        "available_start": "YYYY-MM-DD" date unit is available
        "available_checkout": "YYYY-MM-DD" proposed checkout date
        "available_nights": integer night count, or null if calendar is open.
        "title": "unit title",
        "description": "a brief description",
        "url": "a URL for more information",
        "neighborhood": some brief text description about the location,
        "max_guests": maximum number of guests,
        "num_bedrooms": integer number of bedrooms,
        "num_bathrooms": decimal number of bedrooms,
        "latitude": latitude geo location
        "longitude": longitude geo location,
        "type": This will be a text such as "House", "Apartment", etc.,
        "square_feet": size of unit in square feet
        "price": integer price in 'stripe' format
        "nights": number of nights,
        "price_per_night": price per night in 'stripe' format,
        "bed_info": [
            {
                "King": integer,
                "Queen": integer,
                ...  (keys will be missing if 0)
            },
            ...
        ]
    },
    "alternatives": [
        // same structure as 'getAvailability'
    ]
}

next_available is details about the next time the unit will be available, and 'alternatives' returns a list similar to getAvailability of other units that are available for the same dates and number of guests.

The following structure will be returned if invalid inputs are provided (i.e. incorrect dates). Ideally, you should validate user input to prevent this:


{
    "error": true,
    "message": a helpful message but maybe not the best for the user
}

This call will always return a 200 status code unless provided an invalid API key.

error_callback is passed to jQuery.ajax directly and functions as noted in the Common Conventions section above.

qsb.unitFromUrl (
  • string: url,
  • callback: success_callback,
  • callback: error_callback
)

Unit URLs are used to glue your site and Quantum Suites together seamlessly. For more details about our recommendations here, see the section above.

The url parameter should be the end portion of a URL. For instance, if your unit detail page has the url:

http://yoursite.com/units/detail/1234.html

You could pass '1234.html' to the url parameter and receive the QSB unit ID assuming the unit URL is configured correctly in the QSB back-end.

success_callback will receive the following structure:


[
    {
         "id": the unit ID
         "url": the URL we have on record
         "title": the title we have for the unit
    },
    ...
]

Note that it is technically possible to match multiple URLs in the case that what you pass isn't sufficiently distinct. Thus, this returns a list with all matches. Of course, you may also match nothing and receive an empty list. This call will never generate an error.

error_callback is passed to jQuery.ajax directly and functions as noted in the Common Conventions section above.

qsb.blockedDates(
  • string: unit_id,
  • callback: success_callback,
  • callback: error_callback
)

Sometimes it is desirable to know which dates are already booked; for instance, when presenting a calendar widget for a unit, you may wish to have dates that are not available to be already blocked.

This call will return a list with start/end date pairs for a provided unit_id. success_callback will receive:


[
  [start_date, end_date],
  [start_date, end_date],
  ...
]

This may be an empty list if the unit has no blocks on the calendar. It will never return an error assuming unit_id is valid (if it is not valid, you will receive a 404 error).

error_callback is passed to jQuery.ajax directly and functions as noted in the Common Conventions section above.

PHP API

Our PHP API uses the PHP cURL extension. This extension is enabled by default on most web hosts. At the moment, we do not have our library set up to work with Composer or any other package system, but we will seek to improve that in the future.

You can grab our PHP library here.

Our library provides the QSB object, which can be initialized thusly with your API key (see the introduction section):


require_once ('qsb.php');

$qsb = new QSB('Your API Key');

Once initialized, you can use a variety of methods as described below.

Available Methods

$qsb->getLocations ()

This method fetches available unit cities and states/provinces from the API. We recommend caching the return value of this as it will rarely change. The return value will be a PHP dictionary array such as:


{
    "NC": [
        "Cary",
        "Raleigh",
        ...
    ],
    "VA": [
        "Lynchburg",
        "Richmond",
        ...
    ],
    ...
}
                    

Where the object has a property for each state or province code the host has units in, and each property is a list array of cities in that state where units are located.

This data is provided alphabetically sorted.

$qsb->getAvailability (
  • string: from,
  • string: to,
  • string/integer: num_guests,
  • string: state,
  • string: city
)

This call is basically the unit search. It gets unit availabilities for start/end dates "from" and "to", for the indicated number of guests. State and city may optionally be provided to narrow down the results further.

from and to should be strings containing dates formated either "month/day/year" or "year-month-day"; either format is understood. Four digit years should be used, however 0 padding the month and day are not required. "2023-4-9" and "9/4/2023" are acceptable date formats as an example.

num_guests should either be an integer or a string containing an integer. This is the number of guests in the party. QSB does not distinguish between children/infants and adult guests at this time.

state can either be a two-character state code as obtained from getLocations, or it can be an empty string to not filter by state.

city can be either a city string as obtained from getLocations, or it can be an empty string to not filter by city.

A PHP associative array is returned:


[
    {
        "id": "uuid based ID for unit",
        "title": "unit title",
        "description": "a brief description",
        "url": "a URL for more information",
        "max_guests": maximum number of guests,
        "num_bedrooms": integer number of bedrooms,
        "num_bathrooms": decimal number of bedrooms,
        "price": integer price in 'stripe' format
        "nights": number of nights,
        "price_per_night": price per night in 'stripe' format,
        "latitude": latitude geo location
        "longitude": longitude geo location,
        "type": This will be a text such as "House", "Apartment", etc.,
        "square_feet": size of unit in square feet
        "neighborhood": some brief text description about the location
        "bed_info": [
            {
                "King": integer,
                "Queen": integer,
                ...  (keys will be missing if 0)
            },
            ...
        ]
    },
    ...
]
                    

Some notes about this return structure:

  • Most of these fields are set in the QSB unit editor. Title, description, url, max_guests, num_bedrooms, num_bathrooms, type, square_feet, neighborhood, and bed_info are directly powered by what is put in the unit editor.
  • price is a price estimate and should not be presented as a final price; it doesn't include fees and taxes. This is the estimated total for the stay.
  • nights is a count of the number of nights between the 'from' and 'to' dates, and is the total nights of the stay.
  • price_per_night is a simple division of price by nights to get a nightly rate. It is just an estimate value as well, not factoring in taxes or fees.
  • latitude and longitude are derived from the address you provide in the QSB unit editor. The resolution is intentionally low; if you use this to render a pin on a map, that pin will be somewhere within a couple miles of the house and not an exact location.

If invalid paramters are provided to the search, for example a date that does not exist or isn't properly formatted, you will get an error structure back instead:


{
    "error": true,
    "message": "a helpful message"
}
                    

If your user interface does not allow users to input invalid parameters -- for example, you use date pickers and don't allow arbitrary entry of random data -- you should never receive an error. However, if you do, please note that QSB will give a "200 OK" HTTP status but return the above error object.

qsb.getAvailability (
  • string: from,
  • string: to,
  • string/integer: num_guests,
  • string: query,
  • string: center
)

This call is a twist on getAvailability. Similar to the first call, it gets unit availabilities for start/end dates "from" and "to", for the indicated number of guests. The difference is that we will use the HERE geocoding API to resolve 'query' and return results sorted by distance to the located point.

from and to should be strings containing dates formated either "month/day/year" or "year-month-day"; either format is understood. Four digit years should be used, however 0 padding the month and day are not required. "2023-4-9" and "9/4/2023" are acceptable date formats as an example.

num_guests should either be an integer or a string containing an integer. This is the number of guests in the party. QSB does not distinguish between children/infants and adult guests at this time.

query is a string; it can be anything, be it a point of interest or a specific address. It is very flexible and most queries will return some kind of search.

center is a latitude and longitude point in the string format "lat,lng" such as "35.9050059,-78.7749791". This 'centers' the search near that point, so that you are less likely to get results outside of the state or even country that your units are in.

A PHP associative array is returned:


{
    found: {
        // results from HERE API, documented here:
        https://www.here.com/docs/bundle/geocoding-and-search-api-developer-guide/page/topics-api/code-geocode-spatial-reference.html
    },
    results: [
        {
            "id": "uuid based ID for unit",
            "title": "unit title",
            "distance": distance in meters to location
            "description": "a brief description",
            "url": "a URL for more information",
            "max_guests": maximum number of guests,
            "num_bedrooms": integer number of bedrooms,
            "num_bathrooms": decimal number of bedrooms,
            "price": integer price in 'stripe' format
            "nights": number of nights,
            "price_per_night": price per night in 'stripe' format,
            "latitude": latitude geo location
            "longitude": longitude geo location,
            "type": This will be a text such as "House", "Apartment", etc.,
            "square_feet": size of unit in square feet
            "neighborhood": some brief text description about the location
            "bed_info": [
                {
                    "King": integer,
                    "Queen": integer,
                    ...  (keys will be missing if 0)
                },
                ...
            ]
        },
        ...
    ]
}
                    

Some notes about this return structure:

  • Most of these fields are set in the QSB unit editor. Title, description, url, max_guests, num_bedrooms, num_bathrooms, type, square_feet, neighborhood, and bed_info are directly powered by what is put in the unit editor.
  • price is a price estimate and should not be presented as a final price; it doesn't include fees and taxes. This is the estimated total for the stay.
  • nights is a count of the number of nights between the 'from' and 'to' dates, and is the total nights of the stay.
  • price_per_night is a simple division of price by nights to get a nightly rate. It is just an estimate value as well, not factoring in taxes or fees.
  • latitude and longitude are derived from the address you provide in the QSB unit editor. The resolution is intentionally low; if you use this to render a pin on a map, that pin will be somewhere within a couple miles of the house and not an exact location.

If invalid paramters are provided to the search, for example a date that does not exist or isn't properly formatted, you will get an error structure back instead:


{
    "error": true,
    "message": "a helpful message"
}
                    

If your user interface does not allow users to input invalid parameters -- for example, you use date pickers and don't allow arbitrary entry of random data -- you should never receive an error. However, if you do, please note that QSB will give a "200 OK" HTTP status but return the above error object.

$qsb->loginUser(
  • string: email
)

In order for a user to book a unit, they have to be "logged in". This call will cause QSB to send an email to the email address provided. That email will contain a code which you will in turn pass to validateUser to validate them and confirm the login.

email is the address where we will send their code. This is rate-limited so it cannot be used for SPAM.

You will receive the following associative array as a return:


{
    "message": "some message",
    "success": true if success, false if failed, message has error
}
                    

'message' is safe to display to the user, and showing them the message is recommended as the error may be informative. This call will always return 200 unless you provided an incorrect QuantumSuites API key.

$qsb->validateUser (
  • string: email,
  • string/integer: code
)

loginUser will send the user an email with a 6 digit code in it. This call takes the user's email address and that 6 digit code, and validates them.

email is the email that the code was sent to; it should be the same as what was passed to loginUser

code is either an integer or a string containing an integer with the six digit code.

You will receive the following associative array as a return:


{
    "message": "some message",
    "success": true if success, false if failed, message has error
    "stripe_customer": stripe customer ID string (if success)
}
                    

'message' is usually irrelevant if this call is successful, but it will have an error message if something went wrong (such as an invalid code).

'stripe_customer' is their Stripe customer_id and is safe to reveal, unencrypted, to the user. You may store this in a cookie or some session variable if you wish, but that is not required.

'stripe_customer' is needed to book the unit, using bookUnit

'message' is safe to display to the user, and showing them the message is recommended as the error may be informative. This call will always return 200 unless you provided an incorrect QuantumSuites API key.

$qsb->bookUnit(
  • string: unit_id,
  • string: from,
  • string: to,
  • string/integer: num_guests,
  • string/integer: dogs,
  • string/integer: cats,
  • string: customer_id,
  • string: city,
  • string: state
)

This call actually creates a reservation in the system. However, the reservation isn't confirmed until payment is completed.

When you call this, you will receive a Stripe "client_secret" that can be used to present a Stripe payment form. We provide examples of this in the examples section.

unit_id is a UUID-format string as received from getAvailabilities or unitFromUrl.

from and to are strings containing dates in the format described by getAvailabilities.

num_guests is either an integer or string containing integer number of guests staying at the property.

dogs is either an integer or string containing integer number of dogs staying at the property. This may be blank or 0.

cats is either an integer or string containing integer number of cats or other non-dog animals requiring a special deposit staying at the property. This may be blank or 0.

customer_id is the value obtained from validateUser.

city and state should be the unit's city and state as obtained from getAvailabilities. In a pinch, these can be blank strings; the purpose of passing these is to automatically query for alternative units if the unit was booked out from under the customer during the checkout process.

This call will return the following as an associative array:


{
    'available' => true,
    'client_secret' => Stripe client secret for payment intent
    'expires' => expiration UNIX timestamp, in seconds
    'contract_url' => URL to send the customer to sign contract
                      AFTER payment is done.  Use this as the
                      stripe return URL.
}
                    

If the unit was booked while the customer was going through the checkout process, you will instead receive:


{
    "available": false,
    "alternatives": [
        // same structure as 'getAvailability'
    ]
}
                    

In case of an error, which would be if, for instance, the dates are invalid, you will receive this instead. If your form is properly validating user input, this should never happen.


{
    "error": true,
    "message": "a helpful message"
}
                    

This call will always return a 200 status code unless provided an invalid API key.

$qsb->getNextAvailability (
  • string/integer: nights,
  • string/integer: num_guests,
  • string: state,
  • string: city
)

This call is used to fetch available units based on a number of days rather than specific dates. Specifically, it returns the next availabilities of all your units for a stay of 'nights' number of nights.

nights is the number of nights of availability required as an integer or string containing integer.

num_guests is the number of guests staying as an integer or string containing integer.

state contains a 2 letter state or province code as returned from getLocations. It is optional, if left off, all states will be queried.

city contains a city from getLocations. It is optional, if left off, all cities will be queried.

You will receive the following associative array as a return:


[
    {
        "id": "uuid based ID for unit",
        "title": "unit title",
        "url": "a URL for more information",
        "neighborhood": some brief text description about the location,
        "nights_available": Number of nights available
        "starting": date the nights_available starts,
        "city": city,
        "province": province
        "num_bedrooms": number of bedrooms,
        "num_bathrooms": number of bathrooms
    },
    ...
]

If invalid paramters are passed, you can receive an error object. You should validate the user's input rather than allow this to happen.


{
    "error": true,
    "message": a helpful message but maybe not the best for the user
}

This call will always return a 200 status code unless provided an invalid API key.

$qsb->getPricing(
  • string: unit_id,
  • string: from,
  • string: to,
  • string/integer: num_guests,
  • string/integer: num_dogs,
  • string/integer: num_cats,
  • string: city,
  • string: state,
  • string: customer_id
)

This call produces a full final price for a unit, completely broken down with taxes and fees. It is designed to be called when displaying the checkout screen.

unit_id is a UUID-format string as received from getAvailabilities or unitFromUrl.

from and to are strings containing dates in the format described by getAvailabilities.

num_guests is either an integer or string containing integer number of guests staying at the property.

dogs is either an integer or string containing integer number of dogs staying at the property. This may be blank or 0.

cats is either an integer or string containing integer number of cats or other non-dog animals requiring a special deposit staying at the property. This may be blank or 0.

city and state should be the unit's city and state as obtained from getAvailabilities. In a pinch, these can be blank strings; the purpose of passing these is to automatically query for alternative units if the unit was booked out from under the customer during the checkout process.

customer_id is the value obtained from validateUser. It is optional and may be an empty string or false if you don't have it. The reasoning for passing it here is so that, if a customer has a booking in progress, that booking won't count against availability if the getPricing is called during the checkout process.

You will receive the following associative array as a return:


{
    "available": true,
    "num_nights": integer number of nights in the stay,
    "pay_schedule": [
        {
            "charge_on": "YYYY-MM-DD",
            "amount": integer in stripe format
            "amount_tax": integer in stripe format
        },
        ...
    ],
    "totals": {
        "num_nights": integer number of nights of the stay
        "cat_deposit": integer amount in 'stripe' format
        "pet_fee": integer amount in 'stripe' format
        "authorize": integer amount in 'stripe' format
        "charge": integer amount in 'stripe' format
        "charge_tax": integer amount in 'stripe' format
        "monthly": integer amount in 'stripe' format
        "monthly_tax": integer amount in 'stripe' format
        "last_month": integer amount in 'stripe' format
        "last_month_tax": integer amount in 'stripe' format
        "total_cost": integer amount in 'stripe' format
        "total_tax": integer amount in 'stripe' format
        "utility_fee": integer amount in 'stripe' format
    },
    "title": "unit title",
    "description": "a brief description",
    "url": "a URL for more information",
    "price_per_night": price per night in 'stripe' format,
    "neighborhood": some brief text description about the location
}

Note about "pay_schedule"; this is a list of payments that will be made in the future, if the user has booked a reservation longer than 28 days and will thus be paying some kind of periodic rent instead of paying for the entire reservation up front.

Therefore, for reservations 28 days or shorter, this will be an empty list.

If the unit is not available because someone booked it before this call was made, you will receive:


{
    "available": false,
    "next_available": {  Next time the unit requested is available
        "available_start": "YYYY-MM-DD" date unit is available
        "available_checkout": "YYYY-MM-DD" proposed checkout date
        "available_nights": integer night count, or null if calendar is open.
        "title": "unit title",
        "description": "a brief description",
        "url": "a URL for more information",
        "neighborhood": some brief text description about the location,
        "max_guests": maximum number of guests,
        "num_bedrooms": integer number of bedrooms,
        "num_bathrooms": decimal number of bedrooms,
        "latitude": latitude geo location
        "longitude": longitude geo location,
        "type": This will be a text such as "House", "Apartment", etc.,
        "square_feet": size of unit in square feet
        "price": integer price in 'stripe' format
        "nights": number of nights,
        "price_per_night": price per night in 'stripe' format,
        "bed_info": [
            {
                "King": integer,
                "Queen": integer,
                ...  (keys will be missing if 0)
            },
            ...
        ]
    },
    "alternatives": [
        // same structure as 'getAvailability'
    ]
}

next_available is details about the next time the unit will be available, and 'alternatives' returns a list similar to getAvailability of other units that are available for the same dates and number of guests.

The following structure will be returned if invalid inputs are provided (i.e. incorrect dates). Ideally, you should validate user input to prevent this:


{
    "error": true,
    "message": a helpful message but maybe not the best for the user
}

This call will always return a 200 status code unless provided an invalid API key.

$qsb->unitFromUrl (
  • string: url
)

Unit URLs are used to glue your site and Quantum Suites together seamlessly. For more details about our recommendations here, see the section above.

The url parameter should be the end portion of a URL. For instance, if your unit detail page has the url:

http://yoursite.com/units/detail/1234.html

You could pass '1234.html' to the url parameter and receive the QSB unit ID assuming the unit URL is configured correctly in the QSB back-end.

You will receive the following array as a return:


[
    {
         "id": the unit ID
         "url": the URL we have on record
         "title": the title we have for the unit
    },
    ...
]

Note that it is technically possible to match multiple URLs in the case that what you pass isn't sufficiently distinct. Thus, this returns a list with all matches. Of course, you may also match nothing and receive an empty list. This call will never generate an error.

$qsb->blockedDates(
  • string: unit_id
)

Sometimes it is desirable to know which dates are already booked; for instance, when presenting a calendar widget for a unit, you may wish to have dates that are not available to be already blocked.

This call will return a list with start/end date pairs for a provided unit_id. You will receive the following array as a return:


[
  [start_date, end_date],
  [start_date, end_date],
  ...
]

This may be an empty list if the unit has no blocks on the calendar. It will never return an error assuming unit_id is valid (if it is not valid, you will receive a 404 error).

Samples

JavaScript Sample

This is a work in progress.

PHP Sample

This will be provided at a later date; we recommend reviewing the JavaScript sample. The best integrations use both, with PHP doing calls such as getLocation that can be cached locally and JavaScript handling the user interface bits.

Testing

In the future, we would like to be able to provide a sandbox vs. a live environment. However, at this time, we are unable to do that.

As such, the only way to test is to replace your live Stripe credentials with test Stripe credentials. This means that bookings will be put on your calendar when you do tests; be aware of this and clean up your test bookings.

We recommend you test using dates far in the future (1 year in the future, specifically) to avoid potentially blocking customer bookings.

See the following links for more information:

Integration Plugins

In the near future, this section will have information about plugins that will allow easy integrations with commonly used systems such as WordPress.

Right now, we're still in the launch stages of the Quantum Suites Booking Engine, and as such, we have not yet released any of our integrations.

However, we are planning on releasing a WordPress plugin in the near future. Feel free to contact us if you have an interest in an integration with some specific system, and we will consider building it. Or we may be able to add you to a beta program if it is a system we are already working on.

Contact us at: hello@quantumsuites.me