Add asynchronous bookings

Synchronous bookings are defined as bookings that are confirmed or declined in real time.

Asynchronous bookings are defined as bookings that the merchant confirms or declines at a later time.

A booking is specified as either synchronous or asynchronous at the availability-level. This also means that for a given merchant and service, there could be both synchronous and asynchronous availability slots.

To determine the appropriate implementation, first identify which category your inventory falls under:

Asynchronous booking criteria

  • Modification of an async booking on the Actions Center is not supported.
  • Merchants should be able to accept or decline the booking through the partner's online system (e.g. host panel for the restaurant). Calling the merchant on behalf of the user to determine if the merchant accepts or declines a booking is not allowed.
  • Merchant proposal of a new booking time is not supported. The booking request must be accepted or declined in the original state.

Enabling synchronous bookings only

The standard implementation defaults to synchronous bookings. Please consult the Appointments End-to-End integration documentation for further information.

Enabling asynchronous booking

If some or all of the merchants use an asynchronous booking flow, the following changes need to be made:

  • Confirmation mode: All representations of availability slots now contain a confirmation_mode field which describes how bookings of that availability slot are confirmed. Specify the confirmation_mode of each availability slot for the following:

    • In the Availability Feed, confirmation_mode is specified at the availability level
    • In the Booking Server API methods, confirmation_mode is specified at the slot level
    • In the Real-Time Updates API methods, confirmation_mode is specified at the availability level
  • Booking status: All representations of bookings contain a status field that represents the state of the booking. Three new asynchronous status values have beeen introduced: PENDING_CONFIRMATION, DECLINED_BY_MERCHANT, and FAILED. Use these new status values when processing creations, declines, and failures of asynchronous bookings.
  • Booking updates: All asynchronous updates to the status of the bookings should be reported via the Booking Notification API's bookings.patch method.

The diagram below shows how confirmation mode and booking status are used in a typical asynchronous booking interaction.

Figure 1: Asynchronous booking flow
Figure 1: Asynchronous booking flow
  1. Availability feeds have been updated so that each availability slot’s confirmation mode is specified. It is important to have this information in the feed so that we can explain the asynchronous nature of the booking to the user early on in the flow.
  2. When BatchAvailabilityLookup or CheckAvailability is called, we pass along the confirmation mode and ideally the same confirmation mode to be returned. This ensures the user is shown the appropriate messaging.
  3. When CreateBooking is called, we pass along the confirmation mode to indicate the anticipated confirmation mode. When the asynchronous booking request is submitted, the booking is returned with status PENDING_MERCHANT_CONFIRMATION.
  4. When the merchant accepts or declines a booking request, the booking status is updated via the real-time update Booking Notification API’s bookings.patch method. If you want to auto-decline bookings that are not responded to in a timely fashion, do so via the same real-time update method.

Availability Feeds

In the availability feed, specify if each slot is synchronous or asynchronous. To do this, set the new confirmation_mode field.

// Mode by which bookings for an availability slot are confirmed.
//
enum ConfirmationMode {
  // The confirmation mode was not specified.
  // Synchronous confirmation will be assumed.
  CONFIRMATION_MODE_UNSPECIFIED = 0;
  // Bookings for this availability will be confirmed synchronously.
  CONFIRMATION_MODE_SYNCHRONOUS = 1;
  // Bookings for this availability will be confirmed asynchronously.
  CONFIRMATION_MODE_ASYNCHRONOUS = 2;
}

Although the confirmation mode is assumed to be synchronous if no mode is specified, it is strongly encouraged to explicitly specify a mode since that removes any confusion around accidental omissions.

Async

{
  "availability": [
    {
      "merchant_id": "10001",
      "service_id": "1000",
      "spots_open": 3,
      "spots_total": 3,
      "duration_sec": 3600,
      "start_sec": 1535806800,
      "resources": {
        "party_size": 4
      },
      "confirmation_mode": "CONFIRMATION_MODE_ASYNCHRONOUS"
    }
  ]
}

Sync

{
  "availability": [
    {
      "merchant_id": "10001",
      "service_id": "1000",
      "spots_open": 3,
      "spots_total": 3,
      "duration_sec": 3600,
      "start_sec": 1535806800,
      "resources": {
        "party_size": 4
      },
      "confirmation_mode": "CONFIRMATION_MODE_SYNCHRONOUS"
    }
  ]
}

Async and Sync

{
  "availability": [
    {
      "merchant_id": "10001",
      "service_id": "1000",
      "spots_open": 3,
      "spots_total": 3,
      "duration_sec": 3600,
      "start_sec": 1535806800,
      "resources": {
        "party_size": 4
      },
      "confirmation_mode": "CONFIRMATION_MODE_SYNCHRONOUS"
    },
    {
      "merchant_id": "10002",
      "service_id": "1000",
      "spots_open": 4,
      "spots_total": 4,
      "duration_sec": 3600,
      "start_sec": 1535806800,
      "resources": {
        "party_size": 2
      },
      "confirmation_mode": "CONFIRMATION_MODE_ASYNCHRONOUS"
    }

  ]
}

Booking Server

BatchAvailabilityLookup or CheckAvailability

In the BatchAvailabilityLookupResponse (BAL) or CheckAvailabilityResponse (CA), return the same confirmation_mode as is specified in the availability feed and passed along via the BatchAvailabilityLookupRequest or CheckAvailabilityRequest.

BAL-Async

{
  "slot_time_availability": [
    {
      "slot_time": {
        "duration_sec": "3600",
        "resource_ids": {
          "party_size": 3
        },
        "service_id": "1000",
        "start_sec": "1546458300",
        "confirmation_mode": "CONFIRMATION_MODE_ASYNCHRONOUS"
      },
      "available": true
    }
  ]
}

BAL-Sync

{
  "slot_time_availability": [
    {
      "slot_time": {
        "duration_sec": "3600",
        "resource_ids": {
          "party_size": 3
        },
        "service_id": "1000",
        "start_sec": "1546458300",
        "confirmation_mode": "CONFIRMATION_MODE_SYNCHRONOUS"
      },
      "available": true
    }
  ]
}

CA-Async

{
  "slot": {
    "duration_sec": "3600",
    "merchant_id": "317652",
    "resources": {
      "party_size": 3
    },
    "service_id": "1000",
    "start_sec": "1546458300",
    "confirmation_mode": "CONFIRMATION_MODE_ASYNCHRONOUS"
  },
  "count_available": 1,
  "duration_requirement": "DO_NOT_SHOW_DURATION"
}

CA-Sync

{
  "slot": {
    "duration_sec": "3600",
    "merchant_id": "317652",
    "resources": {
      "party_size": 3
    },
    "service_id": "1000",
    "start_sec": "1546458300",
    "confirmation_mode": "CONFIRMATION_MODE_SYNCHRONOUS"
  },
  "count_available": 1,
  "duration_requirement": "DO_NOT_SHOW_DURATION"
}

CreateBooking

Make sure to return the correct status for the booking using the available options below:

// Status of a booking.
//
// Updating booking status does not change the status of the associated payment.
// Prepayment status updates should be done using the PrepaymentStatus enum.
enum BookingStatus {
  // Not specified.
  BOOKING_STATUS_UNSPECIFIED = 0;
  // Booking has been confirmed
  CONFIRMED = 1;
  // Booking is awaiting confirmation by the merchant before it can transition
  // into CONFIRMED status. Only applicable to non-payments Dining or
  // Beauty verticals.
  PENDING_MERCHANT_CONFIRMATION = 2;
  // Booking has been canceled on behalf of the user.
  // The merchant can still trigger a manual refund.
  CANCELED = 3;
  // User did not show for the appointment
  NO_SHOW = 4;
  // User did not show for the appointment in violation of the cancellation
  // policy.
  NO_SHOW_PENALIZED = 5;
  // Booking could not be completed by the async backend due to a failure.
  FAILED = 6;
  // Booking was asynchronously declined by the merchant. Only applicable to
  // non-payments Dining or Beauty verticals.
  DECLINED_BY_MERCHANT = 7;
}

In the CreateBookingResponse, return the current confirmation_mode for the booking's aggregated slot provided in the CreateBookingRequest. In addition, when the booking is asynchronous, set the status to PENDING_MERCHANT_CONFIRMATION. Please ensure the confirmation_mode is what the user and what Reserve with Google expects to avoid confusing the user.

Async

{
  "booking": {
    "slot": {
      "duration_sec": "3600",
      "merchant_id": "100001",
      "resources": {
        "party_size": 2
      },
      "service_id": "1000",
      "start_sec": "1546647234",
      "confirmation_mode": "CONFIRMATION_MODE_ASYNCHRONOUS"
    },
    "user_information": {
      "email": "johnsmith@gmail.com",
      "family_name": "John",
      "given_name": "Smith",
      "telephone": "+1 800-123-4567",
      "user_id": "2017492857928759285"
    },
    "payment_information": {
      "prepayment_status": "PREPAYMENT_NOT_PROVIDED"
    },
    "status": "PENDING_MERCHANT_CONFIRMATION"
  }
}

Sync

{
  "booking": {
    "slot": {
      "duration_sec": "3600",
      "merchant_id": "100001",
      "resources": {
        "party_size": 2
      },
      "service_id": "1000",
      "start_sec": "1546647234",
      "confirmation_mode": "CONFIRMATION_MODE_SYNCHRONOUS"
    },
    "user_information": {
      "email": "johnsmith@gmail.com",
      "family_name": "John",
      "given_name": "Smith",
      "telephone": "+1 800-123-4567",
      "user_id": "2017492857928759285"
    },
    "payment_information": {
      "prepayment_status": "PREPAYMENT_NOT_PROVIDED"
    },
    "status": "CONFIRMED"
  }
}

UpdateBooking

In the initial release of async, user modifications to an existing booking are not supported. Instead, the user should cancel the booking and create a new booking.

Real-Time Updates

For real-time updates to availabilities, confirmation_mode should be specified. This applies for the following methods:

Inventory RTU (ReplaceServiceAvailability or BatchReplaceServiceAvailability)

Using availability.replace (batch) method or services.availability.replace method, set confirmation_mode to CONFIRMATION_MODE_ASYNCHRONOUS in the Availability

Async

{
  "extendedServiceAvailability": [
    {
      "merchantId": "1001",
      "serviceId": "12310",
      "startTimeRestrict": "2014-10-02T15:01:23.045123456Z",
      "endTimeRestrict": "2014-10-02T19:01:23.045123456Z",
      "availability": [
        {
          "startTime": "2014-10-02T15:30:00.00Z",
          "duration": "3600s",
          "spotsOpen": "0",
          "spotsTotal": "2",
          "availabilityTag": "1000001",
          "confirmation_mode": "CONFIRMATION_MODE_ASYNCHRONOUS"
        }
      ]
    }
  ]
}

Sync

{
  "extendedServiceAvailability": [
    {
      "merchantId": "1001",
      "serviceId": "12310",
      "startTimeRestrict": "2014-10-02T15:01:23.045123456Z",
      "endTimeRestrict": "2014-10-02T19:01:23.045123456Z",
      "availability": [
        {
          "startTime": "2014-10-02T15:30:00.00Z",
          "duration": "3600s",
          "spotsOpen": "0",
          "spotsTotal": "2",
          "availabilityTag": "1000001",
          "confirmation_mode": "CONFIRMATION_MODE_SYNCHRONOUS"
        }
      ]
    }
  ]
}

Async and Sync

{
  "extendedServiceAvailability": [
    {
      "merchantId": "1001",
      "serviceId": "12310",
      "startTimeRestrict": "2014-10-02T15:01:23.045123456Z",
      "endTimeRestrict": "2014-10-02T19:01:23.045123456Z",
      "availability": [
        {
          "startTime": "2014-10-02T15:30:00.00Z",
          "duration": "3600s",
          "spotsOpen": "0",
          "spotsTotal": "2",
          "availabilityTag": "1000001",
          "confirmation_mode": "CONFIRMATION_MODE_ASYNCHRONOUS"
        },
        {
          "startTime": "2014-10-03T11:00:00.00Z",
          "duration": "5400s",
          "spotsOpen": "1",
          "spotsTotal": "1",
          "availabilityTag": "1000002",
          "confirmation_mode": "CONFIRMATION_MODE_SYNCHRONOUS"
        }
      ]
    }
  ]
}

Booking Notification API

Asynchronous updates to a booking status should be made via the Booking Notification API bookings.patch method.

When updating the status, make sure to include the status field name in the updateMask.

Status Description
CONFIRMED merchant confirmed the booking
FAILED partner could not confirm or decline the booking with the merchant
DECLINED_BY_MERCHANT merchant declined the booking
Request:
PATCH https://mapsbooking.googleapis.com/v1alpha/notification/partners/<PARTNER_ID>/bookings/<BOOKING_ID>?updateMask=status

Body:
{"name":"partners/<PARTNER_ID>/bookings/<BOOKING_ID>", "status":"DECLINED_BY_MERCHANT"}

In the event of a booking failure, set the booking status to FAILED and specify the booking_failure. If the status is set to anything else, the booking_failure is ignored.

Request:
PATCH https://mapsbooking.googleapis.com/v1alpha/notification/partners/<PARTNER_ID>/bookings/<BOOKING_ID>?updateMask=status&booking_failure.cause="SLOT_UNAVAILABLE"

Body:
{"name":"partners/<PARTNER_ID>/bookings/<BOOKING_ID>", "status":"FAILED"}

Email Notifications

For asynchronous bookings, there are five potential emails related to the status of the booking that are sent to users.

  • PENDING_MERCHANT_CONFIRMATION
  • CONFIRMED
  • DECLINED_BY_MERCHANT
  • FAILED
  • CANCELED