Building a "Nearby Store Availability" Experience

The following article will guide you through the process of creating and presenting a list of nearby store availability using the Booxi API.

Implementation

To implement this experience, we will follow these simple steps:

  • Retrieve all stores within your merchant group.
  • Request or identify the user’s geolocation (longitude and latitude).
  • Keep a list of nearby stores.
  • Fetch availability from these stores.
  • List store availability that best suits the query.


Please note that this implementation requires a Partner API Key

Your Partner API key must be requested to your Booxi Account Manager. The Partner API key must only be used in server side (backend) code to keep it a secret.

Retrieve Stores

First, you must build a list of all stores in your merchant group.  Use the GET /merchant/list API as per the details shown below. Make sure to provide a merchant group ID using the parameter groupId. Additional parameters such as offset and limit are available as well.

 

Note: If your merchant group has a limited number of stores, you could skip this step and obtain the longitude and latitude of each store using the GET/ merchantAvailability API.


Request URL

https://api.booxi.com/booking/v1/merchant/list

cURL

curl -X GET "https://api.booxi.com/booking/v1/merchant/list?groupId=201&offset=0&limit=20"
-H  "accept: application/json"

 

If your request is valid, the API’s response will include data formatted as a JSON object. Within the JSON object, an array named “items” will contain every store matching your query. Each store is assigned with a longitude and latitude. That information will be necessary in a further step.

 

You can test this API at the link below:

North America: https://api.booxi.com/doc/booking.html#/Directory/getMerchantList

Europe: https://api.booxi.eu/doc/booking.html#/Directory/getMerchantList

 

Here’s an example of a successful JSON response with a single result.

{
 "offset": 0,
 "limit": 20,
 "total": 1,
 "items": [
   {
     "id": 1,
     "name": "The Work Shop",
     "isAvailableOnline": true,
     "storeNumber": "US1210",
      "groupId": 201,
     "groupName": "Printing Co",
     "groupCategoryId": 30,
     "groupCategoryName": "Manhattan",
     "address": {...},
     "contactFirstName": "Jane",
     "contactLastName": "Poe",
     "phoneNumber": "+15553334444",
     "email": "jane@example.com",
     "tags": "self-service,open-late",
     "websiteUrl": "",
     "bookingUrl": "https://site.booxi.com/theworkshop?lang=eng",
     "apiKey": "...",
     "description": "The Work Shop is a great place to find and buy work supplies.",
     "coverImageUrl": "https://www.booxi.com/images/1tg3XisyCv0J9fQY.png",
     "profileImageUrl": "https://www.booxi.com/images/1tg3XisyCv0J9fQZ.png",
     "currency": "USD",
     "tax1Name": "CST",
     "tax1Rate": "0.0450",
     "tax2Name": "",
     "tax2Rate": "0",
     "timeZone": "America/New_York",
      "latitude": "40.6892361",
      "longitude": "-74.0445726",
     "defaultLanguage": "eng",
     "openHours": [
      {
         "dow": 1,
         "start": "09:00:00",
         "end": "13:45:00"
      }
     ]
   }
 ]
}

Request or Identify the User’s Geolocation

In order to build a list of stores nearest to the user, you must first obtain its current location. How you request or obtain that information will depend on your own implementation. From any address or geographic location, longitude and latitude can be determined using geocoding. There are several geocoding API available online such as Google Maps Platform.  Once you have assessed the user’s longitude and latitude, you can proceed to the next step.

Create a List of Nearby Stores

Using the haversine formula (see below), you can now calculate the geographic distance between the user and each store location. Repeat the process for each candidate and, each time, save the distance and its associated store ID. By the end of this step, you will have a list of nearby stores.

 

Haversine Function in Javascript

// Converts degrees to radians
function toRad(Value)
{
  return Value * Math.PI / 180;
}

// Haversine function - calculate distance between two locations and returns a value in km
function haversine(latitude1, longitude1, latitude2, longitude2)
{
  var R = 6371; // Earth’s radius in km (or 3,963 miles)
  var dLat = toRad(lat2-lat1); // delta latitude in radians
  var dLon = toRad(lon2-lon1); // delta longitude in radians
  var lat1 = toRad(lat1);
  var lat2 = toRad(lat2);
  var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
          Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2); 
  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
   var d = R * c;

  // returns distance in km
   return d; 

}

Fetch Availability From Stores

With a list of nearby stores, you can now query their availability. For this step, we recommend using the merchantAvailability API in order to fetch the 5 earliest availability per store within a 31-day window and so for a group of stores in a single query.

 

If you wish to fetch more than 5 availability per store, you will need to use the serviceAvailability API instead. This option requires fetching availability for each store individually while providing a specific service ID.  While this process necessitates more processing and is more complex, it provides a list of all availability within a 31-day window.

 

With the merchantAvailability API, fetch data for one or several stores by providing either a single store ID or a list. Use GET /merchantAvailability as shown below. Make sure to use the parameter serviceKeyword in order to limit the query to relevant results.

 

Request URL

https://api.booxi.com/booking/v1/merchantAvailability

 

cURL

curl -X GET "https://api.booxi.com/booking/v1/merchantAvailability?
merchantId=M001&merchantId=M003&merchantId=M010
&from=2022-05-10T09%3A30%3A00.00Z&to=2022-05-17T09%3A30%3A00.00Z
&serviceKeyword=consultation&serviceBookingMethod=Appointment" 

-H  "accept: application/json"

 

If your request is valid, the API’s response will include data formatted as a JSON object. For each available service, the API will return the earliest 5 availability along with its related service/merchant information.

 

You can test this API at the link below:

North America: https://api.booxi.com/doc/booking.html#/Availability/findAvailability

Europe: https://api.booxi.eu/doc/booking.html#/Availability/findAvailability

 

Here’s an example of a successful JSON response.

{
 "serviceAvailability": [
   {
     "start": "2021-12-01T09:00:00Z",
     "end": "2021-12-01T10:00:00Z",
     "serviceId": 1,
     "staffId": 1,
     "timeSelectionMode": "TimeSlot",
     "duration": 60,
     "price": {...},
     "locationText": "At 100 Right St",
     "groupEventId": 1,
     "capacity": 10,
     "placesLeft": 8,
     "metadata": {
       "referenceId": "102"
     }
   }
 ],
 "services": [
   {
     "id": 1,
     "merchantId": 1,
     "name": "Self Printing",
     "tags": "promotion,self-service",
     "duration": 30,
     "showDuration": true,
     "hasDurationCustomization": false,
     "bookingMethod": "Appointment",
     "location": "Business",
     "locationText": "",
     "price": {...},
     "hasPriceCustomization": false,
     "categoryId": 0,
     "categoryName": "Main Services",
     "description": "Enjoy using all of our equipment at your leisure.",
     "profileImageUrl": "https://www.booxi.com/images/1tg3XisyCv0J9fQB.png",
     "staffSelectionMode": "AssignedStaff",
     "timeSelectionMode": "TimeSlot",
     "maxReservationSize": 0,
     "bookingPolicy": "Cancel at least 24 h before the appointment time.",
     "instructions": "Please arrive 10 minutes before the start of your appointment.",
     "metadata": {
       "referenceId": "102"
     },
   }
 ],
 "staff": [
   {
     "id": 1,
     "name": "Jane Poe",
     "firstName": "Jane",
     "lastName": "Poe",
     "position": "Manager",
     "biography": "The friendly manager.",
     "profileImageUrl": "https://www.booxi.com/images/1tg3XisyCv0J9fQX.png",
     "timeSelectionMode": "ServiceTimeSelection"
   }
  ],

 "merchants": [
   {
     "id": 1,
     "name": "The Work Shop",
     "isAvailableOnline": true,
     "storeNumber": "US1210",
     "groupId": 201,
     "groupName": "Printing Co",
     "groupCategoryId": 30,
     "groupCategoryName": "Manhattan",
     "address": {...},
     "contactFirstName": "Jane",
     "contactLastName": "Poe",
     "phoneNumber": "+15553334444",
     "email": "jane@example.com",
     "tags": "self-service,open-late",
     "websiteUrl": "",
     "bookingUrl": "https://site.booxi.com/theworkshop?lang=eng",
     "apiKey": "7L9K7N2QrELXYJ8PJBsAtSA7HuL3BgRs",
     "description": "The Work Shop is a great place to find and buy work supplies.",
     "coverImageUrl": "https://www.booxi.com/images/1tg3XisyCv0J9fQY.png",
     "profileImageUrl": "https://www.booxi.com/images/1tg3XisyCv0J9fQZ.png",
     "currency": "USD",
     "tax1Name": "CST",
     "tax1Rate": "0.0450",
     "tax2Name": "",
     "tax2Rate": "0",
     "timeZone": "America/New_York",
     "latitude": "40.6892361",
     "longitude": "-74.0445726",
     "defaultLanguage": "eng",
     "openHours": [
       {
         "dow": 1,
         "start": "09:00:00",
         "end": "13:45:00"
       }
     ]
   }
 ],
 "cursor": "string"
}

An API call may return the content with paging. A cursor will be provided if more data needs to be fetched by calling the same API again with the provided cursor.

List Availability

From this point, you can choose how the results will be ordered and presented to the user. For each nearby store, assign a “Book Now” button and make use of our Booking Widget to complete an appointment or, implement your own booking experience using the booking API. For further details on how to book an appointment using the booking API, please consult this article.

References

For more information about the API and its usage, refer to the following links:

Where to find API keys:

  • Your Merchant API key can be found in the back office, section My Business / Business Details.
  • Your Partner API key must be requested to your Booxi Account Manager. The Partner API key must only be used in server-side (backend) code to keep it a secret.