Initial push of API v3 test utility.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..94809b7
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,2 @@
+Unfortunately, given the nature of the tools provided here, we do not
+accept contributions.
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..7a4a3ea
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..5cf8846
--- /dev/null
+++ b/README.md
@@ -0,0 +1,133 @@
+# Maps Booking
+
+This repo contains tools and code samples for partners that wish to integrate
+with [Reserve](https://www.google.com/maps/reserve/) API v3.
+
+## Testing Client
+
+Before using the test utility, the Go programming language must be installed
+on your workstation. A precompiled Go binary for your operating system can
+be [found here](https://golang.org/dl/)
+
+This guide will assume you're using the default GOPATH and subsequent GOBIN.
+For a comprehensive explanation of the GOPATH env variable please see
+[this document](https://golang.org/dl/) by the Go team.
+
+### Installing the utility with Linux
+
+First, build your Go directory structure. A comprehensive guide on the intended
+structure of Go code can be [found here.](https://golang.org/doc/code.html)
+
+    mkdir -p $HOME/go/bin $HOME/go/pkg $HOME/go/src/github.com/maps-booking
+
+Next, add the following to your ~/.bashrc
+
+    export PATH=$PATH:$(go env GOPATH)/bin
+    export GOPATH=$(go env GOPATH)
+    export GOBIN=$(go env GOPATH)/bin
+
+Source changes
+
+    source ~/.bashrc
+
+Next, retrieve the utility from the
+[maps-booking repository](https://maps-booking.googlesource.com/)
+
+    git clone https://maps-booking.googlesource.com/test_client $HOME/go/src/github.com/maps-booking/
+
+Lastly, download all dependencies and install the tool.
+
+    cd $HOME/go
+    go get -d ./...
+    go install $HOME/go/src/github.com/maps-booking/testclient/main.go
+
+### Installing the utility with Windows Powershell
+
+First, build your Go directory structure. A comprehensive guide on the intended
+structure of Go code can be [found here.](https://golang.org/doc/code.html)
+
+    $env:HOME = $env:USERPROFILE
+    md $env:HOME\go\bin
+    md $env:HOME\go\pkg
+    md $env:HOME\go\src\github.com\maps-booking
+
+Next, set the appropriate environment variables
+
+    $env:PATH = $env:PATH + ";" + (go env GOPATH) + "\bin"
+    $env:GOPATH = (go env GOPATH)
+    $env:GOBIN = (go env GOPATH) + "\bin"
+
+Next, retrieve the utility from the
+[maps-booking repository](https://maps-booking.googlesource.com/)
+
+    git clone https://maps-booking.googlesource.com/test_client $env:HOME\go\src\github.com\maps-booking\
+
+Lastly, download all dependencies and install the tool.
+
+    cd $env:HOME\go
+    go get -d .\...
+    go install $env:HOME\go\src\github.com\maps-booking\testclient\main.go
+
+### Using the utility
+
+After following the install steps above an executable should now live in
+
+    $HOME/go/bin/main
+
+or
+
+    $env:HOME\go\bin\main.exe
+
+All available flags can be displayed using the '--help' flag. The currently
+accepted flags are:
+
+    -all_tests
+        Whether to test all endpoints.
+    -availability_feed string
+        Absolute path to availability feed required for all tests except health.
+        Feeds can be in either json or pb3 format
+    -booking_status_test
+        Whether to test the GetBookingStatus endpoint.
+    -booking_test
+        Whether to test the CreateBooking endpoint.
+    -ca_file string
+        Absolute path to your server's Certificate Authority root cert.
+        Downloading all roots currently recommended by the Google Internet
+        Authority is a suitable alternative https://pki.google.com/roots.pem
+    -cancel_all_bookings
+        This option assumes that the ListBookings and UpdateBooking endpoints
+        are fully functional. This is a convenience flag for purging your system
+        of all previously created bookings.
+    -check_availability_test
+        Whether to test the CheckAvailability endpoint.
+    -health_check_test
+        Whether to test the Health endpoint.
+    -list_bookings_test
+        Whether to test the ListBookings endpoint
+    -num_test_slots int
+        Maximum number of slots to test from availability_feed. Slots will be
+        selected randomly (default 10)
+    -output_dir string
+        Absolute path of dir to dump log file.
+    -rescheduling_test
+        Whether to test the UpdateBooking endpoint.
+    -server_addr string
+        Your http server's address in the format of host:port
+        (default "example.com:80")
+    -username_password string
+        (eg 'username:password') credentials for your server. Leave blank to bypass authentication.
+
+Example Usage:
+
+    bin/main -health_check_test=true -check_availability_test=true
+    -output_dir="/tmp" -server_addr="http-service.google.com:50051”
+    -availability_feed="/tmp/test.json"
+
+### Parsing the output
+
+The test utility will output a file with the prefix 'http_test_client_log_'
+followed by a timestamp in RFC3339 format. The output file contains a
+complete log of all Requests and Responses sent/received by the testing tool as
+well as diffs of the expected response in the event of errors.
+Similar to a compiler, an overview of the entire run can be found at the end
+of the file for user friendly digestion.
diff --git a/api/api.go b/api/api.go
new file mode 100644
index 0000000..56d518f
--- /dev/null
+++ b/api/api.go
@@ -0,0 +1,368 @@
+/*
+Copyright 2017 Google Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package api contains validation wrappers over BookingService endpoints.
+package api
+
+import (
+	"bytes"
+	"encoding/base64"
+	"errors"
+	"fmt"
+	"log"
+	"math/rand"
+	"net/http"
+	"sort"
+	"strconv"
+	"time"
+
+	"github.com/golang/protobuf/jsonpb"
+	"github.com/golang/protobuf/proto"
+	"github.com/google/go-cmp/cmp"
+	"github.com/maps-booking/utils"
+
+	fpb "github.com/maps-booking/feeds"
+	mpb "github.com/maps-booking/v3"
+)
+
+const (
+	userID    = "0"
+	firstName = "Jane"
+	lastName  = "Doe"
+	telephone = "+18007897890"
+	email     = "test@example.com"
+)
+
+// HTTPConnection is a convenience struct for holding connection-related objects.
+type HTTPConnection struct {
+	client      *http.Client
+	credentials string
+	marshaler   *jsonpb.Marshaler
+	baseURL     string
+}
+
+// InitHTTPConnection creates and returns a new HTTPConnection object
+// with a given server address and username/password.
+func InitHTTPConnection(serverAddr string, usernamePassword string) *HTTPConnection {
+	return &HTTPConnection{
+		client:      &http.Client{Timeout: time.Duration(1 * time.Second)},
+		credentials: "Basic " + base64.StdEncoding.EncodeToString([]byte(usernamePassword)),
+		marshaler:   &jsonpb.Marshaler{},
+		// TODO(wsilberm): Use https
+		baseURL: "http://" + serverAddr,
+	}
+}
+
+func (h HTTPConnection) getURL(rpcName string) string {
+	if rpcName != "" {
+		return h.baseURL + "/v3/" + rpcName
+	}
+	return h.baseURL
+}
+
+// Bookings is a convenience type for a booking array.
+type Bookings []*mpb.Booking
+
+func (b Bookings) Len() int {
+	return len(b)
+}
+
+func (b Bookings) Less(i, j int) bool {
+	return b[i].GetBookingId() < b[j].GetBookingId()
+}
+
+func (b Bookings) Swap(i, j int) {
+	b[i], b[j] = b[j], b[i]
+}
+
+// HealthCheck performs a health check.
+func HealthCheck(conn *HTTPConnection) error {
+	utils.LogFlow("Health Check", "Start")
+	defer utils.LogFlow("Health Check", "End")
+
+	// See if we get a response.
+	_, err := http.Get(conn.getURL(""))
+	if err != nil {
+		return fmt.Errorf("could not complete health check: %v", err)
+	}
+	log.Println("health check success!")
+	return nil
+}
+
+// sendRequest sets up and sends the relevant HTTP request to the server and returns the HTTP response.
+func sendRequest(rpcName string, req string, conn *HTTPConnection) (*http.Response, error) {
+	httpReq, err := http.NewRequest("POST", conn.getURL(rpcName), bytes.NewBuffer([]byte(req)))
+	httpReq.Header.Set("Content-Type", "application/json")
+	httpReq.Header.Set("Authorization", conn.credentials)
+	log.Printf("%v Request. Sent(unix): %s, Request %v\n", rpcName, time.Now().UTC().Format(time.RFC850), httpReq)
+
+	httpResp, err := conn.client.Do(httpReq)
+	if err != nil {
+		return nil, fmt.Errorf("invalid response. CheckAvailability yielded error: %v", err)
+	}
+	return httpResp, nil
+}
+
+// CheckAvailability beforms a maps booking availability check on all supplied availability slots. This function
+// will return all slots with a valid return.
+func CheckAvailability(a *fpb.Availability, conn *HTTPConnection) error {
+	slot, err := utils.BuildSlotFrom(a)
+	if err != nil {
+		return fmt.Errorf("unable to build request for check availability flow. err: %v, availability record: %v", err, a.String())
+	}
+	reqPB := &mpb.CheckAvailabilityRequest{
+		Slot: slot,
+	}
+	req, err := conn.marshaler.MarshalToString(reqPB)
+	if err != nil {
+		return fmt.Errorf("Could not convert pb3 to json: %v", reqPB)
+	}
+	httpResp, err := sendRequest("CheckAvailability", req, conn)
+	if err != nil {
+		return fmt.Errorf("invalid response. CheckAvailability yielded error: %v", err)
+	}
+	defer httpResp.Body.Close()
+	var resp mpb.CheckAvailabilityResponse
+	if err := jsonpb.Unmarshal(httpResp.Body, &resp); err != nil {
+		return fmt.Errorf("CheckAvailability: Could not parse HTTP response to pb3: %v", err)
+	}
+
+	log.Printf("CheckAvailability Response. Received(unix): %s, Response %s", time.Now().UTC().Format(time.RFC850), resp.String())
+
+	if diff := cmp.Diff(resp.GetSlot(), slot, cmp.Comparer(proto.Equal)); diff != "" {
+		return fmt.Errorf("invalid response. CheckAvailability slots differ (-got +want)\n%s", diff)
+	}
+
+	if resp.GetCountAvailable() == 0 {
+		return errors.New("no count available in response")
+	}
+
+	return nil
+}
+
+// CreateBooking attempts to create bookings from availability slots.
+func CreateBooking(a *fpb.Availability, conn *HTTPConnection) (*mpb.Booking, error) {
+	slot, err := utils.BuildSlotFrom(a)
+	if err != nil {
+		return nil, fmt.Errorf("unable to build request for check availability flow. err: %v, availability record: %v", err, a.String())
+	}
+
+	gen := rand.New(rand.NewSource(time.Now().UnixNano()))
+	// Lease currently unsupported.
+	reqPB := &mpb.CreateBookingRequest{
+		Slot: slot,
+		UserInformation: &mpb.UserInformation{
+			UserId:     userID,
+			GivenName:  firstName,
+			FamilyName: lastName,
+			Telephone:  telephone,
+			Email:      email,
+		},
+		PaymentInformation: &mpb.PaymentInformation{
+			PrepaymentStatus: mpb.PrepaymentStatus_PREPAYMENT_NOT_PROVIDED,
+		},
+		IdempotencyToken: strconv.Itoa(gen.Intn(1000000)),
+	}
+	req, err := conn.marshaler.MarshalToString(reqPB)
+	if err != nil {
+		return nil, fmt.Errorf("Could not convert pb3 to json: %v", reqPB)
+	}
+
+	httpResp, err := sendRequest("CreateBooking", req, conn)
+	if err != nil {
+		return nil, fmt.Errorf("invalid response. CreateBooking  yielded error: %v", err)
+	}
+	defer httpResp.Body.Close()
+	var resp mpb.CreateBookingResponse
+	if err := jsonpb.Unmarshal(httpResp.Body, &resp); err != nil {
+		return nil, fmt.Errorf("CreateBooking: Could not parse HTTP response to pb3: %v", err)
+	}
+
+	log.Printf("CreateBooking Response. Received(unix): %s, Response %s", time.Now().UTC().Format(time.RFC850), resp.String())
+	if resp.GetBookingFailure() != nil {
+		return nil, fmt.Errorf("invalid response. CreateBooking failed with booking failure %v", resp.GetBookingFailure())
+	}
+
+	b := resp.GetBooking()
+	if iE := utils.ValidateBooking(b, &mpb.Booking{
+		Slot:               reqPB.GetSlot(),
+		UserInformation:    reqPB.GetUserInformation(),
+		PaymentInformation: reqPB.GetPaymentInformation(),
+	}); iE != nil {
+		return nil, fmt.Errorf("invalid response. CreateBooking invalid: %s", iE.Error())
+	}
+
+	// Perform idempotency test.
+	log.Printf("Idempotency check -- CreateBooking Request. Sent(unix): %s, Request %s", time.Now().UTC().Format(time.RFC850), reqPB.String())
+	idemHTTPResp, err := sendRequest("CreateBooking", req, conn)
+	if err != nil {
+		return nil, fmt.Errorf("invalid response. Idempotency check yielded error: %v", err)
+	}
+	defer idemHTTPResp.Body.Close()
+	var idemResp mpb.CreateBookingResponse
+	if err := jsonpb.Unmarshal(httpResp.Body, &resp); err != nil {
+		return nil, fmt.Errorf("CreateBooking idem: Could not parse HTTP response to pb3: %v", err)
+	}
+
+	log.Printf("Idempotency check -- Response. Received(unix): %s, Response %s", time.Now().UTC().Format(time.RFC850), idemResp.String())
+	if diff := cmp.Diff(idemResp, resp); diff != "" {
+		return b, fmt.Errorf("Idempotency check invalid (-got +want)\n%s", diff)
+	}
+
+	return b, nil
+}
+
+// ListBookings calls the maps booking ListBookings rpc and compares the return with all input bookings.
+func ListBookings(tB Bookings, conn *HTTPConnection) (Bookings, error) {
+	var out Bookings
+	reqPB := &mpb.ListBookingsRequest{
+		UserId: userID,
+	}
+	req, err := conn.marshaler.MarshalToString(reqPB)
+	if err != nil {
+		return nil, fmt.Errorf("Could not convert pb3 to json: %v", reqPB)
+	}
+	httpResp, err := sendRequest("ListBookings", req, conn)
+	if err != nil {
+		return nil, fmt.Errorf("invalid response. ListBookings yielded error: %v. Abandoning all booking from this flow", err)
+	}
+	defer httpResp.Body.Close()
+	var resp mpb.ListBookingsResponse
+	if err := jsonpb.Unmarshal(httpResp.Body, &resp); err != nil {
+		return nil, fmt.Errorf("ListBookings: Could not parse HTTP response to pb3: %v", err)
+	}
+
+	log.Printf("ListBookings Response. Received(unix): %s, Response %s", time.Now().UTC().Format(time.RFC850), resp.String())
+	gB := Bookings(resp.GetBookings())
+	if len(gB) != len(tB) {
+		return out, fmt.Errorf("number of bookings differ, ListBookings invalid. Got: %d, Want: %d. Abandoning all bookings from this flow", len(gB), len(tB))
+	}
+
+	sort.Sort(gB)
+	sort.Sort(tB)
+	for i := 0; i < len(tB); i++ {
+		if iE := utils.ValidateBooking(gB[i], tB[i]); iE != nil {
+			log.Printf("ListBookings invalid, %s, abandoning slot %d/%d", iE.Error(), i, len(tB))
+			continue
+		}
+		out = append(out, tB[i])
+	}
+
+	return out, nil
+}
+
+// GetBookingStatus checks that all input bookings are in an acceptable state.
+func GetBookingStatus(b *mpb.Booking, conn *HTTPConnection) error {
+	reqPB := &mpb.GetBookingStatusRequest{
+		BookingId: b.GetBookingId(),
+	}
+
+	req, err := conn.marshaler.MarshalToString(reqPB)
+	if err != nil {
+		return fmt.Errorf("Could not convert pb3 to json: %v", reqPB)
+	}
+	httpResp, err := sendRequest("GetBookingStatus", req, conn)
+	if err != nil {
+		return fmt.Errorf("invalid response. GetBookingStatus yielded error: %v", err)
+	}
+	defer httpResp.Body.Close()
+	var resp mpb.GetBookingStatusResponse
+	if err := jsonpb.Unmarshal(httpResp.Body, &resp); err != nil {
+		return fmt.Errorf("GetBookingsStatus: Could not parse HTTP response to pb3: %v", err)
+	}
+
+	log.Printf("GetBookingStatus Response. Received(unix): %s, Response %s", time.Now().UTC().Format(time.RFC850), resp.String())
+	if diff := cmp.Diff(resp.GetBookingStatus(), mpb.BookingStatus_CONFIRMED); diff != "" {
+		return fmt.Errorf("invalid response. BookingStatus differ (-got +want)\n%s", diff)
+	}
+
+	return nil
+}
+
+// CancelBooking is a clean up method that cancels all supplied bookings.
+func CancelBooking(b *mpb.Booking, conn *HTTPConnection) error {
+	b.Status = mpb.BookingStatus_CANCELED
+	reqPB := &mpb.UpdateBookingRequest{
+		Booking: b,
+	}
+	req, err := conn.marshaler.MarshalToString(reqPB)
+	if err != nil {
+		return fmt.Errorf("Could not convert pb3 to json: %v", reqPB)
+	}
+	httpResp, err := sendRequest("UpdateBooking", req, conn)
+	if err != nil {
+		return fmt.Errorf("invalid response. UpdateBooking yielded error: %v", err)
+	}
+	defer httpResp.Body.Close()
+	var resp mpb.UpdateBookingResponse
+	if err := jsonpb.Unmarshal(httpResp.Body, &resp); err != nil {
+		return fmt.Errorf("CancelBooking: Could not parse HTTP response to pb3: %v", err)
+	}
+
+	log.Printf("UpdateBooking Response. Received(unix): %s, Response %s", time.Now().UTC().Format(time.RFC850), resp.String())
+	if iE := utils.ValidateBooking(resp.GetBooking(), reqPB.GetBooking()); iE != nil {
+		return fmt.Errorf("invalid response. UpdateBooking: %s", iE.Error())
+	}
+	return nil
+}
+
+// Rescheduling will attempt to create a booking, update the booking, then cancel.
+func Rescheduling(av []*fpb.Availability, conn *HTTPConnection) error {
+	var slots []*fpb.Availability
+	for _, v := range utils.BuildMerchantServiceMap(av) {
+		// Need at least two slots for reschedule.
+		if len(v) <= 1 {
+			continue
+		}
+		slots = v
+		break
+	}
+
+	if len(slots) == 0 {
+		return errors.New("no suitable availability for rescheduling flow. exiting")
+	}
+	// Book first slot.
+	newBooking, err := CreateBooking(slots[0], conn)
+	if err != nil {
+		return fmt.Errorf("could not complete booking, abandoning rescheduling flow: %v", err)
+	}
+	slot := newBooking.GetSlot()
+
+	// New slot.
+	lastAvailability := slots[len(slots)-1]
+	slot.StartSec = lastAvailability.GetStartSec()
+	slot.DurationSec = lastAvailability.GetDurationSec()
+
+	reqPB := &mpb.UpdateBookingRequest{
+		Booking: newBooking,
+	}
+	req, err := conn.marshaler.MarshalToString(reqPB)
+	if err != nil {
+		return fmt.Errorf("Rescheduling UpdateBooking: Could not convert pb3 to json: %v", reqPB)
+	}
+	updateHTTPResp, err := sendRequest("UpdateBooking", req, conn)
+	defer updateHTTPResp.Body.Close()
+	var resp mpb.CreateBookingResponse
+	if err := jsonpb.Unmarshal(updateHTTPResp.Body, &resp); err != nil {
+		return fmt.Errorf("Rescheduling UpdateBooking: Could not parse HTTP response to pb3: %v", err)
+	}
+
+	log.Printf("UpdateBooking Response. Received(unix): %s, Response %s", time.Now().UTC().Format(time.RFC850), resp.String())
+	if iE := utils.ValidateBooking(resp.GetBooking(), newBooking); iE != nil {
+		return fmt.Errorf("invalid response. UpdateBooking: %s, abandoning slot 1/1", iE.Error())
+	}
+	return CancelBooking(resp.GetBooking(), conn)
+}
diff --git a/feeds/availability_feed.pb.go b/feeds/availability_feed.pb.go
new file mode 100644
index 0000000..c41f821
--- /dev/null
+++ b/feeds/availability_feed.pb.go
@@ -0,0 +1,637 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: availability_feed.proto
+
+/*
+Package maps_booking_feeds is a generated protocol buffer package.
+
+It is generated from these files:
+	availability_feed.proto
+
+It has these top-level messages:
+	FeedMetadata
+	AvailabilityFeed
+	ServiceAvailability
+	Availability
+	Resources
+	TimeRange
+*/
+package maps_booking_feeds
+
+import proto "github.com/golang/protobuf/proto"
+import fmt "fmt"
+import math "math"
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
+
+type FeedMetadata_ProcessingInstruction int32
+
+const (
+	// By default we will assume that this feed is an incremental feed.
+	FeedMetadata_PROCESS_UNKNOWN FeedMetadata_ProcessingInstruction = 0
+	// This Feed message is one shard of a complete feed. Anything previously
+	// supplied by this partner will be deleted; the contents of this feed
+	// represent the entire state of the world.
+	FeedMetadata_PROCESS_AS_COMPLETE FeedMetadata_ProcessingInstruction = 1
+	// This Feed message is one shard of an incremental feed. Existing entities
+	// will be left untouched except as modified in this feed.
+	FeedMetadata_PROCESS_AS_INCREMENTAL FeedMetadata_ProcessingInstruction = 2
+)
+
+var FeedMetadata_ProcessingInstruction_name = map[int32]string{
+	0: "PROCESS_UNKNOWN",
+	1: "PROCESS_AS_COMPLETE",
+	2: "PROCESS_AS_INCREMENTAL",
+}
+var FeedMetadata_ProcessingInstruction_value = map[string]int32{
+	"PROCESS_UNKNOWN":        0,
+	"PROCESS_AS_COMPLETE":    1,
+	"PROCESS_AS_INCREMENTAL": 2,
+}
+
+func (x FeedMetadata_ProcessingInstruction) String() string {
+	return proto.EnumName(FeedMetadata_ProcessingInstruction_name, int32(x))
+}
+func (FeedMetadata_ProcessingInstruction) EnumDescriptor() ([]byte, []int) {
+	return fileDescriptor0, []int{0, 0}
+}
+
+type FeedMetadata struct {
+	// Instructs us how to process the feed: either as a shard of a complete feed,
+	// or as a shard of an incremental update.
+	ProcessingInstruction FeedMetadata_ProcessingInstruction `protobuf:"varint,1,opt,name=processing_instruction,json=processingInstruction,enum=maps.booking.feeds.FeedMetadata_ProcessingInstruction" json:"processing_instruction,omitempty"`
+	// The current shard and total number of shards for this feed.
+	//
+	// Shard number is assumed to be zero-based.
+	//
+	// There does not need to be any relationship to the file name.
+	//
+	// Shards do not need to be transferred in order, and they may not be
+	// processed in order.
+	ShardNumber int32 `protobuf:"varint,2,opt,name=shard_number,json=shardNumber" json:"shard_number,omitempty"`
+	TotalShards int32 `protobuf:"varint,3,opt,name=total_shards,json=totalShards" json:"total_shards,omitempty"`
+	// An identifier that must be consistent across all shards in a feed.
+	// This value must be globally unique across each feed type.
+	//
+	// This value ensures that complete feeds spanning multiple shards are
+	// processed together correctly.
+	//
+	// Clients only need to set this value when the processing_instruction is set
+	// to PROCESS_AS_COMPLETE and the feed spans multiple shards (defined by
+	// total_shards).
+	//
+	// Feeds that span multiple shards must set this nonce to the same value.
+	Nonce uint64 `protobuf:"varint,5,opt,name=nonce" json:"nonce,omitempty"`
+	// The timestamp at which this feed shard was generated.
+	//
+	// In Unix time format (seconds since the epoch).
+	GenerationTimestamp int64 `protobuf:"varint,4,opt,name=generation_timestamp,json=generationTimestamp" json:"generation_timestamp,omitempty"`
+}
+
+func (m *FeedMetadata) Reset()                    { *m = FeedMetadata{} }
+func (m *FeedMetadata) String() string            { return proto.CompactTextString(m) }
+func (*FeedMetadata) ProtoMessage()               {}
+func (*FeedMetadata) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
+
+func (m *FeedMetadata) GetProcessingInstruction() FeedMetadata_ProcessingInstruction {
+	if m != nil {
+		return m.ProcessingInstruction
+	}
+	return FeedMetadata_PROCESS_UNKNOWN
+}
+
+func (m *FeedMetadata) GetShardNumber() int32 {
+	if m != nil {
+		return m.ShardNumber
+	}
+	return 0
+}
+
+func (m *FeedMetadata) GetTotalShards() int32 {
+	if m != nil {
+		return m.TotalShards
+	}
+	return 0
+}
+
+func (m *FeedMetadata) GetNonce() uint64 {
+	if m != nil {
+		return m.Nonce
+	}
+	return 0
+}
+
+func (m *FeedMetadata) GetGenerationTimestamp() int64 {
+	if m != nil {
+		return m.GenerationTimestamp
+	}
+	return 0
+}
+
+type AvailabilityFeed struct {
+	Metadata            *FeedMetadata          `protobuf:"bytes,1,opt,name=metadata" json:"metadata,omitempty"`
+	ServiceAvailability []*ServiceAvailability `protobuf:"bytes,2,rep,name=service_availability,json=serviceAvailability" json:"service_availability,omitempty"`
+}
+
+func (m *AvailabilityFeed) Reset()                    { *m = AvailabilityFeed{} }
+func (m *AvailabilityFeed) String() string            { return proto.CompactTextString(m) }
+func (*AvailabilityFeed) ProtoMessage()               {}
+func (*AvailabilityFeed) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
+
+func (m *AvailabilityFeed) GetMetadata() *FeedMetadata {
+	if m != nil {
+		return m.Metadata
+	}
+	return nil
+}
+
+func (m *AvailabilityFeed) GetServiceAvailability() []*ServiceAvailability {
+	if m != nil {
+		return m.ServiceAvailability
+	}
+	return nil
+}
+
+type ServiceAvailability struct {
+	// If provided, we will consider the Availability entities provided to be a
+	// complete snapshot from [start_timestamp_restrict, end_timestamp_restrict).
+	// That is, all existing availability will be deleted if the following
+	// condition holds true:
+	//
+	//    start_timestamp_restrict <= Availability.start_sec &&
+	//    Availability.start_sec < end_timestamp_restrict
+	//
+	// If a resource_restrict message is set, the condition is further restricted:
+	//
+	//    Availability.resource.staff_id == resource_restrict.staff_id &&
+	//    Availability.resource.room_id == resource_restrict.room_id
+	//
+	// These fields are typically used to provide a complete update of
+	// availability in a given time range.
+	//
+	// Setting start_timestamp_restrict while leaving end_timestamp_restrict unset
+	// is interpreted to mean all time beginning at start_timestamp_restrict.
+	//
+	// Setting end_timestamp_restrict while leaving start_timestamp_restrict unset
+	// is interpreted to mean all time up to the end_timestamp_restrict.
+	//
+	// In Unix time format (seconds since the epoch).
+	StartTimestampRestrict int64 `protobuf:"varint,1,opt,name=start_timestamp_restrict,json=startTimestampRestrict" json:"start_timestamp_restrict,omitempty"`
+	EndTimestampRestrict   int64 `protobuf:"varint,2,opt,name=end_timestamp_restrict,json=endTimestampRestrict" json:"end_timestamp_restrict,omitempty"`
+	// If provided, the timestamp restricts will be applied only to the given
+	// merchant or service.
+	//
+	// These fields are typically used to provide complete snapshot of
+	// availability in a given range (defined above) for a specific merchant or
+	// service.
+	//
+	// Leaving these fields unset, or setting these to the empty string or null,
+	// is interpreted to mean that no restrict is intended.
+	MerchantIdRestrict string `protobuf:"bytes,3,opt,name=merchant_id_restrict,json=merchantIdRestrict" json:"merchant_id_restrict,omitempty"`
+	ServiceIdRestrict  string `protobuf:"bytes,4,opt,name=service_id_restrict,json=serviceIdRestrict" json:"service_id_restrict,omitempty"`
+	// Setting resources_restrict further restricts the scope of the update to
+	// just this set of resources. All id fields of the resources must match
+	// exactly.
+	ResourcesRestrict *Resources      `protobuf:"bytes,6,opt,name=resources_restrict,json=resourcesRestrict" json:"resources_restrict,omitempty"`
+	Availability      []*Availability `protobuf:"bytes,5,rep,name=availability" json:"availability,omitempty"`
+}
+
+func (m *ServiceAvailability) Reset()                    { *m = ServiceAvailability{} }
+func (m *ServiceAvailability) String() string            { return proto.CompactTextString(m) }
+func (*ServiceAvailability) ProtoMessage()               {}
+func (*ServiceAvailability) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
+
+func (m *ServiceAvailability) GetStartTimestampRestrict() int64 {
+	if m != nil {
+		return m.StartTimestampRestrict
+	}
+	return 0
+}
+
+func (m *ServiceAvailability) GetEndTimestampRestrict() int64 {
+	if m != nil {
+		return m.EndTimestampRestrict
+	}
+	return 0
+}
+
+func (m *ServiceAvailability) GetMerchantIdRestrict() string {
+	if m != nil {
+		return m.MerchantIdRestrict
+	}
+	return ""
+}
+
+func (m *ServiceAvailability) GetServiceIdRestrict() string {
+	if m != nil {
+		return m.ServiceIdRestrict
+	}
+	return ""
+}
+
+func (m *ServiceAvailability) GetResourcesRestrict() *Resources {
+	if m != nil {
+		return m.ResourcesRestrict
+	}
+	return nil
+}
+
+func (m *ServiceAvailability) GetAvailability() []*Availability {
+	if m != nil {
+		return m.Availability
+	}
+	return nil
+}
+
+// An availability of the merchant's service, indicating time and number
+// of spots.
+// The availability feed should be a list of this message.
+// Please note that it's up to the partner to call out all the possible
+// availabilities.
+// If a massage therapist is available 9am-12pm, and they provide
+// one-hour massage sessions, the aggregator should provide the feed as
+//   availability {start_sec: 9am, duration: 60 minutes, ...}
+//   availability {start_sec: 10am, duration: 60 minutes, ...}
+//   availability {start_sec: 11am, duration: 60 minutes, ...}
+// instead of
+//   availability {start_sec: 9am, duration: 180 minutes, ...}
+//
+type Availability struct {
+	// An opaque string from an aggregator to identify a merchant.
+	MerchantId string `protobuf:"bytes,1,opt,name=merchant_id,json=merchantId" json:"merchant_id,omitempty"`
+	// An opaque string from aggregator to identify a service of the
+	// merchant.
+	ServiceId string `protobuf:"bytes,2,opt,name=service_id,json=serviceId" json:"service_id,omitempty"`
+	// Start time of this availability, using epoch time in seconds.
+	StartSec int64 `protobuf:"varint,3,opt,name=start_sec,json=startSec" json:"start_sec,omitempty"`
+	// Duration of the service in seconds, e.g. 30 minutes for a chair massage.
+	DurationSec int64 `protobuf:"varint,4,opt,name=duration_sec,json=durationSec" json:"duration_sec,omitempty"`
+	// Number of total spots and open spots of this availability.
+	// E.g. a Yoga class of 10 spots with 3 booked.
+	//   availability {spots_total: 10, spots_open: 7 ...}
+	// E.g. a chair massage session which was already booked.
+	//   availability {spots_total: 1, spots_open: 0 ...}
+	//
+	// Note: If sending requests using the availability compression format defined
+	//       below, these two fields will be inferred. A Recurrence
+	//       implies spots_total=1 and spots_open=1. A ScheduleException implies
+	//       spots_total=1 and spots_open=0.
+	SpotsTotal int64 `protobuf:"varint,5,opt,name=spots_total,json=spotsTotal" json:"spots_total,omitempty"`
+	SpotsOpen  int64 `protobuf:"varint,6,opt,name=spots_open,json=spotsOpen" json:"spots_open,omitempty"`
+	// An optional opaque string to identify this availability slot. If set, it
+	// will be included in the requests that book/update/cancel appointments.
+	AvailabilityTag string `protobuf:"bytes,7,opt,name=availability_tag,json=availabilityTag" json:"availability_tag,omitempty"`
+	// Optional resources used to disambiguate this availability slot from
+	// others when different staff, room, or party_size values are part
+	// of the service.
+	//
+	// E.g. the same Yoga class with two 2 instructors.
+	//  availability { resources { staff_id: "1" staff_name: "Amy" }
+	//                 spots_total: 10 spots_open: 7 }
+	//  availability { resources { staff_id: "2" staff_name: "John" }
+	//                 spots_total: 5 spots_open: 2 }
+	Resources *Resources `protobuf:"bytes,8,opt,name=resources" json:"resources,omitempty"`
+	// A list of ids referencing the payment options which can be used to pay
+	// for this slot. The actual payment options are defined at the Merchant
+	// level, and can also be shared among multiple Merchants.
+	//
+	// This field overrides any payment_option_ids specified in the service
+	// message. Similarly payment_option_ids specified here do NOT have to be
+	// present in the service message, though must be defined at the
+	// Merchant level.
+	PaymentOptionId []string `protobuf:"bytes,9,rep,name=payment_option_id,json=paymentOptionId" json:"payment_option_id,omitempty"`
+	// The recurrence information for the availability, representing more than one
+	// start time. A recurrence should contain appointments for one working day.
+	Recurrence *Availability_Recurrence `protobuf:"bytes,10,opt,name=recurrence" json:"recurrence,omitempty"`
+	// When this service cannot be scheduled. To limit the number of
+	// schedule_exception messages consider joining adjacent exceptions.
+	ScheduleException []*Availability_ScheduleException `protobuf:"bytes,11,rep,name=schedule_exception,json=scheduleException" json:"schedule_exception,omitempty"`
+}
+
+func (m *Availability) Reset()                    { *m = Availability{} }
+func (m *Availability) String() string            { return proto.CompactTextString(m) }
+func (*Availability) ProtoMessage()               {}
+func (*Availability) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
+
+func (m *Availability) GetMerchantId() string {
+	if m != nil {
+		return m.MerchantId
+	}
+	return ""
+}
+
+func (m *Availability) GetServiceId() string {
+	if m != nil {
+		return m.ServiceId
+	}
+	return ""
+}
+
+func (m *Availability) GetStartSec() int64 {
+	if m != nil {
+		return m.StartSec
+	}
+	return 0
+}
+
+func (m *Availability) GetDurationSec() int64 {
+	if m != nil {
+		return m.DurationSec
+	}
+	return 0
+}
+
+func (m *Availability) GetSpotsTotal() int64 {
+	if m != nil {
+		return m.SpotsTotal
+	}
+	return 0
+}
+
+func (m *Availability) GetSpotsOpen() int64 {
+	if m != nil {
+		return m.SpotsOpen
+	}
+	return 0
+}
+
+func (m *Availability) GetAvailabilityTag() string {
+	if m != nil {
+		return m.AvailabilityTag
+	}
+	return ""
+}
+
+func (m *Availability) GetResources() *Resources {
+	if m != nil {
+		return m.Resources
+	}
+	return nil
+}
+
+func (m *Availability) GetPaymentOptionId() []string {
+	if m != nil {
+		return m.PaymentOptionId
+	}
+	return nil
+}
+
+func (m *Availability) GetRecurrence() *Availability_Recurrence {
+	if m != nil {
+		return m.Recurrence
+	}
+	return nil
+}
+
+func (m *Availability) GetScheduleException() []*Availability_ScheduleException {
+	if m != nil {
+		return m.ScheduleException
+	}
+	return nil
+}
+
+// Recurrence messages are optional, but allow for a more compact
+// representation of consistently repeating availability slots. They typically
+// represent a day's working schedule.
+// ScheduleException messages are then used to represent booked/unavailable
+// time ranges within the work day.
+//
+// Requirements:
+//   1. The expansion of availability slots or recurrences must NOT create
+//      identical slots. If the ids, start_sec, duration_sec, and resources
+//      match, slots are considered identical.
+//   2. Do NOT mix the standard availability format and recurrence within the
+//      slots of a single service. Recurrence benefits merchants/services that
+//      offer appointments. The standard format is geared towards
+//      merchants/services with regularly scheduled classes.
+type Availability_Recurrence struct {
+	// The inclusive maximum UTC timestamp the availability repeats until.
+	RepeatUntilSec int64 `protobuf:"varint,1,opt,name=repeat_until_sec,json=repeatUntilSec" json:"repeat_until_sec,omitempty"`
+	// Defines the time between successive availability slots.
+	//
+	// E.g. An availability with a duration of 20 min, a repeat_every_sec of
+	// 30 min, a start_sec of 9:00am, and a repeat_until_sec of 11:00am will
+	// yield slots at 9-9:20am, 9:30-9:50am, 10-10:20am, 10:30-10:50am,
+	// 11-11:20am.
+	RepeatEverySec int32 `protobuf:"varint,2,opt,name=repeat_every_sec,json=repeatEverySec" json:"repeat_every_sec,omitempty"`
+}
+
+func (m *Availability_Recurrence) Reset()                    { *m = Availability_Recurrence{} }
+func (m *Availability_Recurrence) String() string            { return proto.CompactTextString(m) }
+func (*Availability_Recurrence) ProtoMessage()               {}
+func (*Availability_Recurrence) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3, 0} }
+
+func (m *Availability_Recurrence) GetRepeatUntilSec() int64 {
+	if m != nil {
+		return m.RepeatUntilSec
+	}
+	return 0
+}
+
+func (m *Availability_Recurrence) GetRepeatEverySec() int32 {
+	if m != nil {
+		return m.RepeatEverySec
+	}
+	return 0
+}
+
+// ScheduleException messages are used to represent booked/unavailable time
+// ranges within the work day. As time slots are booked, the list of
+// exceptions should grow to reflect the newly unavailable time ranges.
+// The recurrence itself shouldn't be modified.
+type Availability_ScheduleException struct {
+	// The time range of the exception.
+	TimeRange *TimeRange `protobuf:"bytes,1,opt,name=time_range,json=timeRange" json:"time_range,omitempty"`
+}
+
+func (m *Availability_ScheduleException) Reset()         { *m = Availability_ScheduleException{} }
+func (m *Availability_ScheduleException) String() string { return proto.CompactTextString(m) }
+func (*Availability_ScheduleException) ProtoMessage()    {}
+func (*Availability_ScheduleException) Descriptor() ([]byte, []int) {
+	return fileDescriptor0, []int{3, 1}
+}
+
+func (m *Availability_ScheduleException) GetTimeRange() *TimeRange {
+	if m != nil {
+		return m.TimeRange
+	}
+	return nil
+}
+
+// A resource is used to disambiguate availability slots from one another when
+// different staff, room or party_size values are part of the service.
+// Multiple slots for the same service and time interval can co-exist when they
+// have different resources.
+type Resources struct {
+	// Optional id for a staff member providing the service. This field identifies
+	// the staff member across all merchants, services, and availability records.
+	// It also needs to be stable over time to allow correlation with past
+	// bookings.
+	// This field must be present if staff_name is present.
+	StaffId string `protobuf:"bytes,1,opt,name=staff_id,json=staffId" json:"staff_id,omitempty"`
+	// Optional name of a staff member providing the service. This field will be
+	// displayed to users making a booking, and should be human readable, as
+	// opposed to an opaque identifier.
+	// This field must be present if staff_id is present.
+	StaffName string `protobuf:"bytes,2,opt,name=staff_name,json=staffName" json:"staff_name,omitempty"`
+	// An optional id for the room the service is located in. This field
+	// identifies the room across all merchants, services, and availability
+	// records. It also needs to be stable over time to allow correlation with
+	// past bookings.
+	// This field must be present if room_name is present.
+	RoomId string `protobuf:"bytes,3,opt,name=room_id,json=roomId" json:"room_id,omitempty"`
+	// An optional name for the room the service is located in. This
+	// field will be displayed to users making a booking, and should be human
+	// readable, as opposed to an opaque identifier.
+	// This field must be present if room_id is present.
+	RoomName string `protobuf:"bytes,4,opt,name=room_name,json=roomName" json:"room_name,omitempty"`
+	// Applicable only for Dining: The party size which can be accommodated
+	// during this time slot. A restaurant can be associated with multiple Slots
+	// for the same time, each specifying a different party_size, if for instance
+	// 2, 3, or 4 people can be seated with a reservation.
+	PartySize int32 `protobuf:"varint,5,opt,name=party_size,json=partySize" json:"party_size,omitempty"`
+}
+
+func (m *Resources) Reset()                    { *m = Resources{} }
+func (m *Resources) String() string            { return proto.CompactTextString(m) }
+func (*Resources) ProtoMessage()               {}
+func (*Resources) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
+
+func (m *Resources) GetStaffId() string {
+	if m != nil {
+		return m.StaffId
+	}
+	return ""
+}
+
+func (m *Resources) GetStaffName() string {
+	if m != nil {
+		return m.StaffName
+	}
+	return ""
+}
+
+func (m *Resources) GetRoomId() string {
+	if m != nil {
+		return m.RoomId
+	}
+	return ""
+}
+
+func (m *Resources) GetRoomName() string {
+	if m != nil {
+		return m.RoomName
+	}
+	return ""
+}
+
+func (m *Resources) GetPartySize() int32 {
+	if m != nil {
+		return m.PartySize
+	}
+	return 0
+}
+
+type TimeRange struct {
+	BeginSec int64 `protobuf:"varint,1,opt,name=begin_sec,json=beginSec" json:"begin_sec,omitempty"`
+	EndSec   int64 `protobuf:"varint,2,opt,name=end_sec,json=endSec" json:"end_sec,omitempty"`
+}
+
+func (m *TimeRange) Reset()                    { *m = TimeRange{} }
+func (m *TimeRange) String() string            { return proto.CompactTextString(m) }
+func (*TimeRange) ProtoMessage()               {}
+func (*TimeRange) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
+
+func (m *TimeRange) GetBeginSec() int64 {
+	if m != nil {
+		return m.BeginSec
+	}
+	return 0
+}
+
+func (m *TimeRange) GetEndSec() int64 {
+	if m != nil {
+		return m.EndSec
+	}
+	return 0
+}
+
+func init() {
+	proto.RegisterType((*FeedMetadata)(nil), "maps.booking.feeds.FeedMetadata")
+	proto.RegisterType((*AvailabilityFeed)(nil), "maps.booking.feeds.AvailabilityFeed")
+	proto.RegisterType((*ServiceAvailability)(nil), "maps.booking.feeds.ServiceAvailability")
+	proto.RegisterType((*Availability)(nil), "maps.booking.feeds.Availability")
+	proto.RegisterType((*Availability_Recurrence)(nil), "maps.booking.feeds.Availability.Recurrence")
+	proto.RegisterType((*Availability_ScheduleException)(nil), "maps.booking.feeds.Availability.ScheduleException")
+	proto.RegisterType((*Resources)(nil), "maps.booking.feeds.Resources")
+	proto.RegisterType((*TimeRange)(nil), "maps.booking.feeds.TimeRange")
+	proto.RegisterEnum("maps.booking.feeds.FeedMetadata_ProcessingInstruction", FeedMetadata_ProcessingInstruction_name, FeedMetadata_ProcessingInstruction_value)
+}
+
+func init() { proto.RegisterFile("availability_feed.proto", fileDescriptor0) }
+
+var fileDescriptor0 = []byte{
+	// 859 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x55, 0xdb, 0x6e, 0x23, 0x45,
+	0x10, 0xc5, 0x76, 0x9c, 0x64, 0xca, 0xd1, 0xae, 0xdd, 0xf6, 0x26, 0x43, 0x50, 0xb4, 0xc6, 0x2f,
+	0x18, 0x90, 0x2c, 0x08, 0x08, 0x21, 0xb1, 0x2f, 0x51, 0x30, 0x52, 0xb4, 0x89, 0x1d, 0x7a, 0xbc,
+	0x42, 0xe2, 0x65, 0x68, 0xcf, 0x54, 0x9c, 0x11, 0x9e, 0x9e, 0x51, 0x77, 0x3b, 0x22, 0xfb, 0x29,
+	0x7c, 0x03, 0xff, 0xc1, 0xe7, 0xf0, 0x01, 0xbc, 0xa0, 0xae, 0xb9, 0x9a, 0x58, 0xca, 0xbe, 0x79,
+	0x4e, 0x9d, 0xd3, 0x97, 0x73, 0xaa, 0xda, 0x70, 0x22, 0x1e, 0x44, 0xb4, 0x16, 0xcb, 0x68, 0x1d,
+	0x99, 0x47, 0xff, 0x0e, 0x31, 0x9c, 0xa4, 0x2a, 0x31, 0x09, 0x63, 0xb1, 0x48, 0xf5, 0x64, 0x99,
+	0x24, 0xbf, 0x47, 0x72, 0x35, 0xb1, 0x05, 0x3d, 0xfa, 0xa7, 0x09, 0x47, 0x3f, 0x21, 0x86, 0x37,
+	0x68, 0x44, 0x28, 0x8c, 0x60, 0x31, 0x1c, 0xa7, 0x2a, 0x09, 0x50, 0xeb, 0x48, 0xae, 0xfc, 0x48,
+	0x6a, 0xa3, 0x36, 0x81, 0x89, 0x12, 0xe9, 0x36, 0x86, 0x8d, 0xf1, 0x8b, 0xf3, 0xef, 0x26, 0x4f,
+	0x57, 0x99, 0xd4, 0x57, 0x98, 0xdc, 0x96, 0xf2, 0xab, 0x4a, 0xcd, 0x5f, 0xa5, 0xbb, 0x60, 0xf6,
+	0x29, 0x1c, 0xe9, 0x7b, 0xa1, 0x42, 0x5f, 0x6e, 0xe2, 0x25, 0x2a, 0xb7, 0x39, 0x6c, 0x8c, 0xdb,
+	0xbc, 0x43, 0xd8, 0x8c, 0x20, 0x4b, 0x31, 0x89, 0x11, 0x6b, 0x9f, 0x40, 0xed, 0xb6, 0x32, 0x0a,
+	0x61, 0x1e, 0x41, 0x6c, 0x00, 0x6d, 0x99, 0xc8, 0x00, 0xdd, 0xf6, 0xb0, 0x31, 0xde, 0xe3, 0xd9,
+	0x07, 0xfb, 0x1a, 0x06, 0x2b, 0x94, 0xa8, 0x84, 0xdd, 0xc9, 0x37, 0x51, 0x8c, 0xda, 0x88, 0x38,
+	0x75, 0xf7, 0x86, 0x8d, 0x71, 0x8b, 0xf7, 0xab, 0xda, 0xa2, 0x28, 0x8d, 0x04, 0xbc, 0xda, 0x79,
+	0x7c, 0xd6, 0x87, 0x97, 0xb7, 0x7c, 0x7e, 0x39, 0xf5, 0x3c, 0xff, 0xdd, 0xec, 0xed, 0x6c, 0xfe,
+	0xcb, 0xac, 0xfb, 0x11, 0x3b, 0x81, 0x7e, 0x01, 0x5e, 0x78, 0xfe, 0xe5, 0xfc, 0xe6, 0xf6, 0x7a,
+	0xba, 0x98, 0x76, 0x1b, 0xec, 0x14, 0x8e, 0x6b, 0x85, 0xab, 0xd9, 0x25, 0x9f, 0xde, 0x4c, 0x67,
+	0x8b, 0x8b, 0xeb, 0x6e, 0x73, 0xf4, 0x57, 0x03, 0xba, 0x17, 0xb5, 0x84, 0xac, 0x77, 0xec, 0x0d,
+	0x1c, 0xc6, 0xb9, 0x7f, 0xe4, 0x73, 0xe7, 0x7c, 0xf8, 0x9c, 0xcf, 0xbc, 0x54, 0xb0, 0x5f, 0x61,
+	0xa0, 0x51, 0x3d, 0x44, 0x01, 0xfa, 0xf5, 0xec, 0xdd, 0xe6, 0xb0, 0x35, 0xee, 0x9c, 0x7f, 0xb6,
+	0x6b, 0x25, 0x2f, 0xe3, 0xd7, 0x0f, 0xc2, 0xfb, 0xfa, 0x29, 0x38, 0xfa, 0xb7, 0x09, 0xfd, 0x1d,
+	0x64, 0xf6, 0x3d, 0xb8, 0xda, 0x08, 0x65, 0x2a, 0x5f, 0x7d, 0x85, 0xda, 0xa8, 0x28, 0x30, 0x74,
+	0x83, 0x16, 0x3f, 0xa6, 0x7a, 0xe9, 0x2d, 0xcf, 0xab, 0xec, 0x5b, 0x38, 0x46, 0x19, 0xee, 0xd2,
+	0x35, 0x49, 0x37, 0x40, 0x19, 0x3e, 0x55, 0x7d, 0x05, 0x83, 0x18, 0x55, 0x70, 0x2f, 0xa4, 0xf1,
+	0xa3, 0xb0, 0xd2, 0xd8, 0x6e, 0x70, 0x38, 0x2b, 0x6a, 0x57, 0x61, 0xa9, 0x98, 0x40, 0x71, 0xa1,
+	0x2d, 0xc1, 0x1e, 0x09, 0x7a, 0x79, 0xa9, 0xc6, 0xbf, 0x06, 0xa6, 0x50, 0x27, 0x1b, 0x15, 0xa0,
+	0xae, 0xe8, 0xfb, 0x94, 0xc6, 0xd9, 0x2e, 0x0f, 0x79, 0xc1, 0xe6, 0xbd, 0x52, 0x58, 0xae, 0xf6,
+	0x23, 0x1c, 0x6d, 0x65, 0xd1, 0xa6, 0x2c, 0x76, 0xa6, 0xba, 0x15, 0xc2, 0x96, 0x6a, 0xf4, 0x77,
+	0x1b, 0x8e, 0xb6, 0x6c, 0x7f, 0x0d, 0x9d, 0x9a, 0x0d, 0xe4, 0xb4, 0xc3, 0xa1, 0xba, 0x3d, 0x3b,
+	0x03, 0xa8, 0x6e, 0x4d, 0x8e, 0x3a, 0xdc, 0x29, 0x2f, 0xcb, 0x3e, 0x01, 0x27, 0x8b, 0x4d, 0x63,
+	0x40, 0xde, 0xb5, 0xf8, 0x21, 0x01, 0x1e, 0x06, 0x76, 0xd2, 0xc2, 0x4d, 0x3e, 0x2e, 0xb6, 0x9e,
+	0x0d, 0x4a, 0xa7, 0xc0, 0x2c, 0xe5, 0x35, 0x74, 0x74, 0x9a, 0x18, 0xed, 0xd3, 0xf8, 0xd1, 0xbc,
+	0xb5, 0x38, 0x10, 0xb4, 0xb0, 0x08, 0xed, 0x4f, 0x84, 0x24, 0x45, 0x49, 0xee, 0xb5, 0xb8, 0x43,
+	0xc8, 0x3c, 0x45, 0xc9, 0x3e, 0x87, 0xee, 0xd6, 0xf3, 0x64, 0xc4, 0xca, 0x3d, 0xa0, 0x43, 0xbe,
+	0xac, 0xe3, 0x0b, 0xb1, 0x62, 0x3f, 0x80, 0x53, 0xda, 0xea, 0x1e, 0x7e, 0x48, 0x0c, 0x15, 0x9f,
+	0x7d, 0x01, 0xbd, 0x54, 0x3c, 0xc6, 0x28, 0x8d, 0x9f, 0xa4, 0x74, 0xa1, 0x28, 0x74, 0x9d, 0x61,
+	0xcb, 0x6e, 0x94, 0x17, 0xe6, 0x84, 0x5f, 0x85, 0xec, 0x2d, 0x80, 0xc2, 0x60, 0xa3, 0x14, 0xda,
+	0x27, 0x04, 0x68, 0xa7, 0x2f, 0x9f, 0x0b, 0x6a, 0xc2, 0x4b, 0x09, 0xaf, 0xc9, 0x99, 0x00, 0xa6,
+	0x83, 0x7b, 0x0c, 0x37, 0x6b, 0xf4, 0xf1, 0x8f, 0x00, 0x69, 0x13, 0xb7, 0x43, 0xe9, 0x9f, 0x3f,
+	0xbb, 0xa8, 0x97, 0x4b, 0xa7, 0x85, 0x92, 0xf7, 0xf4, 0xff, 0xa1, 0xd3, 0xdf, 0x00, 0xaa, 0xcd,
+	0xd9, 0x18, 0xba, 0x0a, 0x53, 0x14, 0xc6, 0xdf, 0x48, 0x13, 0xad, 0x29, 0xb8, 0x6c, 0x00, 0x5f,
+	0x64, 0xf8, 0x3b, 0x0b, 0xdb, 0xec, 0x2a, 0x26, 0x3e, 0xa0, 0x7a, 0x24, 0x66, 0xf6, 0xde, 0xe6,
+	0xcc, 0xa9, 0x85, 0x3d, 0x0c, 0x4e, 0x7f, 0x86, 0xde, 0x93, 0x93, 0xb0, 0x37, 0x00, 0x76, 0x66,
+	0x7d, 0x25, 0xe4, 0x0a, 0xf3, 0x57, 0x6a, 0x67, 0x20, 0x76, 0x78, 0xb9, 0x25, 0x71, 0xc7, 0x14,
+	0x3f, 0x47, 0x7f, 0x36, 0xc0, 0x29, 0x93, 0x62, 0x1f, 0x83, 0xed, 0xba, 0xbb, 0xbb, 0xaa, 0x87,
+	0x0f, 0xe8, 0x3b, 0x6f, 0x60, 0x2a, 0x49, 0x11, 0x63, 0xd9, 0xc0, 0x16, 0x99, 0x89, 0x18, 0xd9,
+	0x09, 0x1c, 0xa8, 0x24, 0x89, 0xad, 0x30, 0x1b, 0xfd, 0x7d, 0xfb, 0x99, 0x75, 0x36, 0x15, 0x48,
+	0x96, 0x0d, 0xf9, 0xa1, 0x05, 0x48, 0x75, 0x06, 0x90, 0x0a, 0x65, 0x1e, 0x7d, 0x1d, 0xbd, 0xcf,
+	0xfe, 0x25, 0xda, 0xdc, 0x21, 0xc4, 0x8b, 0xde, 0xe3, 0xe8, 0x02, 0x9c, 0xf2, 0xd0, 0x76, 0xa1,
+	0x25, 0xae, 0x22, 0x59, 0x73, 0xf2, 0x90, 0x00, 0xeb, 0xe1, 0x09, 0x1c, 0xd8, 0xc7, 0xab, 0xb0,
+	0xae, 0xc5, 0xf7, 0x51, 0x86, 0x1e, 0x06, 0xcb, 0x7d, 0xfa, 0x8f, 0xfd, 0xe6, 0xbf, 0x00, 0x00,
+	0x00, 0xff, 0xff, 0x08, 0xf3, 0x9e, 0x1d, 0x7e, 0x07, 0x00, 0x00,
+}
diff --git a/feeds/availability_feed.proto b/feeds/availability_feed.proto
new file mode 100644
index 0000000..e25bd0e
--- /dev/null
+++ b/feeds/availability_feed.proto
@@ -0,0 +1,249 @@
+syntax = "proto3";
+
+package maps.booking.feeds;
+
+message FeedMetadata {
+  enum ProcessingInstruction {
+    // By default we will assume that this feed is an incremental feed.
+    PROCESS_UNKNOWN = 0;
+
+    // This Feed message is one shard of a complete feed. Anything previously
+    // supplied by this partner will be deleted; the contents of this feed
+    // represent the entire state of the world.
+    PROCESS_AS_COMPLETE = 1;
+
+    // This Feed message is one shard of an incremental feed. Existing entities
+    // will be left untouched except as modified in this feed.
+    PROCESS_AS_INCREMENTAL = 2;
+  }
+
+  // Instructs us how to process the feed: either as a shard of a complete feed,
+  // or as a shard of an incremental update.
+  ProcessingInstruction processing_instruction = 1;
+
+  // The current shard and total number of shards for this feed.
+  //
+  // Shard number is assumed to be zero-based.
+  //
+  // There does not need to be any relationship to the file name.
+  //
+  // Shards do not need to be transferred in order, and they may not be
+  // processed in order.
+  int32 shard_number = 2;
+  int32 total_shards = 3;
+
+  // An identifier that must be consistent across all shards in a feed.
+  // This value must be globally unique across each feed type.
+  //
+  // This value ensures that complete feeds spanning multiple shards are
+  // processed together correctly.
+  //
+  // Clients only need to set this value when the processing_instruction is set
+  // to PROCESS_AS_COMPLETE and the feed spans multiple shards (defined by
+  // total_shards).
+  //
+  // Feeds that span multiple shards must set this nonce to the same value.
+  uint64 nonce = 5;
+
+  // The timestamp at which this feed shard was generated.
+  //
+  // In Unix time format (seconds since the epoch).
+  int64 generation_timestamp = 4;
+}
+
+message AvailabilityFeed {
+  FeedMetadata metadata = 1;
+  repeated ServiceAvailability service_availability = 2;
+}
+
+message ServiceAvailability {
+  // If provided, we will consider the Availability entities provided to be a
+  // complete snapshot from [start_timestamp_restrict, end_timestamp_restrict).
+  // That is, all existing availability will be deleted if the following
+  // condition holds true:
+  //
+  //    start_timestamp_restrict <= Availability.start_sec &&
+  //    Availability.start_sec < end_timestamp_restrict
+  //
+  // If a resource_restrict message is set, the condition is further restricted:
+  //
+  //    Availability.resource.staff_id == resource_restrict.staff_id &&
+  //    Availability.resource.room_id == resource_restrict.room_id
+  //
+  // These fields are typically used to provide a complete update of
+  // availability in a given time range.
+  //
+  // Setting start_timestamp_restrict while leaving end_timestamp_restrict unset
+  // is interpreted to mean all time beginning at start_timestamp_restrict.
+  //
+  // Setting end_timestamp_restrict while leaving start_timestamp_restrict unset
+  // is interpreted to mean all time up to the end_timestamp_restrict.
+  //
+  // In Unix time format (seconds since the epoch).
+  int64 start_timestamp_restrict = 1;
+  int64 end_timestamp_restrict = 2;
+
+  // If provided, the timestamp restricts will be applied only to the given
+  // merchant or service.
+  //
+  // These fields are typically used to provide complete snapshot of
+  // availability in a given range (defined above) for a specific merchant or
+  // service.
+  //
+  // Leaving these fields unset, or setting these to the empty string or null,
+  // is interpreted to mean that no restrict is intended.
+  string merchant_id_restrict = 3;
+  string service_id_restrict = 4;
+
+  // Setting resources_restrict further restricts the scope of the update to
+  // just this set of resources. All id fields of the resources must match
+  // exactly.
+  Resources resources_restrict = 6;
+
+  repeated Availability availability = 5;
+}
+
+// An availability of the merchant's service, indicating time and number
+// of spots.
+// The availability feed should be a list of this message.
+// Please note that it's up to the partner to call out all the possible
+// availabilities.
+// If a massage therapist is available 9am-12pm, and they provide
+// one-hour massage sessions, the aggregator should provide the feed as
+//   availability {start_sec: 9am, duration: 60 minutes, ...}
+//   availability {start_sec: 10am, duration: 60 minutes, ...}
+//   availability {start_sec: 11am, duration: 60 minutes, ...}
+// instead of
+//   availability {start_sec: 9am, duration: 180 minutes, ...}
+//
+message Availability {
+  // An opaque string from an aggregator to identify a merchant.
+  string merchant_id = 1;
+  // An opaque string from aggregator to identify a service of the
+  // merchant.
+  string service_id = 2;
+  // Start time of this availability, using epoch time in seconds.
+  int64 start_sec = 3;
+  // Duration of the service in seconds, e.g. 30 minutes for a chair massage.
+  int64 duration_sec = 4;
+  // Number of total spots and open spots of this availability.
+  // E.g. a Yoga class of 10 spots with 3 booked.
+  //   availability {spots_total: 10, spots_open: 7 ...}
+  // E.g. a chair massage session which was already booked.
+  //   availability {spots_total: 1, spots_open: 0 ...}
+  //
+  // Note: If sending requests using the availability compression format defined
+  //       below, these two fields will be inferred. A Recurrence
+  //       implies spots_total=1 and spots_open=1. A ScheduleException implies
+  //       spots_total=1 and spots_open=0.
+  int64 spots_total = 5;
+  int64 spots_open = 6;
+  // An optional opaque string to identify this availability slot. If set, it
+  // will be included in the requests that book/update/cancel appointments.
+  string availability_tag = 7;
+
+  // Optional resources used to disambiguate this availability slot from
+  // others when different staff, room, or party_size values are part
+  // of the service.
+  //
+  // E.g. the same Yoga class with two 2 instructors.
+  //  availability { resources { staff_id: "1" staff_name: "Amy" }
+  //                 spots_total: 10 spots_open: 7 }
+  //  availability { resources { staff_id: "2" staff_name: "John" }
+  //                 spots_total: 5 spots_open: 2 }
+  Resources resources = 8;
+
+  // A list of ids referencing the payment options which can be used to pay
+  // for this slot. The actual payment options are defined at the Merchant
+  // level, and can also be shared among multiple Merchants.
+  //
+  // This field overrides any payment_option_ids specified in the service
+  // message. Similarly payment_option_ids specified here do NOT have to be
+  // present in the service message, though must be defined at the
+  // Merchant level.
+  repeated string payment_option_id = 9;
+
+  // Recurrence messages are optional, but allow for a more compact
+  // representation of consistently repeating availability slots. They typically
+  // represent a day's working schedule.
+  // ScheduleException messages are then used to represent booked/unavailable
+  // time ranges within the work day.
+  //
+  // Requirements:
+  //   1. The expansion of availability slots or recurrences must NOT create
+  //      identical slots. If the ids, start_sec, duration_sec, and resources
+  //      match, slots are considered identical.
+  //   2. Do NOT mix the standard availability format and recurrence within the
+  //      slots of a single service. Recurrence benefits merchants/services that
+  //      offer appointments. The standard format is geared towards
+  //      merchants/services with regularly scheduled classes.
+  message Recurrence {
+    // The inclusive maximum UTC timestamp the availability repeats until.
+    int64 repeat_until_sec = 1;
+    // Defines the time between successive availability slots.
+    //
+    // E.g. An availability with a duration of 20 min, a repeat_every_sec of
+    // 30 min, a start_sec of 9:00am, and a repeat_until_sec of 11:00am will
+    // yield slots at 9-9:20am, 9:30-9:50am, 10-10:20am, 10:30-10:50am,
+    // 11-11:20am.
+    int32 repeat_every_sec = 2;
+  }
+  // The recurrence information for the availability, representing more than one
+  // start time. A recurrence should contain appointments for one working day.
+  Recurrence recurrence = 10;
+
+  // ScheduleException messages are used to represent booked/unavailable time
+  // ranges within the work day. As time slots are booked, the list of
+  // exceptions should grow to reflect the newly unavailable time ranges.
+  // The recurrence itself shouldn't be modified.
+  message ScheduleException {
+    // The time range of the exception.
+    TimeRange time_range = 1;
+  }
+  // When this service cannot be scheduled. To limit the number of
+  // schedule_exception messages consider joining adjacent exceptions.
+  repeated ScheduleException schedule_exception = 11;
+}
+
+// A resource is used to disambiguate availability slots from one another when
+// different staff, room or party_size values are part of the service.
+// Multiple slots for the same service and time interval can co-exist when they
+// have different resources.
+message Resources {
+  // Optional id for a staff member providing the service. This field identifies
+  // the staff member across all merchants, services, and availability records.
+  // It also needs to be stable over time to allow correlation with past
+  // bookings.
+  // This field must be present if staff_name is present.
+  string staff_id = 1;
+
+  // Optional name of a staff member providing the service. This field will be
+  // displayed to users making a booking, and should be human readable, as
+  // opposed to an opaque identifier.
+  // This field must be present if staff_id is present.
+  string staff_name = 2;
+
+  // An optional id for the room the service is located in. This field
+  // identifies the room across all merchants, services, and availability
+  // records. It also needs to be stable over time to allow correlation with
+  // past bookings.
+  // This field must be present if room_name is present.
+  string room_id = 3;
+
+  // An optional name for the room the service is located in. This
+  // field will be displayed to users making a booking, and should be human
+  // readable, as opposed to an opaque identifier.
+  // This field must be present if room_id is present.
+  string room_name = 4;
+
+  // Applicable only for Dining: The party size which can be accommodated
+  // during this time slot. A restaurant can be associated with multiple Slots
+  // for the same time, each specifying a different party_size, if for instance
+  // 2, 3, or 4 people can be seated with a reservation.
+  int32 party_size = 5;
+}
+
+message TimeRange {
+  int64 begin_sec = 1;
+  int64 end_sec = 2;
+}
\ No newline at end of file
diff --git a/proto/v3.proto b/proto/v3.proto
new file mode 100644
index 0000000..1c217bb
--- /dev/null
+++ b/proto/v3.proto
@@ -0,0 +1,1085 @@
+syntax = "proto3";
+
+package v3;
+
+// [START postaladdr_definition]
+// The postal address for a merchant.
+message PostalAddress {
+  // The country, e.g. "USA". (required)
+  string country = 1;
+  // The locality/city, e.g. "Mountain View". (required)
+  string locality = 2;
+  // The region/state/province, e.g. "CA". (required)
+  string region = 3;
+  // The postal code, e.g. "94043". (required)
+  string postal_code = 4;
+  // The street address, e.g. "1600 Amphitheatre Pkwy". (required)
+  string street_address = 5;
+}
+// [END postaladdr_definition]
+
+// [START geocoord_definition]
+// The Geo data of a location, including latitude, longitude, and address.
+message GeoCoordinates {
+  double latitude = 1;        // In degrees. (optional)
+  double longitude = 2;       // In degrees. (optional)
+  PostalAddress address = 3;  // (required)
+}
+// [END geocoord_definition]
+
+// [START price_definition]
+// The price of a service or a fee.
+message Price {
+  // The price in micro-units of the currency.
+  // Fractions of smallest currency unit will be rounded using nearest even
+  // rounding. (e.g. For USD 2.5 cents rounded to 2 cents, 3.5 cents rounded to
+  // 4 cents, 0.5 cents rounded to 0 cents, 2.51 cents rounded to 3 cents).
+  // (required)
+  int64 price_micros = 1;
+  // The currency of the price that is defined in ISO 4217. (required)
+  string currency_code = 2;
+  // An optional and opaque string that identifies the pricing option that is
+  // associated with the extended price. (optional)
+  string pricing_option_tag = 3;
+}
+// [END price_definition]
+
+// [START taxrate_definition]
+// A tax rate applied when charging the user for a service, and which can be set
+// on either a per merchant, or per service basis.
+message TaxRate {
+  // A tax rate in millionths of one percent, effectively giving 6 decimals of
+  // precision. For example, if the tax rate is 7.253%, this field should be set
+  // to 7253000.
+  //
+  // If this field is left unset or set to 0, the total price charged to a user
+  // for any service provided by this merchant is the exact price specified by
+  // Service.price. The service price is assumed to be exempt from or already
+  // inclusive of applicable taxes. Taxes will not be shown to the user as a
+  // separate line item.
+  //
+  // If this field is set to any nonzero value, the total price charged to a
+  // user for any service provided by this merchant will include the service
+  // price plus the tax assessed using the tax rate provided here. Fractions of
+  // the smallest currency unit (for example, fractions of one cent) will be
+  // rounded using nearest even rounding. Taxes will be shown to the user as a
+  // separate line item. (required)
+  int32 micro_percent = 1;
+}
+// [END taxrate_definition]
+
+// [START schedulingrules_definition]
+// The scheduling rules for a service.
+message SchedulingRules {
+  // The minimum advance notice in seconds required to book an appointment.
+  // (optional)
+  int64 min_advance_booking = 1;
+
+  // The minimum advance notice in seconds required to cancel a booked
+  // appointment online. (optional)
+  int64 min_advance_online_canceling = 2;
+
+  // The fee for canceling within the minimum advance notice period.
+  Price late_cancellation_fee = 3 [deprecated = true];
+
+  // The fee for no-show without canceling.
+  Price noshow_fee = 4 [deprecated = true];
+}
+// [END schedulingrules_definition]
+
+// This defines the ingestion source type.
+enum IngestionSource {
+  SOURCE_UNKNOWN = 0;
+
+  // This ingestion is from an uploaded feed file.
+  SOURCE_FEED = 1;
+
+  // This ingestion is from an API call.
+  SOURCE_API = 2;
+}
+
+// An empty boilplate proto for the Ingestion Queue in Spanner.
+message IngestionQueuePayload {
+}
+
+// The types of content that we can ingest through feeds or APIs.
+enum ContentType {
+  CONTENT_UNKNOWN = 0;
+  CONTENT_MERCHANT = 1;
+  CONTENT_SERVICE = 2;
+  CONTENT_AVAILABILITY = 3;
+  CONTENT_PAYMENT_OPTION = 4;
+  CONTENT_PAYMENT_OPTION_SERVICE = 5;
+}
+
+message IngestionStatus {
+  // The status code of an Ingestion event: a feed upload or an API call.
+  // Only used for logging the ingestion status in the IngestionMetadata
+  // table, do NOT use it in the code's control flow.
+  enum Code {
+    // An unknown status for Ingestion, shouldn't use it.
+    STATUS_UNKNOWN = 0;
+
+    // 1-99 for Feed upload.
+    // A feed has been uploaded.
+    STATUS_FEED_UPLOADED = 1;
+    // A feed has been added to the Ingestion Queue.
+    STATUS_FEED_ENQUEUED = 2;
+    // A feed has been picked up from the queue and started processing.
+    STATUS_FEED_PROCESSING_STARTED = 3;
+    // A feed has been processed successfully.
+    STATUS_FEED_PROCESSING_SUCCEEDED = 4;
+    // A feed has failed the processing.
+    STATUS_FEED_PROCESSING_FAILED = 5;
+    // A feed duplicate was uploaded.
+    STATUS_FEED_DUPLICATED = 6;
+
+    // 101-199 for API.
+    // An API has been called.
+    STATUS_API_CALLED = 101;
+    // An API has been processed successfully.
+    STATUS_API_PROCESSING_SUCCEEDED = 102;
+    // An API has failed the processing.
+    STATUS_API_PROCESSING_FAILED = 103;
+  }
+
+  // The code of the status.
+  Code code = 1;
+
+  // Microseconds since epoch when the ingestion updates its status code.
+  int64 timestamp_micros = 2;
+
+  // A human description of the error if any.
+  string internal_error_details = 3;
+  string partner_visible_error_details = 4;
+}
+
+// [START timerange_definition]
+// A closed-open time range, i.e. [begin_sec, end_sec)
+message TimeRange {
+  // Seconds of UTC time since Unix epoch (required)
+  int64 begin_sec = 1;
+  // Seconds of UTC time since Unix epoch (required)
+  int64 end_sec = 2;
+}
+// [END timerange_definition]
+
+// [START pricetype_definition]
+// Defines how a total price is determined from an availability.
+enum PriceType {
+  // The price is for a fixed amount. This is the default value if the field is
+  // not set.
+  FIXED_RATE_DEFAULT = 0;
+  // The price specified is per person, and the total price is calculated
+  // according to the party size specified in Resources as
+  // price_micros * party_size. A PER_PERSON price must be accompanied by a
+  // party size in the availability resources. If it is not, a party size of one
+  // is used.
+  PER_PERSON = 1;
+}
+// [END pricetype_definition]
+
+// [START noshowfee_definition]
+// A fee that a user may be charged if they have made a booking but do not
+// show up.
+message NoShowFee {
+  // The amount the user may be charged if they do not show up for their
+  // reservation.
+  Price fee = 1;
+
+  // Defines how the fee is determined from the availability.
+  PriceType fee_type = 3;
+}
+// [END noshowfee_definition]
+
+// [START deposit_definition]
+// A deposit that the user may be charged or have a hold on their credit card
+// for.
+message Deposit {
+  // Deposit amount.
+  Price deposit = 1;
+
+  // Minimum advance cancellation for the deposit.
+  int64 min_advance_cancellation_sec = 2;
+
+  // Defines how the deposit is determined from the availability.
+  PriceType deposit_type = 3;
+}
+// [END deposit_definition]
+
+// [START RequireCreditCard_definition]
+// Defines whether a credit card is required in order to book an appointment.
+enum RequireCreditCard {
+  // The credit card requirement is not explicitly specified and the
+  // behaviour is identical to the one specified for CONDITIONAL.
+  REQUIRE_CREDIT_CARD_UNSPECIFIED = 0;
+
+  // Google will require a credit card for the booking if any of the following
+  // conditions are met:
+  // * the availability has a price and the prepayment_type is REQUIRED
+  // * the no_show_fee is set
+  // * the deposit field is set.
+  REQUIRE_CREDIT_CARD_CONDITIONAL = 1;
+
+  // A credit card is always required in order to book this availability
+  // regardless of other field values.
+  REQUIRE_CREDIT_CARD_ALWAYS = 2;
+}
+// [END RequireCreditCard_definition]
+
+// [START ActionLink_definition]
+// An action URL with associated language and list of countries restricted to.
+message ActionLink {
+  // The entry point URL for this action link.
+  string url = 1;
+
+  // The BCP-47 language tag identifying the language in which the content
+  // from this URI is available.
+  string language = 2;
+
+  // ISO 3166-1 alpha-2 country code. Leave empty for unrestricted visibility.
+  repeated string restricted_country = 3;
+}
+// [END ActionLink_definition]
+
+// [START message_slot]
+// An inventory slot
+message Slot {
+  // ID of the merchant for the slot (required)
+  string merchant_id = 1;
+
+  // ID of the merchant service (required)
+  string service_id = 2;
+
+  // Start time of the appointment slot in seconds of UTC time since Unix epoch.
+  // (required)
+  int64 start_sec = 3;
+
+  // Duration of the appointment slot (required)
+  int64 duration_sec = 4;
+
+  // Opaque tag that identifies the availability slot and matches the value
+  // provided in the availability feed (optional)
+  string availability_tag = 5;
+
+  // The set of resources that disambiguates the appointment slot, e.g. by
+  // indicating the staff member and room selected by the user (optional)
+  ResourceIds resources = 6;
+}
+// [END message_slot]
+
+// [START message_lease]
+// Temporary lease for an inventory slot
+message Lease {
+  // ID of the lease.
+  // Not populated in CreateLeaseRequest. The value is chosen by the partner and
+  // has to be returned in the response of CreateLease. (required)
+  string lease_id = 1;
+
+  // The appointment slot that the lease is created for. (required)
+  Slot slot = 2;
+
+  // Unique identifier for this lease, chosen by Reserve with Google. Serves as
+  // an idempotency token for CreateLease requests. (required)
+  string user_reference = 3;
+
+  // Expiration time of the lease in UTC Timestamp (required)
+  int64 lease_expiration_time_sec = 4;
+}
+
+// Reference to a Lease that has been created via CreateLease.
+message LeaseReference {
+  // Lease ID (required)
+  string lease_id = 1;
+}
+// [END message_lease]
+
+// [START message_booking]
+// A booking for an inventory slot
+message Booking {
+  // ID of this booking (required)
+  string booking_id = 1;
+
+  // The appointment slot of this booking (required)
+  Slot slot = 2;
+
+  // Personal information of the user making the appointment (required)
+  UserInformation user_information = 3;
+
+  // Status of the booking (required)
+  BookingStatus status = 4;
+
+  // Information about payment transactions that relate to the booking.
+  // (optional)
+  PaymentInformation payment_information = 5;
+}
+// [END message_booking]
+
+// [START user_definition]
+// Personal information about the person making a booking
+message UserInformation {
+  // Unique ID of the user to the partner, chosen by Reserve with Google.
+  // (required)
+  string user_id = 1;
+
+  // Given name of the user (required)
+  string given_name = 2;
+
+  // Family name of the user (required)
+  string family_name = 3;
+
+  // Address of the user (optional)
+  PostalAddress address = 4;
+
+  // Phone number of the user (required)
+  string telephone = 5;
+
+  // Email address of the user (required)
+  string email = 6;
+}
+// [END user_definition]
+
+// [START paymentprocessing_definition]
+message PaymentProcessingParameters {
+  enum PaymentProcessor {
+    PAYMENT_PROCESSOR_UNSPECIFIED = 0;
+    PROCESSOR_STRIPE = 1;
+    PROCESSOR_BRAINTREE = 2;
+  }
+  // The payment processor used to process payment for a given booking.
+  // (required)
+  //
+  // Replaced by the payment_processor field.
+  PaymentProcessor processor = 1 [deprecated = true];
+
+  // The token representing the payment method that will be used to pay
+  // for this booking. This token can be only used once. This token can be
+  // only used for the merchant associated with this booking.
+  //
+  // Each processor may choose its own format for this field.
+  // An example of Stripe's token is "tok_1C3orL2eZvKYlo2CxReMgS4K".
+  //
+  // Replaced by unparsed_payment_method_token, which contains
+  // payment_method_token as one of its fields.
+  // For example, for Stripe, unparsed_payment_method_token is a serialized
+  // JSON object documented at https://stripe.com/docs/api#token_object.
+  // payment_method_token is the 'id' field parsed out of that.
+  string payment_method_token = 2 [deprecated = true];
+
+  // The full token received from Google Payments.  This is typically a
+  // serialized JSON object.  See documentation from Google Payments and your
+  // payment processor for the JSON format of the token for your processor.
+  // https://developers.google.com/pay/api/#participating-google-pay-processors
+  //
+  // This token can only be used once, and only for the merchant associated with
+  // this booking.
+  string unparsed_payment_method_token = 5;
+
+  // The payment processor API version that the given payment token is valid
+  // for.
+  //
+  // Each processor may choose its own format for this field.
+  // Stripe uses a date (e.g. "2017-06-15"). (required)
+  string version = 3;
+
+  // The payment processor whose configuration was used to generate this token.
+  // (required)
+  string payment_processor = 4;
+}
+// [END paymentprocessing_definition]
+
+// [START paymentoption_definition]
+enum PaymentOptionType {
+  PAYMENT_OPTION_TYPE_UNSPECIFIED = 0;
+  PAYMENT_OPTION_SINGLE_USE = 1;
+  PAYMENT_OPTION_MULTI_USE = 2;
+  PAYMENT_OPTION_UNLIMITED_USE = 3;
+}
+// [END paymentoption_definition]
+
+// [START userpaymentoption_definition]
+// This describes a payment option, such as a pack, membership, or
+// single-session pass after it has been purchased by a user. It includes an
+// identifier for the user payment option, as well as some information about
+// the payment option with which it is associated.
+message UserPaymentOption {
+  // A unique identifier for the user payment option. This Id MUST be unique
+  // for all UserPaymentOptions across all merchants and users. (required)
+  string user_payment_option_id = 1;
+  // The user payment option will be valid (usable) between start_time and
+  // end_time set in UTC. Attempts to use a user payment option to make a
+  // booking outside of this interval will fail. (both optional)
+  int64 valid_start_time_sec = 2;
+  int64 valid_end_time_sec = 3;
+  // The type of the payment option associated with this user payment option.
+  // This can be unlimited for a membership or subscription, multi-use for a
+  // pack, or single-use. (required)
+  PaymentOptionType type = 4;
+  // The original number of uses for this user payment option when it was
+  // purchased. This value is ignored for unlimited payment options. (required)
+  int32 original_count = 5;
+  // The number of uses remaining for this user payment option. If this number
+  // is 0 for a pack, attempts to use this payment option to make a booking will
+  // fail. (required)
+  int32 current_count = 6;
+  // The id of the payment option that has been used to purchase this user
+  // payment option. (required)
+  string payment_option_id = 7;
+}
+// [END userpaymentoption_definition]
+
+// [START paymentinfo_definition]
+// Payment details that are sent when creating a new booking.
+message PaymentInformation {
+  // Prepayment status of the booking.
+  // If the prepayment_status is PREPAYMENT_PROVIDED, then
+  // payment_transaction_id contains the associated unique transaction id for
+  // the purchase.
+  // If the prepayment status is PREPAYMENT_REFUNDED, then
+  // payment_transaction_id contains the associated unique transaction id for
+  // the refund. (required)
+  PrepaymentStatus prepayment_status = 1;
+
+  // Unique identifier for a payment transaction associated with the booking.
+  // Empty if not applicable. (required)
+  string payment_transaction_id = 2;
+
+  // These fields must match the service price (specified in the Services feed)
+  // or the PaymentOption corresponding with this service.
+  // They are included in the booking request and response to verify that
+  // the price indicated in the feed has not changed since the last feed
+  // update.
+  //
+  // The price of the booking or order, exclusive of any taxes.
+  // Existence of price or taxes does not imply that they have been paid,
+  // prepayment_state should be used for that purpose. (required)
+  Price price = 3;
+  // Taxes that are calculated to be paid for this booking.
+  // This field can only be absent in one of the following cases:
+  // (1) the price is exempt from or already inclusive of applicable taxes; or
+  // (2) the break down between taxes and fees is not available.
+  // (required when neither of the above holds)
+  Price tax_amount = 4;
+
+  // Who handles payment processing?
+  // If payment is processed by the partner, CreateBooking request will
+  // include additional parameters (PaymentProcessingParameters) indicating
+  // the payment method to be used to process the payment.
+  enum PaymentProcessedBy {
+    PAYMENT_PROCESSED_BY_UNSPECIFIED = 0;
+    PROCESSED_BY_GOOGLE = 1;
+    PROCESSED_BY_PARTNER = 2;
+  }
+  // Whether the partner or Google processed the payment. (required)
+  PaymentProcessedBy payment_processed_by = 5;
+
+  // The id of the payment option or user payment option associated with the
+  // booking.
+  // If a payment option is purchased as part of a booking, payment_option_id
+  // will be set with the id of that payment option.
+  // If an already purchased user payment option is being used to pay for a
+  // booking, user_payment_option_id will be set with the id of that user
+  // payment option.
+  // When included as part of a response proto, the user_payment_option_id
+  // should be set and must match the UserPaymentOption that is returned in the
+  // RPC response (e.g. the user_payment_option returned in
+  // CreateBookingResponse). (one of these required)
+  oneof payment_id {
+    // The id of the payment option associated with this booking. If this field
+    // is populated, price (and tax_amount, if applicable) must be  populated as
+    // well.
+    string payment_option_id = 6;
+
+    // The id of the user payment option used to pay for this booking.
+    string user_payment_option_id = 7;
+  }
+  // Defines how a deposit may be charged to the user. If there is a deposit,
+  // this field should be set. (optional)
+  Deposit deposit = 8;
+  // Defines a no show fee that may be charged to the user. If the user can be
+  // charged a no show fee, this field should be set. (optional)
+  NoShowFee no_show_fee = 9;
+
+  // Total processing fees & taxes that the user needs to pay for the order;
+  // only applicable to partners that handle order based booking (e.g., with
+  // CreateOrder method). (optional)
+  Price fees_and_taxes = 10;
+}
+// [END paymentinfo_definition]
+
+// [START bookingstatus_definition]
+// 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.
+//
+// nextID: 6
+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
+  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;
+}
+// [END bookingstatus_definition]
+
+// [START creditcardtype_definition]
+// Used when booking/order failure cause is PAYMENT_ERROR_CARD_TYPE_REJECTED to
+// indicate the type of credit card that was rejected.
+enum CreditCardType {
+  // Default value. Used if credit card type does not match to one below.
+  CREDIT_CARD_TYPE_UNSPECIFIED = 0;
+  VISA = 1;
+  MASTERCARD = 2;
+  AMERICAN_EXPRESS = 3;
+  DISCOVER = 4;
+}
+// [END creditcardtype_definition]
+
+// [START bookingfailure_definition]
+// Status data that conveys why (1) creating a lease or (2) creating or updating
+// a booking fails.
+// BookingFailure is intended to primarily capture business logic errors.
+message BookingFailure {
+  enum Cause {
+    // Default value: Don't use; amounts to an "unknown error"
+    CAUSE_UNSPECIFIED = 0;
+    // The referenced availability slot is not available any longer.
+    SLOT_UNAVAILABLE = 1;
+    // The user has already booked an appointment for the referenced
+    // availability slot.
+    SLOT_ALREADY_BOOKED_BY_USER = 2;
+    // The lease (if provided) has expired and cannot be used any longer to
+    // complete the requested booking.
+    LEASE_EXPIRED = 3;
+    // The requested cancellation cannot be performed at the current time due
+    // to time restrictions in the merchant's cancellation policy.
+    OUTSIDE_CANCELLATION_WINDOW = 4;
+    // An error was encountered while processing the payment because the
+    // provided credit card type was not accepted by the merchant. The credit
+    // card type must be supplied in rejected_card_type.
+    PAYMENT_ERROR_CARD_TYPE_REJECTED = 5;
+    // An error was encountered while processing the payment because the
+    // provided credit card was declined.
+    PAYMENT_ERROR_CARD_DECLINED = 6;
+    // An error was encountered with the pack/membership used to pay for the
+    // booking. There could be no valid uses left, it could have expired, etc.
+    PAYMENT_OPTION_NOT_VALID = 7;
+    // An error was encountered while processing the payment for this booking.
+    // Use this value to indicate a general payment related error, only if the
+    // error does not match to a specific payment error above.
+    PAYMENT_ERROR = 8;
+    // User cannot use the given payment option (e.g. user trying to use a
+    // first time price for the second time).
+    USER_CANNOT_USE_PAYMENT_OPTION = 9;
+    // A booking that the user tried to cancel has already been cancelled.
+    BOOKING_ALREADY_CANCELLED = 10;
+    // A booking that the user tried to cancel is not cancellable.
+    BOOKING_NOT_CANCELLABLE = 11;
+  }
+  // The reason why the booking failed. (required)
+  Cause cause = 1;
+
+  // (required only if cause is PAYMENT_ERROR_CARD_TYPE_REJECTED)
+  CreditCardType rejected_card_type = 2;
+
+  // This optional field is used for the partner to include additional
+  // information for debugging purpose only. (optional)
+  string description = 3;
+}
+// [END bookingfailure_definition]
+
+// [START prepaymentstatus_definition]
+// Prepayment status of a booking.
+// Updating payment status will trigger an update on the payment status of the
+// associated booking (if applicable).
+// Currently, the only supported transition is from PREPAYMENT_PROVIDED to
+// PREPAYMENT_REFUNDED, which will initiate a non-reversible refund on the
+// associated payment transaction.
+enum PrepaymentStatus {
+  // Not specified, defaults to PREPAYMENT_NOT_PROVIDED.
+  PREPAYMENT_STATUS_UNSPECIFIED = 0;
+  // The fee for the booking has been paid in advance.
+  PREPAYMENT_PROVIDED = 1;
+  // The fee for the booking has not been paid in advance.
+  PREPAYMENT_NOT_PROVIDED = 2;
+  // The fee was previously PREPAYMENT_PROVIDED but has now been refunded.
+  PREPAYMENT_REFUNDED = 3;
+  // The fee was previously PREPAYMENT_PROVIDED but now has been credited
+  // (user given a UserPaymentOption as a voucher for the booking).
+  // If this is set, the response should also include the updated
+  // UserPaymentOption.
+  PREPAYMENT_CREDITED = 4;
+}
+// [END prepaymentstatus_definition]
+
+// [START message_slot_availability]
+// An inventory slot and associated count of open spots.
+message SlotAvailability {
+  Slot slot = 1;
+  // Number of available spots.
+  // 0 indicates that the appointment slot is not available. (required)
+  int32 count_available = 2;
+}
+// [END message_slot_availability]
+
+// [START message_availability_update]
+// An update to one ore more slots indicating that the availability for the
+// associated time has potentially changed.
+message AvailabilityUpdate {
+  repeated SlotAvailability slot_availability = 1;
+}
+// [END message_availability_update]
+
+// [START resources_definition]
+// Resource specification that disambiguates an appointment slot
+message ResourceIds {
+  // The staff ID as provided in the feed or empty if not applicable or no staff
+  // was selected. (optional)
+  string staff_id = 1;
+  // The room ID as provided in the feed or empty if not applicable or no room
+  // was selected. (optional)
+  string room_id = 2;
+  // For Dining Reservations only: the number of seats requested in the booking.
+  // (optional)
+  int32 party_size = 3;
+}
+// [END resources_definition]
+
+// [START tickettype_definition]
+// TicketType is used to differentiate among tickets (where a ticket can be a
+// spot on a raft trip, an admission to a museum, etc.) with different prices
+// and/or availabilities due to different user types or different service
+// attributes.
+message TicketType {
+  // The ticket id is used to differentiate among different ticket types of the
+  // same service, and is only expected to be unique within a service.
+  string ticket_type_id = 1;
+
+  // This can be user visible, e.g., “adult”, "child", “veteran”, “Row J”, etc.
+  string short_description = 2;
+
+  // The price of a single ticket of this type, exclusive of any taxes. The tax
+  // rate of Service is applied to its tickets.
+  Price price = 3;
+}
+// [END tickettype_definition]
+
+// [START lineitem_definition]
+// A single item in an order--the booking of a single service in a single time
+// slot.
+message LineItem {
+  // ID of the merchant service. (required)
+  string service_id = 1;
+  // Start time of the appointment slot in seconds of UTC time since Unix epoch.
+  // (required)
+  int64 start_sec = 2;
+  // Duration of the appointment slot in seconds. (required)
+  int64 duration_sec = 3;
+
+  message OrderedTickets {
+    string ticket_id = 1;
+    int32 count = 2;
+  }
+  // Number of tickets ordered by type.
+  repeated OrderedTickets tickets = 4;
+
+  // In handling CreateOrderRequest and CheckOrderFulfillabilityRequest,
+  // the total price (excluding taxes) of the item must be verified to guard
+  // against price changes. In CreateOrderResponse and
+  // CheckOrderFulfillabilityResponse, the price should be updated to the
+  // correct value if the value from the request was incorrect or outdated.
+  // (reqired)
+  Price price = 5;
+
+  // Status of the line item. (required in CreateOrderResponse and
+  // ListOrdersResponse; should not be set in requests)
+  BookingStatus status = 6;
+}
+// [END lineitem_definition]
+
+// [START lineitemfulfillability_definition]
+// Fulfillability of a line item.
+message LineItemFulfillability {
+  // The line item of question. (required)
+  LineItem item = 1;
+
+  // The result of a line item fulfillability check.
+  enum ItemFulfillabilityResult {
+    // Default value: Don't use.
+    ITEM_FULFILLABILITY_RESULT_UNSPECIFIED = 0;
+    // This line item can be fulfilled.
+    CAN_FULFILL = 1;
+    // No adequate availability for the slot requested.
+    SLOT_UNAVAILABLE = 2;
+    // The combination of ticket types requested cannot be fulfilled.
+    UNFULFILLABLE_TICKET_COMBINATION = 3;
+    // The total price of this line item is not incorrect.
+    INCORRECT_PRICE = 4;
+    // The line item cannot be fulfilled for reasons that do not fall into
+    // the categories above.
+    ITEM_UNFULFILLABLE_OTHER_REASON = 5;
+  }
+  // (required)
+  ItemFulfillabilityResult result = 2;
+  // Additional description of the reason if the item is unfulfillable.
+  // (optional)
+  string unfulfillable_reason = 3;
+  // Updated availability for this slot can be piggybacked in
+  // CheckOrderFulfillabilityResponse. (optional)
+  int32 spots_open = 4;
+  // Updated ticket types can be piggybacked in
+  // CheckOrderFulfillabilityResponse. If non-empty, all available ticket types
+  // for this slot with up-to-date prices should be listed without omitting any.
+  // (optional)
+  repeated TicketType ticket_type = 5;
+}
+// [END lineitemfulfillability_definition]
+
+// [START orderfulfillability_definition]
+message OrderFulfillability {
+  // The result of an order fulfillability check.
+  enum OrderFulfillabilityResult {
+    // Default value: Don't use.
+    ORDER_FULFILLABILITY_RESULT_UNSPECIFIED = 0;
+    // The order can be fulfilled.
+    CAN_FULFILL = 1;
+    // The order cannot be fulfilled due to one or more unfulfillable line
+    // item(s).
+    UNFULFILLABLE_LINE_ITEM = 2;
+    // The combination of the line items requested cannot be fulfilled.
+    UNFULFILLABLE_SERVICE_COMBINATION = 3;
+    // The order cannot be fulfilled due to reasons that do not fall into the
+    // categories above.
+    ORDER_UNFULFILLABLE_OTHER_REASON = 4;
+  }
+
+  OrderFulfillabilityResult result = 1;
+  // Fulfillability results of all line items in this order (required).
+  repeated LineItemFulfillability item_fulfillability = 2;
+  // Additional description of the reason if the item is unfulfillable.
+  // (optional)
+  string unfulfillable_reason = 3;
+}
+// [END orderfulfillability_definition]
+
+// [START order_definition]
+// An order for service appointments with a merchant.
+message Order {
+  // ID of this order, chosen by the booking partner who handles the order
+  // (required in CreateOrderResponse and ListOrdersResponse, must not be set in
+  // CreateOrderRequest)
+  string order_id = 1;
+  // Personal information of the user making the order (required)
+  UserInformation user_information = 2;
+  // Information about payment transactions that relate to the order.
+  // (optional)
+  PaymentInformation payment_information = 3;
+  // The merchant that all services in this order belong to.
+  string merchant_id = 4;
+  // Line items in this order.
+  repeated LineItem item = 5;
+}
+// [END order_definition]
+
+// [START orderfailure_definition]
+// Status data that conveys why creating an order fails.
+// OrderFailure is intended to primarily capture business logic errors.
+message OrderFailure {
+  enum Cause {
+    // Default value: Don't use; amounts to an "unknown error"
+    CAUSE_UNSPECIFIED = 0;
+    // The order is no longer fulfillable.
+    ORDER_UNFULFILLABLE = 1;
+    // An error was encountered while processing the payment because the
+    // provided credit card type was not accepted by the merchant. The credit
+    // card type must be supplied in rejected_card_type.
+    PAYMENT_ERROR_CARD_TYPE_REJECTED = 2;
+    // An error was encountered while processing the payment because the
+    // provided credit card was declined.
+    PAYMENT_ERROR_CARD_DECLINED = 3;
+    // An error was encountered while processing the payment for this order.
+    // Use this value to indicate a general payment related error, only if the
+    // error does not match to a specific payment error above.
+    PAYMENT_ERROR = 4;
+  }
+  // The reason why the order failed. (required)
+  Cause cause = 1;
+
+  // (required only if cause is ORDER_UNFULFILLABLE)
+  OrderFulfillability fulfillability = 2;
+
+  // (required only if cause is PAYMENT_ERROR_CARD_TYPE_REJECTED)
+  CreditCardType rejected_card_type = 3;
+
+  // This optional field is used for the partner to include additional
+  // information for debugging purpose only. (optional)
+  string description = 4;
+}
+// [END orderfailure_definition]
+
+// [START method_check_availability]
+// Request to check availability for a Slot.
+message CheckAvailabilityRequest {
+  // The appointment slot that is being checked (required)
+  Slot slot = 1;
+}
+
+// Response for the CheckAvailability RPC with the availability of the
+// appointment slot.
+message CheckAvailabilityResponse {
+  // The requested slot. (required)
+  Slot slot = 1;
+  // Number of available spots.
+  // 0 indicates that the appointment slot is not available. (required)
+  int32 count_available = 2;
+  // This enum indicates what requirements exist for the user to acknowledge or
+  // view the requested slots duration/end time.
+  enum DurationRequirement {
+    // The handling of the end time is not specified. This is the default.
+    DURATION_REQUIREMENT_UNSPECIFIED = 0;
+
+    // The end time is not shown to the user.
+    DO_NOT_SHOW_DURATION = 1;
+
+    // The end time has to be shown to the user before an appointment can be
+    // made.
+    MUST_SHOW_DURATION = 2;
+  }
+  // The requirement to show the slots duration and/or endtime. This field will
+  // be ignored if the slot is unavailable. (optional)
+  DurationRequirement duration_requirement = 3;
+
+  // Optionally, the partner can return additional updated information about the
+  // availability for this merchant if this information is present when
+  // responding to the CheckAvailabilityRequest and if there is no negative
+  // impact on the CheckAvailability request latency.
+  // For instance an entire day of merchant availability for a superset of
+  // resources can be returned here.
+  AvailabilityUpdate availability_update = 4;
+}
+// [END method_check_availability]
+
+// [START method_get_booking_status]
+// Request to get booking status and prepayment status for a Booking.
+message GetBookingStatusRequest {
+  // ID of the existing booking (required)
+  string booking_id = 1;
+}
+
+// Response for the GetBookingStatus RPC with booking status and prepayment
+// status.
+message GetBookingStatusResponse {
+  // ID of the booking (required)
+  string booking_id = 1;
+
+  // Status of the booking (required)
+  BookingStatus booking_status = 2;
+
+  // Prepayment status of the booking (required)
+  PrepaymentStatus prepayment_status = 3;
+}
+// [END method_get_booking_status]
+
+// [START method_check_order_fulfillability]
+// Request to check the fulfillability of an order.
+message CheckOrderFulfillabilityRequest {
+  // The merchant that this order is intended for. (required)
+  string merchant_id = 1;
+
+  // The line items in this order. All services requested must belong to the
+  // specified merchant. (required)
+  repeated LineItem item = 2;
+}
+
+// Response for the CheckOrderfulfillabilityRequest.
+message CheckOrderFulfillabilityResponse {
+  // Fulfillability status of the order, potentially contains updated
+  // availabilities and prices of the requested line item. (required)
+  OrderFulfillability fulfillability = 1;
+
+  // Total processing fees & taxes that need to be paid for this order.
+  // (required)
+  Price fees_and_taxes = 2;
+}
+// [END method_check_order_fulfillability]
+
+// [START method_create_booking]
+// Request to create a Booking for an inventory slot. Consumes the lease if
+// provided.
+message CreateBookingRequest {
+  // The inventory slot that is being requested to make this booking.
+  // If lease_ref is provided, slot must match the lease; slot is provided for
+  // the partner to verify the lease information.
+  // If lease_ref is absent, then create the booking for the slot. (required)
+  Slot slot = 1;
+
+  // The lease that is being confirmed to make this booking.
+  // If lease_ref is provided, then create the booking using the lease.
+  // (optional)
+  LeaseReference lease_ref = 2;
+
+  // Personal information of the user making the appointment (required)
+  UserInformation user_information = 3;
+
+  // Information about payments. When payment authorizations are handled by
+  // Google, if the booking request does not succeed, payment authorizations are
+  // automatically canceled. (optional)
+  PaymentInformation payment_information = 4;
+
+  // The parameters to be used if the payment is processed by the partner
+  // (i.e. payment_information.payment_processed_by is equal to
+  // PROCESSED_BY_PARTNER). (optional)
+  PaymentProcessingParameters payment_processing_parameters = 5;
+
+  // Idempotency token for CreateBooking requests. (required)
+  string idempotency_token = 6;
+
+  // A string from the user which contains any special requests or additional
+  // information that they would like to notify the merchant about. (optional)
+  string additional_request = 7;
+}
+
+// Response with the created Booking for an inventory slot.
+message CreateBookingResponse {
+  // The created booking (required)
+  Booking booking = 1;
+
+  // The updated user payment option used in this booking.
+  // If a new payment option was purchased to pay for the booking, this should
+  // be a newly created user payment option.
+  // If an already purchased user payment option was used for this booking,
+  // this should reflect an updated version of that user payment option.
+  // (optional)
+  UserPaymentOption user_payment_option = 2;
+
+  // If creating a booking fails, this field should reflect the business logic
+  // error (e.g., slot has become unavailable) and all other fields in the
+  // CreateBookingResponse message are expected to be unset. (required if
+  // failure occurs)
+  BookingFailure booking_failure = 3;
+}
+// [END method_create_booking]
+
+// [START method_create_order]
+// Request to create an order.
+message CreateOrderRequest {
+  // The order to create. (required)
+  Order order = 1;
+
+  // The parameters to be used if the payment is processed by the partner
+  // (i.e. order.payment_information.payment_processed_by is equal to
+  // PROCESSED_BY_PARTNER). (required if payment is processed by the partner)
+  PaymentProcessingParameters payment_processing_parameters = 2;
+
+  // Idempotency token for CreateOrder requests. (required)
+  string idempotency_token = 3;
+}
+
+// Response for the CreateOrderRequest.
+message CreateOrderResponse {
+  // The order created. (required)
+  Order order = 1;
+
+  // If creating an order fails, this field should reflect the business logic
+  // error (e.g., slot has become unavailable or price has changed) and all
+  // other fields in the CreateOrderResponse are expected to be unset. (required
+  // if failure occurs)
+  OrderFailure order_failure = 2;
+}
+// [END method_create_order]
+
+// [START method_create_lease]
+// Request to create a Leaese for a slot in the inventory.  The expiration time
+// in the returned Lease may be modified by the backend, e.g. if the requested
+// lease period is too long.
+message CreateLeaseRequest {
+  // The lease to be created with information about the appointment slot
+  // (required)
+  Lease lease = 1;
+}
+
+// Response for the CreateLease RPC with the created Lease.
+message CreateLeaseResponse {
+  // The created Lease (required)
+  Lease lease = 1;
+
+  // If creating a lease fails, this field should reflect the business logic
+  // error (e.g., slot has become unavailable) and lease field is expected to be
+  // unset. (required if failure occurs)
+  BookingFailure booking_failure = 2;
+}
+// [END method_create_lease]
+
+// [START method_list_bookings]
+// Request to list all bookings for a user
+message ListBookingsRequest {
+  // ID of the user (required)
+  string user_id = 1;
+}
+
+// Response for the ListBookings RPC with all bookings for the requested user.
+message ListBookingsResponse {
+  // All bookings of the user (required)
+  repeated Booking bookings = 1;
+}
+// [END method_list_bookings]
+
+// [START method_list_orders]
+// Request to list orders.
+message ListOrdersRequest {
+  // ID of the user (required only if order_id is not set).
+  string user_id = 1;
+  // If set, return only the specified orders; otherwise, return all orders of
+  // the user. (required only if user_id is not set).
+  repeated string order_id = 2;
+}
+
+// Response for the ListOrders RPC.
+message ListOrdersResponse {
+  // All requested orders (required)
+  repeated Order order = 1;
+}
+// [END method_list_orders]
+
+// [START method_update_booking]
+// Request to update a Booking.
+message UpdateBookingRequest {
+  // The booking to be updated
+  // The following fields can be set in a booking:
+  // - status, to cancel a booking.
+  // - start_time and duration in the slot, to reschedule a booking. (required)
+  Booking booking = 1;
+}
+
+// Response with the updated Booking.
+message UpdateBookingResponse {
+  // The updated booking (required)
+  Booking booking = 1;
+
+  // The updated user payment option originally used to pay for this booking.
+  // This should be set if the UpdateBookingRequest results in a change to
+  // the UserPaymentOption.
+  // For instance, if the booking is canceled, the UserPaymentOption should
+  // reflect an additional credit to the user. In the case of a multi-use
+  // payment option, the current_count should be increased by one to
+  // allow the user to create another booking with this payment option. In the
+  // case of a single-use payment option, a new single-use user payment option
+  // should be returned. (required if altered in update)
+  UserPaymentOption user_payment_option = 2;
+
+  // If updating a booking fails, this field should reflect the business logic
+  // error (e.g., booking is not cancellable) (required if failure occurs)
+  BookingFailure booking_failure = 3;
+}
+// [END method_update_booking]
diff --git a/testclient/main.go b/testclient/main.go
new file mode 100644
index 0000000..522df19
--- /dev/null
+++ b/testclient/main.go
@@ -0,0 +1,308 @@
+/*
+Copyright 2017 Google Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package main
+
+import (
+	"flag"
+	"fmt"
+	"log"
+	"os"
+	"path/filepath"
+	"time"
+
+	"github.com/maps-booking/api"
+	"github.com/maps-booking/utils"
+
+	fpb "github.com/maps-booking/feeds"
+	mpb "github.com/maps-booking/v3"
+)
+
+const logFile = "http_test_client_log_"
+
+var (
+	serverAddr        = flag.String("server_addr", "example.com:80", "Your http server's address in the format of host:port")
+	usernamePassword  = flag.String("username_password", "", "(eg 'username:password') credentials for your server. Leave blank to bypass authentication.")
+	testSlots         = flag.Int("num_test_slots", 10, "Maximum number of slots to test from availability_feed. Slots will be selected randomly")
+	allFlows          = flag.Bool("all_tests", false, "Whether to test all endpoints.")
+	healthFlow        = flag.Bool("health_check_test", false, "Whether to test the Health endpoint.")
+	checkFlow         = flag.Bool("check_availability_test", false, "Whether to test the CheckAvailability endpoint.")
+	bookFlow          = flag.Bool("booking_test", false, "Whether to test the CreateBooking endpoint.")
+	listFlow          = flag.Bool("list_bookings_test", false, "Whether to test the ListBookings endpoint")
+	statusFlow        = flag.Bool("booking_status_test", false, "Whether to test the GetBookingStatus endpoint.")
+	rescheduleFlow    = flag.Bool("rescheduling_test", false, "Whether to test the UpdateBooking endpoint.")
+	cancelAllBookings = flag.Bool("cancel_all_bookings", false, "This option assumes that the ListBookings and UpdateBooking endpoints are fully functional. This is a convenience flag for purging your system of all previously created bookings.")
+	availabilityFeed  = flag.String("availability_feed", "", "Absolute path to availability feed required for all tests except health. Feeds can be in either json or pb3 format")
+	outputDir         = flag.String("output_dir", "", "Absolute path of dir to dump log file.")
+)
+
+type counters struct {
+	TotalSlotsProcessed      int
+	HealthCheckSuccess       bool
+	CheckAvailabilitySuccess int
+	CheckAvailabilityErrors  int
+	CreateBookingSuccess     int
+	CreateBookingErrors      int
+	ListBookingsSuccess      bool
+	GetBookingStatusSuccess  int
+	GetBookingStatusErrors   int
+	CancelBookingsSuccess    int
+	CancelBookingsErrors     int
+	ReschedulingSuccess      bool
+}
+
+// GenerateBookings creates bookings from an availability feed.
+func GenerateBookings(av []*fpb.Availability, stats *counters, conn *api.HTTPConnection) api.Bookings {
+	log.Println("no previous bookings to use, acquiring new inventory")
+	utils.LogFlow("Generate Fresh Inventory", "Start")
+	defer utils.LogFlow("Generate Fresh Inventory", "End")
+
+	var out api.Bookings
+	totalSlots := len(av)
+	for i, a := range av {
+		if err := api.CheckAvailability(a, conn); err != nil {
+			log.Printf("%s. skipping slot %d/%d", err.Error(), i, totalSlots)
+			stats.CheckAvailabilityErrors++
+			continue
+		}
+		stats.CheckAvailabilitySuccess++
+
+		booking, err := api.CreateBooking(a, conn)
+		if err != nil {
+			log.Printf("%s. skipping slot %d/%d", err.Error(), i, totalSlots)
+			stats.CreateBookingErrors++
+			continue
+		}
+		out = append(out, booking)
+		stats.CreateBookingSuccess++
+	}
+	return out
+}
+
+func createLogFile() (*os.File, error) {
+	var err error
+	outPath := *outputDir
+	if outPath == "" {
+		outPath, err = os.Getwd()
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	now := time.Now().UTC()
+	nowString := fmt.Sprintf("%d-%02d-%02d_%02d-%02d-%02d", now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second())
+	outFile := filepath.Join(outPath, fmt.Sprintf("%s%s", logFile, nowString))
+
+	return os.Create(outFile)
+}
+
+func logStats(stats counters) {
+	log.Println("\n************* Begin Stats *************\n")
+	var totalErrors int
+	if *healthFlow || *allFlows {
+		if stats.HealthCheckSuccess {
+			log.Println("HealthCheck Succeeded")
+		} else {
+			totalErrors++
+			log.Println("HealthCheck Failed")
+		}
+	}
+	if *checkFlow || *allFlows {
+		totalErrors += stats.CheckAvailabilityErrors
+		log.Printf("CheckAvailability Errors: %d/%d", stats.CheckAvailabilityErrors, stats.CheckAvailabilityErrors+stats.CheckAvailabilitySuccess)
+	}
+	if *bookFlow || *allFlows {
+		totalErrors += stats.CreateBookingErrors
+		log.Printf("CreateBooking Errors: %d/%d", stats.CreateBookingErrors, stats.CreateBookingErrors+stats.CreateBookingSuccess)
+	}
+	if *listFlow || *allFlows {
+		if stats.ListBookingsSuccess {
+			log.Println("ListBookings Succeeded")
+		} else {
+			totalErrors++
+			log.Println("ListBookings Failed")
+		}
+	}
+	if *statusFlow || *allFlows {
+		totalErrors += stats.GetBookingStatusErrors
+		log.Printf("GetBookingStatus Errors: %d/%d", stats.GetBookingStatusErrors, stats.GetBookingStatusErrors+stats.GetBookingStatusSuccess)
+	}
+	if *rescheduleFlow || *allFlows {
+		if stats.ReschedulingSuccess {
+			log.Println("Rescheduling Succeeded")
+		} else {
+			totalErrors++
+			log.Println("Rescheduling Failed")
+		}
+	}
+
+	log.Println("\n\n\n")
+	if totalErrors == 0 {
+		log.Println("All Tests Pass!")
+	} else {
+		log.Printf("Found %d Errors", totalErrors)
+	}
+
+	log.Println("\n************* End Stats *************\n")
+	os.Exit(0)
+}
+
+func main() {
+	flag.Parse()
+	var stats counters
+
+	// Set up logging before continuing with flows
+	f, err := createLogFile()
+	if err != nil {
+		log.Fatalf("Failed to create log file %v", err)
+	}
+	defer f.Close()
+	log.SetOutput(f)
+
+	conn := api.InitHTTPConnection(*serverAddr, *usernamePassword)
+
+	// Health check doesn't affect the cancel booking flow so we let it through.
+	if *cancelAllBookings && (*allFlows || *checkFlow || *bookFlow || *listFlow || *statusFlow || *rescheduleFlow) {
+		log.Fatal("cancel_all_bookings is not supported with other test flows")
+	}
+
+	// HealthCheck Flow
+	if *healthFlow || *allFlows {
+		stats.HealthCheckSuccess = true
+		if err := api.HealthCheck(conn); err != nil {
+			stats.HealthCheckSuccess = false
+			log.Println(err.Error())
+		}
+		if !*allFlows && !*checkFlow && !*bookFlow &&
+			!*listFlow && !*statusFlow && !*rescheduleFlow {
+			logStats(stats)
+		}
+	}
+
+	var av []*fpb.Availability
+	if !*cancelAllBookings {
+		// Build availablility records.
+		if *availabilityFeed == "" {
+			log.Fatal("please set availability_feed flag if you wish to test additional flows")
+		}
+		av, err = utils.AvailabilityFrom(*availabilityFeed, *testSlots)
+		if err != nil {
+			log.Fatal(err.Error())
+		}
+		stats.TotalSlotsProcessed += len(av)
+	}
+
+	// AvailabilityCheck Flow
+	if *checkFlow || *allFlows {
+		utils.LogFlow("Availability Check", "Start")
+		totalSlots := len(av)
+
+		j := 0
+		for i, a := range av {
+			if err = api.CheckAvailability(a, conn); err != nil {
+				log.Printf("%s. skipping slot %d/%d", err.Error(), i, totalSlots)
+				stats.CheckAvailabilityErrors++
+				continue
+			}
+			stats.CheckAvailabilitySuccess++
+			av[j] = a
+			j++
+		}
+		av = av[:j]
+		utils.LogFlow("Availability Check", "End")
+	}
+	// CreateBooking Flow.
+	var b []*mpb.Booking
+	if *bookFlow || *allFlows {
+		utils.LogFlow("Booking", "Start")
+		totalSlots := len(av)
+		for i, a := range av {
+			booking, err := api.CreateBooking(a, conn)
+			if err != nil {
+				log.Printf("%s. skipping slot %d/%d", err.Error(), i, totalSlots)
+				stats.CreateBookingErrors++
+				continue
+			}
+			b = append(b, booking)
+			stats.CreateBookingSuccess++
+		}
+		utils.LogFlow("Booking", "End")
+	}
+	// ListBookings Flow
+	if *listFlow || *allFlows || *cancelAllBookings {
+		if len(b) == 0 && !*cancelAllBookings {
+			b = GenerateBookings(av, &stats, conn)
+		}
+		utils.LogFlow("List Bookings", "Start")
+		b, err = api.ListBookings(b, conn)
+		stats.ListBookingsSuccess = true
+		if err != nil {
+			stats.ListBookingsSuccess = false
+			log.Println(err.Error())
+		}
+		utils.LogFlow("List Bookings", "End")
+	}
+
+	// GetBookingStatus Flow
+	if *statusFlow || *allFlows {
+		if len(b) == 0 {
+			b = GenerateBookings(av, &stats, conn)
+		}
+
+		utils.LogFlow("BookingStatus", "Start")
+		totalBookings := len(b)
+
+		j := 0
+		for i, booking := range b {
+			if err = api.GetBookingStatus(booking, conn); err != nil {
+				log.Printf("%s. abandoning booking %d/%d", err.Error(), i, totalBookings)
+				stats.GetBookingStatusErrors++
+				continue
+			}
+			stats.GetBookingStatusSuccess++
+			b[j] = booking
+			j++
+		}
+		b = b[:j]
+		utils.LogFlow("BookingStatus", "End")
+	}
+	// CancelBooking Flow
+	if len(b) > 0 {
+		utils.LogFlow("Cancel Booking", "Start")
+		for i, booking := range b {
+			if err = api.CancelBooking(booking, conn); err != nil {
+				log.Printf("%s. abandoning booking %d/%d", err.Error(), i, len(b))
+				stats.CancelBookingsErrors++
+				continue
+			}
+			stats.CancelBookingsSuccess++
+		}
+		utils.LogFlow("Cancel Booking", "End")
+	}
+
+	// Rescheduling is nuanced and can be isolated
+	// from the rest of the tests.
+	if *rescheduleFlow || *allFlows {
+		utils.LogFlow("Rescheduling", "Start")
+		stats.ReschedulingSuccess = true
+		if err = api.Rescheduling(av, conn); err != nil {
+			log.Println(err.Error())
+			stats.ReschedulingSuccess = false
+		}
+		utils.LogFlow("Rescheduling", "End")
+	}
+
+	logStats(stats)
+}
diff --git a/utils/utils.go b/utils/utils.go
new file mode 100644
index 0000000..ea9f1fa
--- /dev/null
+++ b/utils/utils.go
@@ -0,0 +1,147 @@
+/*
+Copyright 2017 Google Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package utils contains common BookingService based helper functions.
+package utils
+
+import (
+	"errors"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"math/rand"
+	"path"
+	"strings"
+
+	"github.com/golang/protobuf/jsonpb"
+	"github.com/golang/protobuf/proto"
+	"github.com/google/go-cmp/cmp"
+
+	fpb "github.com/maps-booking/feeds"
+	mpb "github.com/maps-booking/v3"
+)
+
+// SlotKey is a struct representing a unique service.
+type SlotKey struct {
+	MerchantID string
+	ServiceID  string
+	StaffID    string
+	RoomID     string
+}
+
+// LogFlow is a convenience function for logging common flows..
+func LogFlow(f string, status string) {
+	log.Println(strings.Join([]string{"\n##########\n", status, f, "Flow", "\n##########"}, " "))
+}
+
+// AvailabilityFrom parses the file specified in availabilityFeed, returning a random permutation of availability data, maximum entries specified in testSlots
+func AvailabilityFrom(availabilityFeed string, testSlots int) ([]*fpb.Availability, error) {
+	LogFlow("Parse Input Feed", "Start")
+	defer LogFlow("Parse Input Feed", "End")
+
+	var feed fpb.AvailabilityFeed
+	content, err := ioutil.ReadFile(availabilityFeed)
+	if err != nil {
+		return nil, fmt.Errorf("unable to read input file: %v", err)
+	}
+	if path.Ext(availabilityFeed) == ".json" {
+		if err := jsonpb.UnmarshalString(string(content), &feed); err != nil {
+			return nil, fmt.Errorf("unable to parse feed as json: %v", err)
+		}
+	}
+	if path.Ext(availabilityFeed) == ".pb3" {
+		if err := proto.Unmarshal(content, &feed); err != nil {
+			return nil, fmt.Errorf("unable to parse feed as pb3: %v", err)
+		}
+	}
+
+	var finalAvailability []*fpb.Availability
+	var rawAvailability []*fpb.Availability
+	for _, sa := range feed.GetServiceAvailability() {
+		rawAvailability = append(rawAvailability, sa.GetAvailability()...)
+	}
+	if len(rawAvailability) == 0 || testSlots == 0 {
+		return finalAvailability, errors.New("no valid availability in feed, exiting workflows")
+	}
+	if len(rawAvailability) <= testSlots {
+		finalAvailability = rawAvailability
+	} else {
+		nums := rand.Perm(len(rawAvailability))[0:testSlots]
+		for _, n := range nums {
+			finalAvailability = append(finalAvailability, rawAvailability[n])
+		}
+	}
+	log.Printf("Selected %d slots out of a possible %d", len(finalAvailability), len(rawAvailability))
+	return finalAvailability, nil
+}
+
+// ValidateBooking performs granular comparisons between all got and want Bookings.
+func ValidateBooking(got *mpb.Booking, want *mpb.Booking) error {
+	if got.GetBookingId() == "" {
+		return errors.New("booking_id is empty")
+	}
+	if diff := cmp.Diff(got.GetSlot(), want.GetSlot(), cmp.Comparer(proto.Equal)); diff != "" {
+		return fmt.Errorf("slots differ (-got +want)\n%s", diff)
+	}
+	// UserId is the only required field for the partner to return.
+	if diff := cmp.Diff(got.GetUserInformation().GetUserId(), want.GetUserInformation().GetUserId()); diff != "" {
+		return fmt.Errorf("users differ (-got +want)\n%s", diff)
+	}
+	if diff := cmp.Diff(got.GetPaymentInformation(), want.GetPaymentInformation(), cmp.Comparer(proto.Equal)); diff != "" {
+		return fmt.Errorf("payment information differs (-got +want)\n%s", diff)
+	}
+	// BookingStatus_CONFIRMED is the default case unless want overrides it.
+	wantStatus := mpb.BookingStatus_CONFIRMED
+	if want.GetStatus() != mpb.BookingStatus_BOOKING_STATUS_UNSPECIFIED {
+		wantStatus = want.GetStatus()
+	}
+	if diff := cmp.Diff(got.GetStatus(), wantStatus); diff != "" {
+		return fmt.Errorf("status differs (-got +want)\n%s", diff)
+	}
+	return nil
+}
+
+// BuildSlotFrom creates a bookingservice slot from an feed availability record.
+func BuildSlotFrom(a *fpb.Availability) (*mpb.Slot, error) {
+	r := a.GetResources()
+	return &mpb.Slot{
+		MerchantId:      a.GetMerchantId(),
+		ServiceId:       a.GetServiceId(),
+		StartSec:        a.GetStartSec(),
+		DurationSec:     a.GetDurationSec(),
+		AvailabilityTag: a.GetAvailabilityTag(),
+		Resources: &mpb.ResourceIds{
+			StaffId:   r.GetStaffId(),
+			RoomId:    r.GetRoomId(),
+			PartySize: r.GetPartySize(),
+		},
+	}, nil
+}
+
+// BuildMerchantServiceMap creates a key value pair of unique services to all of their availability slots.
+func BuildMerchantServiceMap(av []*fpb.Availability) map[SlotKey][]*fpb.Availability {
+	m := make(map[SlotKey][]*fpb.Availability)
+	for _, a := range av {
+		key := SlotKey{
+			MerchantID: a.GetMerchantId(),
+			ServiceID:  a.GetServiceId(),
+			StaffID:    a.GetResources().GetStaffId(),
+			RoomID:     a.GetResources().GetRoomId(),
+		}
+		m[key] = append(m[key], a)
+	}
+	return m
+}
diff --git a/v3/v3.pb.go b/v3/v3.pb.go
new file mode 100644
index 0000000..2df1389
--- /dev/null
+++ b/v3/v3.pb.go
@@ -0,0 +1,3103 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: v3.proto
+
+/*
+Package v3 is a generated protocol buffer package.
+
+It is generated from these files:
+	v3.proto
+
+It has these top-level messages:
+	PostalAddress
+	GeoCoordinates
+	Price
+	TaxRate
+	SchedulingRules
+	IngestionQueuePayload
+	IngestionStatus
+	TimeRange
+	NoShowFee
+	Deposit
+	ActionLink
+	Slot
+	Lease
+	LeaseReference
+	Booking
+	UserInformation
+	PaymentProcessingParameters
+	UserPaymentOption
+	PaymentInformation
+	BookingFailure
+	SlotAvailability
+	AvailabilityUpdate
+	ResourceIds
+	TicketType
+	LineItem
+	LineItemFulfillability
+	OrderFulfillability
+	Order
+	OrderFailure
+	CheckAvailabilityRequest
+	CheckAvailabilityResponse
+	GetBookingStatusRequest
+	GetBookingStatusResponse
+	CheckOrderFulfillabilityRequest
+	CheckOrderFulfillabilityResponse
+	CreateBookingRequest
+	CreateBookingResponse
+	CreateOrderRequest
+	CreateOrderResponse
+	CreateLeaseRequest
+	CreateLeaseResponse
+	ListBookingsRequest
+	ListBookingsResponse
+	ListOrdersRequest
+	ListOrdersResponse
+	UpdateBookingRequest
+	UpdateBookingResponse
+*/
+package v3
+
+import proto "github.com/golang/protobuf/proto"
+import fmt "fmt"
+import math "math"
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
+
+// This defines the ingestion source type.
+type IngestionSource int32
+
+const (
+	IngestionSource_SOURCE_UNKNOWN IngestionSource = 0
+	// This ingestion is from an uploaded feed file.
+	IngestionSource_SOURCE_FEED IngestionSource = 1
+	// This ingestion is from an API call.
+	IngestionSource_SOURCE_API IngestionSource = 2
+)
+
+var IngestionSource_name = map[int32]string{
+	0: "SOURCE_UNKNOWN",
+	1: "SOURCE_FEED",
+	2: "SOURCE_API",
+}
+var IngestionSource_value = map[string]int32{
+	"SOURCE_UNKNOWN": 0,
+	"SOURCE_FEED":    1,
+	"SOURCE_API":     2,
+}
+
+func (x IngestionSource) String() string {
+	return proto.EnumName(IngestionSource_name, int32(x))
+}
+func (IngestionSource) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
+
+// The types of content that we can ingest through feeds or APIs.
+type ContentType int32
+
+const (
+	ContentType_CONTENT_UNKNOWN                ContentType = 0
+	ContentType_CONTENT_MERCHANT               ContentType = 1
+	ContentType_CONTENT_SERVICE                ContentType = 2
+	ContentType_CONTENT_AVAILABILITY           ContentType = 3
+	ContentType_CONTENT_PAYMENT_OPTION         ContentType = 4
+	ContentType_CONTENT_PAYMENT_OPTION_SERVICE ContentType = 5
+)
+
+var ContentType_name = map[int32]string{
+	0: "CONTENT_UNKNOWN",
+	1: "CONTENT_MERCHANT",
+	2: "CONTENT_SERVICE",
+	3: "CONTENT_AVAILABILITY",
+	4: "CONTENT_PAYMENT_OPTION",
+	5: "CONTENT_PAYMENT_OPTION_SERVICE",
+}
+var ContentType_value = map[string]int32{
+	"CONTENT_UNKNOWN":                0,
+	"CONTENT_MERCHANT":               1,
+	"CONTENT_SERVICE":                2,
+	"CONTENT_AVAILABILITY":           3,
+	"CONTENT_PAYMENT_OPTION":         4,
+	"CONTENT_PAYMENT_OPTION_SERVICE": 5,
+}
+
+func (x ContentType) String() string {
+	return proto.EnumName(ContentType_name, int32(x))
+}
+func (ContentType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
+
+// [START pricetype_definition]
+// Defines how a total price is determined from an availability.
+type PriceType int32
+
+const (
+	// The price is for a fixed amount. This is the default value if the field is
+	// not set.
+	PriceType_FIXED_RATE_DEFAULT PriceType = 0
+	// The price specified is per person, and the total price is calculated
+	// according to the party size specified in Resources as
+	// price_micros * party_size. A PER_PERSON price must be accompanied by a
+	// party size in the availability resources. If it is not, a party size of one
+	// is used.
+	PriceType_PER_PERSON PriceType = 1
+)
+
+var PriceType_name = map[int32]string{
+	0: "FIXED_RATE_DEFAULT",
+	1: "PER_PERSON",
+}
+var PriceType_value = map[string]int32{
+	"FIXED_RATE_DEFAULT": 0,
+	"PER_PERSON":         1,
+}
+
+func (x PriceType) String() string {
+	return proto.EnumName(PriceType_name, int32(x))
+}
+func (PriceType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
+
+// [START RequireCreditCard_definition]
+// Defines whether a credit card is required in order to book an appointment.
+type RequireCreditCard int32
+
+const (
+	// The credit card requirement is not explicitly specified and the
+	// behaviour is identical to the one specified for CONDITIONAL.
+	RequireCreditCard_REQUIRE_CREDIT_CARD_UNSPECIFIED RequireCreditCard = 0
+	// Google will require a credit card for the booking if any of the following
+	// conditions are met:
+	// * the availability has a price and the prepayment_type is REQUIRED
+	// * the no_show_fee is set
+	// * the deposit field is set.
+	RequireCreditCard_REQUIRE_CREDIT_CARD_CONDITIONAL RequireCreditCard = 1
+	// A credit card is always required in order to book this availability
+	// regardless of other field values.
+	RequireCreditCard_REQUIRE_CREDIT_CARD_ALWAYS RequireCreditCard = 2
+)
+
+var RequireCreditCard_name = map[int32]string{
+	0: "REQUIRE_CREDIT_CARD_UNSPECIFIED",
+	1: "REQUIRE_CREDIT_CARD_CONDITIONAL",
+	2: "REQUIRE_CREDIT_CARD_ALWAYS",
+}
+var RequireCreditCard_value = map[string]int32{
+	"REQUIRE_CREDIT_CARD_UNSPECIFIED": 0,
+	"REQUIRE_CREDIT_CARD_CONDITIONAL": 1,
+	"REQUIRE_CREDIT_CARD_ALWAYS":      2,
+}
+
+func (x RequireCreditCard) String() string {
+	return proto.EnumName(RequireCreditCard_name, int32(x))
+}
+func (RequireCreditCard) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
+
+// [START paymentoption_definition]
+type PaymentOptionType int32
+
+const (
+	PaymentOptionType_PAYMENT_OPTION_TYPE_UNSPECIFIED PaymentOptionType = 0
+	PaymentOptionType_PAYMENT_OPTION_SINGLE_USE       PaymentOptionType = 1
+	PaymentOptionType_PAYMENT_OPTION_MULTI_USE        PaymentOptionType = 2
+	PaymentOptionType_PAYMENT_OPTION_UNLIMITED_USE    PaymentOptionType = 3
+)
+
+var PaymentOptionType_name = map[int32]string{
+	0: "PAYMENT_OPTION_TYPE_UNSPECIFIED",
+	1: "PAYMENT_OPTION_SINGLE_USE",
+	2: "PAYMENT_OPTION_MULTI_USE",
+	3: "PAYMENT_OPTION_UNLIMITED_USE",
+}
+var PaymentOptionType_value = map[string]int32{
+	"PAYMENT_OPTION_TYPE_UNSPECIFIED": 0,
+	"PAYMENT_OPTION_SINGLE_USE":       1,
+	"PAYMENT_OPTION_MULTI_USE":        2,
+	"PAYMENT_OPTION_UNLIMITED_USE":    3,
+}
+
+func (x PaymentOptionType) String() string {
+	return proto.EnumName(PaymentOptionType_name, int32(x))
+}
+func (PaymentOptionType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
+
+// [START bookingstatus_definition]
+// 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.
+//
+// nextID: 6
+type BookingStatus int32
+
+const (
+	// Not specified.
+	BookingStatus_BOOKING_STATUS_UNSPECIFIED BookingStatus = 0
+	// Booking has been confirmed
+	BookingStatus_CONFIRMED BookingStatus = 1
+	// Booking is awaiting confirmation by the merchant before it can transition
+	// into CONFIRMED status
+	BookingStatus_PENDING_MERCHANT_CONFIRMATION BookingStatus = 2
+	// Booking has been canceled on behalf of the user.
+	// The merchant can still trigger a manual refund.
+	BookingStatus_CANCELED BookingStatus = 3
+	// User did not show for the appointment
+	BookingStatus_NO_SHOW BookingStatus = 4
+	// User did not show for the appointment in violation of the cancellation
+	// policy.
+	BookingStatus_NO_SHOW_PENALIZED BookingStatus = 5
+)
+
+var BookingStatus_name = map[int32]string{
+	0: "BOOKING_STATUS_UNSPECIFIED",
+	1: "CONFIRMED",
+	2: "PENDING_MERCHANT_CONFIRMATION",
+	3: "CANCELED",
+	4: "NO_SHOW",
+	5: "NO_SHOW_PENALIZED",
+}
+var BookingStatus_value = map[string]int32{
+	"BOOKING_STATUS_UNSPECIFIED":    0,
+	"CONFIRMED":                     1,
+	"PENDING_MERCHANT_CONFIRMATION": 2,
+	"CANCELED":                      3,
+	"NO_SHOW":                       4,
+	"NO_SHOW_PENALIZED":             5,
+}
+
+func (x BookingStatus) String() string {
+	return proto.EnumName(BookingStatus_name, int32(x))
+}
+func (BookingStatus) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
+
+// [START creditcardtype_definition]
+// Used when booking/order failure cause is PAYMENT_ERROR_CARD_TYPE_REJECTED to
+// indicate the type of credit card that was rejected.
+type CreditCardType int32
+
+const (
+	// Default value. Used if credit card type does not match to one below.
+	CreditCardType_CREDIT_CARD_TYPE_UNSPECIFIED CreditCardType = 0
+	CreditCardType_VISA                         CreditCardType = 1
+	CreditCardType_MASTERCARD                   CreditCardType = 2
+	CreditCardType_AMERICAN_EXPRESS             CreditCardType = 3
+	CreditCardType_DISCOVER                     CreditCardType = 4
+)
+
+var CreditCardType_name = map[int32]string{
+	0: "CREDIT_CARD_TYPE_UNSPECIFIED",
+	1: "VISA",
+	2: "MASTERCARD",
+	3: "AMERICAN_EXPRESS",
+	4: "DISCOVER",
+}
+var CreditCardType_value = map[string]int32{
+	"CREDIT_CARD_TYPE_UNSPECIFIED": 0,
+	"VISA":             1,
+	"MASTERCARD":       2,
+	"AMERICAN_EXPRESS": 3,
+	"DISCOVER":         4,
+}
+
+func (x CreditCardType) String() string {
+	return proto.EnumName(CreditCardType_name, int32(x))
+}
+func (CreditCardType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{6} }
+
+// [START prepaymentstatus_definition]
+// Prepayment status of a booking.
+// Updating payment status will trigger an update on the payment status of the
+// associated booking (if applicable).
+// Currently, the only supported transition is from PREPAYMENT_PROVIDED to
+// PREPAYMENT_REFUNDED, which will initiate a non-reversible refund on the
+// associated payment transaction.
+type PrepaymentStatus int32
+
+const (
+	// Not specified, defaults to PREPAYMENT_NOT_PROVIDED.
+	PrepaymentStatus_PREPAYMENT_STATUS_UNSPECIFIED PrepaymentStatus = 0
+	// The fee for the booking has been paid in advance.
+	PrepaymentStatus_PREPAYMENT_PROVIDED PrepaymentStatus = 1
+	// The fee for the booking has not been paid in advance.
+	PrepaymentStatus_PREPAYMENT_NOT_PROVIDED PrepaymentStatus = 2
+	// The fee was previously PREPAYMENT_PROVIDED but has now been refunded.
+	PrepaymentStatus_PREPAYMENT_REFUNDED PrepaymentStatus = 3
+	// The fee was previously PREPAYMENT_PROVIDED but now has been credited
+	// (user given a UserPaymentOption as a voucher for the booking).
+	// If this is set, the response should also include the updated
+	// UserPaymentOption.
+	PrepaymentStatus_PREPAYMENT_CREDITED PrepaymentStatus = 4
+)
+
+var PrepaymentStatus_name = map[int32]string{
+	0: "PREPAYMENT_STATUS_UNSPECIFIED",
+	1: "PREPAYMENT_PROVIDED",
+	2: "PREPAYMENT_NOT_PROVIDED",
+	3: "PREPAYMENT_REFUNDED",
+	4: "PREPAYMENT_CREDITED",
+}
+var PrepaymentStatus_value = map[string]int32{
+	"PREPAYMENT_STATUS_UNSPECIFIED": 0,
+	"PREPAYMENT_PROVIDED":           1,
+	"PREPAYMENT_NOT_PROVIDED":       2,
+	"PREPAYMENT_REFUNDED":           3,
+	"PREPAYMENT_CREDITED":           4,
+}
+
+func (x PrepaymentStatus) String() string {
+	return proto.EnumName(PrepaymentStatus_name, int32(x))
+}
+func (PrepaymentStatus) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{7} }
+
+// The status code of an Ingestion event: a feed upload or an API call.
+// Only used for logging the ingestion status in the IngestionMetadata
+// table, do NOT use it in the code's control flow.
+type IngestionStatus_Code int32
+
+const (
+	// An unknown status for Ingestion, shouldn't use it.
+	IngestionStatus_STATUS_UNKNOWN IngestionStatus_Code = 0
+	// 1-99 for Feed upload.
+	// A feed has been uploaded.
+	IngestionStatus_STATUS_FEED_UPLOADED IngestionStatus_Code = 1
+	// A feed has been added to the Ingestion Queue.
+	IngestionStatus_STATUS_FEED_ENQUEUED IngestionStatus_Code = 2
+	// A feed has been picked up from the queue and started processing.
+	IngestionStatus_STATUS_FEED_PROCESSING_STARTED IngestionStatus_Code = 3
+	// A feed has been processed successfully.
+	IngestionStatus_STATUS_FEED_PROCESSING_SUCCEEDED IngestionStatus_Code = 4
+	// A feed has failed the processing.
+	IngestionStatus_STATUS_FEED_PROCESSING_FAILED IngestionStatus_Code = 5
+	// A feed duplicate was uploaded.
+	IngestionStatus_STATUS_FEED_DUPLICATED IngestionStatus_Code = 6
+	// 101-199 for API.
+	// An API has been called.
+	IngestionStatus_STATUS_API_CALLED IngestionStatus_Code = 101
+	// An API has been processed successfully.
+	IngestionStatus_STATUS_API_PROCESSING_SUCCEEDED IngestionStatus_Code = 102
+	// An API has failed the processing.
+	IngestionStatus_STATUS_API_PROCESSING_FAILED IngestionStatus_Code = 103
+)
+
+var IngestionStatus_Code_name = map[int32]string{
+	0:   "STATUS_UNKNOWN",
+	1:   "STATUS_FEED_UPLOADED",
+	2:   "STATUS_FEED_ENQUEUED",
+	3:   "STATUS_FEED_PROCESSING_STARTED",
+	4:   "STATUS_FEED_PROCESSING_SUCCEEDED",
+	5:   "STATUS_FEED_PROCESSING_FAILED",
+	6:   "STATUS_FEED_DUPLICATED",
+	101: "STATUS_API_CALLED",
+	102: "STATUS_API_PROCESSING_SUCCEEDED",
+	103: "STATUS_API_PROCESSING_FAILED",
+}
+var IngestionStatus_Code_value = map[string]int32{
+	"STATUS_UNKNOWN":                   0,
+	"STATUS_FEED_UPLOADED":             1,
+	"STATUS_FEED_ENQUEUED":             2,
+	"STATUS_FEED_PROCESSING_STARTED":   3,
+	"STATUS_FEED_PROCESSING_SUCCEEDED": 4,
+	"STATUS_FEED_PROCESSING_FAILED":    5,
+	"STATUS_FEED_DUPLICATED":           6,
+	"STATUS_API_CALLED":                101,
+	"STATUS_API_PROCESSING_SUCCEEDED":  102,
+	"STATUS_API_PROCESSING_FAILED":     103,
+}
+
+func (x IngestionStatus_Code) String() string {
+	return proto.EnumName(IngestionStatus_Code_name, int32(x))
+}
+func (IngestionStatus_Code) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{6, 0} }
+
+type PaymentProcessingParameters_PaymentProcessor int32
+
+const (
+	PaymentProcessingParameters_PAYMENT_PROCESSOR_UNSPECIFIED PaymentProcessingParameters_PaymentProcessor = 0
+	PaymentProcessingParameters_PROCESSOR_STRIPE              PaymentProcessingParameters_PaymentProcessor = 1
+	PaymentProcessingParameters_PROCESSOR_BRAINTREE           PaymentProcessingParameters_PaymentProcessor = 2
+)
+
+var PaymentProcessingParameters_PaymentProcessor_name = map[int32]string{
+	0: "PAYMENT_PROCESSOR_UNSPECIFIED",
+	1: "PROCESSOR_STRIPE",
+	2: "PROCESSOR_BRAINTREE",
+}
+var PaymentProcessingParameters_PaymentProcessor_value = map[string]int32{
+	"PAYMENT_PROCESSOR_UNSPECIFIED": 0,
+	"PROCESSOR_STRIPE":              1,
+	"PROCESSOR_BRAINTREE":           2,
+}
+
+func (x PaymentProcessingParameters_PaymentProcessor) String() string {
+	return proto.EnumName(PaymentProcessingParameters_PaymentProcessor_name, int32(x))
+}
+func (PaymentProcessingParameters_PaymentProcessor) EnumDescriptor() ([]byte, []int) {
+	return fileDescriptor0, []int{16, 0}
+}
+
+// Who handles payment processing?
+// If payment is processed by the partner, CreateBooking request will
+// include additional parameters (PaymentProcessingParameters) indicating
+// the payment method to be used to process the payment.
+type PaymentInformation_PaymentProcessedBy int32
+
+const (
+	PaymentInformation_PAYMENT_PROCESSED_BY_UNSPECIFIED PaymentInformation_PaymentProcessedBy = 0
+	PaymentInformation_PROCESSED_BY_GOOGLE              PaymentInformation_PaymentProcessedBy = 1
+	PaymentInformation_PROCESSED_BY_PARTNER             PaymentInformation_PaymentProcessedBy = 2
+)
+
+var PaymentInformation_PaymentProcessedBy_name = map[int32]string{
+	0: "PAYMENT_PROCESSED_BY_UNSPECIFIED",
+	1: "PROCESSED_BY_GOOGLE",
+	2: "PROCESSED_BY_PARTNER",
+}
+var PaymentInformation_PaymentProcessedBy_value = map[string]int32{
+	"PAYMENT_PROCESSED_BY_UNSPECIFIED": 0,
+	"PROCESSED_BY_GOOGLE":              1,
+	"PROCESSED_BY_PARTNER":             2,
+}
+
+func (x PaymentInformation_PaymentProcessedBy) String() string {
+	return proto.EnumName(PaymentInformation_PaymentProcessedBy_name, int32(x))
+}
+func (PaymentInformation_PaymentProcessedBy) EnumDescriptor() ([]byte, []int) {
+	return fileDescriptor0, []int{18, 0}
+}
+
+type BookingFailure_Cause int32
+
+const (
+	// Default value: Don't use; amounts to an "unknown error"
+	BookingFailure_CAUSE_UNSPECIFIED BookingFailure_Cause = 0
+	// The referenced availability slot is not available any longer.
+	BookingFailure_SLOT_UNAVAILABLE BookingFailure_Cause = 1
+	// The user has already booked an appointment for the referenced
+	// availability slot.
+	BookingFailure_SLOT_ALREADY_BOOKED_BY_USER BookingFailure_Cause = 2
+	// The lease (if provided) has expired and cannot be used any longer to
+	// complete the requested booking.
+	BookingFailure_LEASE_EXPIRED BookingFailure_Cause = 3
+	// The requested cancellation cannot be performed at the current time due
+	// to time restrictions in the merchant's cancellation policy.
+	BookingFailure_OUTSIDE_CANCELLATION_WINDOW BookingFailure_Cause = 4
+	// An error was encountered while processing the payment because the
+	// provided credit card type was not accepted by the merchant. The credit
+	// card type must be supplied in rejected_card_type.
+	BookingFailure_PAYMENT_ERROR_CARD_TYPE_REJECTED BookingFailure_Cause = 5
+	// An error was encountered while processing the payment because the
+	// provided credit card was declined.
+	BookingFailure_PAYMENT_ERROR_CARD_DECLINED BookingFailure_Cause = 6
+	// An error was encountered with the pack/membership used to pay for the
+	// booking. There could be no valid uses left, it could have expired, etc.
+	BookingFailure_PAYMENT_OPTION_NOT_VALID BookingFailure_Cause = 7
+	// An error was encountered while processing the payment for this booking.
+	// Use this value to indicate a general payment related error, only if the
+	// error does not match to a specific payment error above.
+	BookingFailure_PAYMENT_ERROR BookingFailure_Cause = 8
+	// User cannot use the given payment option (e.g. user trying to use a
+	// first time price for the second time).
+	BookingFailure_USER_CANNOT_USE_PAYMENT_OPTION BookingFailure_Cause = 9
+	// A booking that the user tried to cancel has already been cancelled.
+	BookingFailure_BOOKING_ALREADY_CANCELLED BookingFailure_Cause = 10
+	// A booking that the user tried to cancel is not cancellable.
+	BookingFailure_BOOKING_NOT_CANCELLABLE BookingFailure_Cause = 11
+)
+
+var BookingFailure_Cause_name = map[int32]string{
+	0:  "CAUSE_UNSPECIFIED",
+	1:  "SLOT_UNAVAILABLE",
+	2:  "SLOT_ALREADY_BOOKED_BY_USER",
+	3:  "LEASE_EXPIRED",
+	4:  "OUTSIDE_CANCELLATION_WINDOW",
+	5:  "PAYMENT_ERROR_CARD_TYPE_REJECTED",
+	6:  "PAYMENT_ERROR_CARD_DECLINED",
+	7:  "PAYMENT_OPTION_NOT_VALID",
+	8:  "PAYMENT_ERROR",
+	9:  "USER_CANNOT_USE_PAYMENT_OPTION",
+	10: "BOOKING_ALREADY_CANCELLED",
+	11: "BOOKING_NOT_CANCELLABLE",
+}
+var BookingFailure_Cause_value = map[string]int32{
+	"CAUSE_UNSPECIFIED":                0,
+	"SLOT_UNAVAILABLE":                 1,
+	"SLOT_ALREADY_BOOKED_BY_USER":      2,
+	"LEASE_EXPIRED":                    3,
+	"OUTSIDE_CANCELLATION_WINDOW":      4,
+	"PAYMENT_ERROR_CARD_TYPE_REJECTED": 5,
+	"PAYMENT_ERROR_CARD_DECLINED":      6,
+	"PAYMENT_OPTION_NOT_VALID":         7,
+	"PAYMENT_ERROR":                    8,
+	"USER_CANNOT_USE_PAYMENT_OPTION":   9,
+	"BOOKING_ALREADY_CANCELLED":        10,
+	"BOOKING_NOT_CANCELLABLE":          11,
+}
+
+func (x BookingFailure_Cause) String() string {
+	return proto.EnumName(BookingFailure_Cause_name, int32(x))
+}
+func (BookingFailure_Cause) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{19, 0} }
+
+// The result of a line item fulfillability check.
+type LineItemFulfillability_ItemFulfillabilityResult int32
+
+const (
+	// Default value: Don't use.
+	LineItemFulfillability_ITEM_FULFILLABILITY_RESULT_UNSPECIFIED LineItemFulfillability_ItemFulfillabilityResult = 0
+	// This line item can be fulfilled.
+	LineItemFulfillability_CAN_FULFILL LineItemFulfillability_ItemFulfillabilityResult = 1
+	// No adequate availability for the slot requested.
+	LineItemFulfillability_SLOT_UNAVAILABLE LineItemFulfillability_ItemFulfillabilityResult = 2
+	// The combination of ticket types requested cannot be fulfilled.
+	LineItemFulfillability_UNFULFILLABLE_TICKET_COMBINATION LineItemFulfillability_ItemFulfillabilityResult = 3
+	// The total price of this line item is not incorrect.
+	LineItemFulfillability_INCORRECT_PRICE LineItemFulfillability_ItemFulfillabilityResult = 4
+	// The line item cannot be fulfilled for reasons that do not fall into
+	// the categories above.
+	LineItemFulfillability_ITEM_UNFULFILLABLE_OTHER_REASON LineItemFulfillability_ItemFulfillabilityResult = 5
+)
+
+var LineItemFulfillability_ItemFulfillabilityResult_name = map[int32]string{
+	0: "ITEM_FULFILLABILITY_RESULT_UNSPECIFIED",
+	1: "CAN_FULFILL",
+	2: "SLOT_UNAVAILABLE",
+	3: "UNFULFILLABLE_TICKET_COMBINATION",
+	4: "INCORRECT_PRICE",
+	5: "ITEM_UNFULFILLABLE_OTHER_REASON",
+}
+var LineItemFulfillability_ItemFulfillabilityResult_value = map[string]int32{
+	"ITEM_FULFILLABILITY_RESULT_UNSPECIFIED": 0,
+	"CAN_FULFILL":                            1,
+	"SLOT_UNAVAILABLE":                       2,
+	"UNFULFILLABLE_TICKET_COMBINATION":       3,
+	"INCORRECT_PRICE":                        4,
+	"ITEM_UNFULFILLABLE_OTHER_REASON":        5,
+}
+
+func (x LineItemFulfillability_ItemFulfillabilityResult) String() string {
+	return proto.EnumName(LineItemFulfillability_ItemFulfillabilityResult_name, int32(x))
+}
+func (LineItemFulfillability_ItemFulfillabilityResult) EnumDescriptor() ([]byte, []int) {
+	return fileDescriptor0, []int{25, 0}
+}
+
+// The result of an order fulfillability check.
+type OrderFulfillability_OrderFulfillabilityResult int32
+
+const (
+	// Default value: Don't use.
+	OrderFulfillability_ORDER_FULFILLABILITY_RESULT_UNSPECIFIED OrderFulfillability_OrderFulfillabilityResult = 0
+	// The order can be fulfilled.
+	OrderFulfillability_CAN_FULFILL OrderFulfillability_OrderFulfillabilityResult = 1
+	// The order cannot be fulfilled due to one or more unfulfillable line
+	// item(s).
+	OrderFulfillability_UNFULFILLABLE_LINE_ITEM OrderFulfillability_OrderFulfillabilityResult = 2
+	// The combination of the line items requested cannot be fulfilled.
+	OrderFulfillability_UNFULFILLABLE_SERVICE_COMBINATION OrderFulfillability_OrderFulfillabilityResult = 3
+	// The order cannot be fulfilled due to reasons that do not fall into the
+	// categories above.
+	OrderFulfillability_ORDER_UNFULFILLABLE_OTHER_REASON OrderFulfillability_OrderFulfillabilityResult = 4
+)
+
+var OrderFulfillability_OrderFulfillabilityResult_name = map[int32]string{
+	0: "ORDER_FULFILLABILITY_RESULT_UNSPECIFIED",
+	1: "CAN_FULFILL",
+	2: "UNFULFILLABLE_LINE_ITEM",
+	3: "UNFULFILLABLE_SERVICE_COMBINATION",
+	4: "ORDER_UNFULFILLABLE_OTHER_REASON",
+}
+var OrderFulfillability_OrderFulfillabilityResult_value = map[string]int32{
+	"ORDER_FULFILLABILITY_RESULT_UNSPECIFIED": 0,
+	"CAN_FULFILL":                             1,
+	"UNFULFILLABLE_LINE_ITEM":                 2,
+	"UNFULFILLABLE_SERVICE_COMBINATION":       3,
+	"ORDER_UNFULFILLABLE_OTHER_REASON":        4,
+}
+
+func (x OrderFulfillability_OrderFulfillabilityResult) String() string {
+	return proto.EnumName(OrderFulfillability_OrderFulfillabilityResult_name, int32(x))
+}
+func (OrderFulfillability_OrderFulfillabilityResult) EnumDescriptor() ([]byte, []int) {
+	return fileDescriptor0, []int{26, 0}
+}
+
+type OrderFailure_Cause int32
+
+const (
+	// Default value: Don't use; amounts to an "unknown error"
+	OrderFailure_CAUSE_UNSPECIFIED OrderFailure_Cause = 0
+	// The order is no longer fulfillable.
+	OrderFailure_ORDER_UNFULFILLABLE OrderFailure_Cause = 1
+	// An error was encountered while processing the payment because the
+	// provided credit card type was not accepted by the merchant. The credit
+	// card type must be supplied in rejected_card_type.
+	OrderFailure_PAYMENT_ERROR_CARD_TYPE_REJECTED OrderFailure_Cause = 2
+	// An error was encountered while processing the payment because the
+	// provided credit card was declined.
+	OrderFailure_PAYMENT_ERROR_CARD_DECLINED OrderFailure_Cause = 3
+	// An error was encountered while processing the payment for this order.
+	// Use this value to indicate a general payment related error, only if the
+	// error does not match to a specific payment error above.
+	OrderFailure_PAYMENT_ERROR OrderFailure_Cause = 4
+)
+
+var OrderFailure_Cause_name = map[int32]string{
+	0: "CAUSE_UNSPECIFIED",
+	1: "ORDER_UNFULFILLABLE",
+	2: "PAYMENT_ERROR_CARD_TYPE_REJECTED",
+	3: "PAYMENT_ERROR_CARD_DECLINED",
+	4: "PAYMENT_ERROR",
+}
+var OrderFailure_Cause_value = map[string]int32{
+	"CAUSE_UNSPECIFIED":                0,
+	"ORDER_UNFULFILLABLE":              1,
+	"PAYMENT_ERROR_CARD_TYPE_REJECTED": 2,
+	"PAYMENT_ERROR_CARD_DECLINED":      3,
+	"PAYMENT_ERROR":                    4,
+}
+
+func (x OrderFailure_Cause) String() string {
+	return proto.EnumName(OrderFailure_Cause_name, int32(x))
+}
+func (OrderFailure_Cause) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{28, 0} }
+
+// This enum indicates what requirements exist for the user to acknowledge or
+// view the requested slots duration/end time.
+type CheckAvailabilityResponse_DurationRequirement int32
+
+const (
+	// The handling of the end time is not specified. This is the default.
+	CheckAvailabilityResponse_DURATION_REQUIREMENT_UNSPECIFIED CheckAvailabilityResponse_DurationRequirement = 0
+	// The end time is not shown to the user.
+	CheckAvailabilityResponse_DO_NOT_SHOW_DURATION CheckAvailabilityResponse_DurationRequirement = 1
+	// The end time has to be shown to the user before an appointment can be
+	// made.
+	CheckAvailabilityResponse_MUST_SHOW_DURATION CheckAvailabilityResponse_DurationRequirement = 2
+)
+
+var CheckAvailabilityResponse_DurationRequirement_name = map[int32]string{
+	0: "DURATION_REQUIREMENT_UNSPECIFIED",
+	1: "DO_NOT_SHOW_DURATION",
+	2: "MUST_SHOW_DURATION",
+}
+var CheckAvailabilityResponse_DurationRequirement_value = map[string]int32{
+	"DURATION_REQUIREMENT_UNSPECIFIED": 0,
+	"DO_NOT_SHOW_DURATION":             1,
+	"MUST_SHOW_DURATION":               2,
+}
+
+func (x CheckAvailabilityResponse_DurationRequirement) String() string {
+	return proto.EnumName(CheckAvailabilityResponse_DurationRequirement_name, int32(x))
+}
+func (CheckAvailabilityResponse_DurationRequirement) EnumDescriptor() ([]byte, []int) {
+	return fileDescriptor0, []int{30, 0}
+}
+
+// [START postaladdr_definition]
+// The postal address for a merchant.
+type PostalAddress struct {
+	// The country, e.g. "USA". (required)
+	Country string `protobuf:"bytes,1,opt,name=country" json:"country,omitempty"`
+	// The locality/city, e.g. "Mountain View". (required)
+	Locality string `protobuf:"bytes,2,opt,name=locality" json:"locality,omitempty"`
+	// The region/state/province, e.g. "CA". (required)
+	Region string `protobuf:"bytes,3,opt,name=region" json:"region,omitempty"`
+	// The postal code, e.g. "94043". (required)
+	PostalCode string `protobuf:"bytes,4,opt,name=postal_code,json=postalCode" json:"postal_code,omitempty"`
+	// The street address, e.g. "1600 Amphitheatre Pkwy". (required)
+	StreetAddress string `protobuf:"bytes,5,opt,name=street_address,json=streetAddress" json:"street_address,omitempty"`
+}
+
+func (m *PostalAddress) Reset()                    { *m = PostalAddress{} }
+func (m *PostalAddress) String() string            { return proto.CompactTextString(m) }
+func (*PostalAddress) ProtoMessage()               {}
+func (*PostalAddress) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
+
+func (m *PostalAddress) GetCountry() string {
+	if m != nil {
+		return m.Country
+	}
+	return ""
+}
+
+func (m *PostalAddress) GetLocality() string {
+	if m != nil {
+		return m.Locality
+	}
+	return ""
+}
+
+func (m *PostalAddress) GetRegion() string {
+	if m != nil {
+		return m.Region
+	}
+	return ""
+}
+
+func (m *PostalAddress) GetPostalCode() string {
+	if m != nil {
+		return m.PostalCode
+	}
+	return ""
+}
+
+func (m *PostalAddress) GetStreetAddress() string {
+	if m != nil {
+		return m.StreetAddress
+	}
+	return ""
+}
+
+// [START geocoord_definition]
+// The Geo data of a location, including latitude, longitude, and address.
+type GeoCoordinates struct {
+	Latitude  float64        `protobuf:"fixed64,1,opt,name=latitude" json:"latitude,omitempty"`
+	Longitude float64        `protobuf:"fixed64,2,opt,name=longitude" json:"longitude,omitempty"`
+	Address   *PostalAddress `protobuf:"bytes,3,opt,name=address" json:"address,omitempty"`
+}
+
+func (m *GeoCoordinates) Reset()                    { *m = GeoCoordinates{} }
+func (m *GeoCoordinates) String() string            { return proto.CompactTextString(m) }
+func (*GeoCoordinates) ProtoMessage()               {}
+func (*GeoCoordinates) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
+
+func (m *GeoCoordinates) GetLatitude() float64 {
+	if m != nil {
+		return m.Latitude
+	}
+	return 0
+}
+
+func (m *GeoCoordinates) GetLongitude() float64 {
+	if m != nil {
+		return m.Longitude
+	}
+	return 0
+}
+
+func (m *GeoCoordinates) GetAddress() *PostalAddress {
+	if m != nil {
+		return m.Address
+	}
+	return nil
+}
+
+// [START price_definition]
+// The price of a service or a fee.
+type Price struct {
+	// The price in micro-units of the currency.
+	// Fractions of smallest currency unit will be rounded using nearest even
+	// rounding. (e.g. For USD 2.5 cents rounded to 2 cents, 3.5 cents rounded to
+	// 4 cents, 0.5 cents rounded to 0 cents, 2.51 cents rounded to 3 cents).
+	// (required)
+	PriceMicros int64 `protobuf:"varint,1,opt,name=price_micros,json=priceMicros" json:"price_micros,omitempty"`
+	// The currency of the price that is defined in ISO 4217. (required)
+	CurrencyCode string `protobuf:"bytes,2,opt,name=currency_code,json=currencyCode" json:"currency_code,omitempty"`
+	// An optional and opaque string that identifies the pricing option that is
+	// associated with the extended price. (optional)
+	PricingOptionTag string `protobuf:"bytes,3,opt,name=pricing_option_tag,json=pricingOptionTag" json:"pricing_option_tag,omitempty"`
+}
+
+func (m *Price) Reset()                    { *m = Price{} }
+func (m *Price) String() string            { return proto.CompactTextString(m) }
+func (*Price) ProtoMessage()               {}
+func (*Price) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
+
+func (m *Price) GetPriceMicros() int64 {
+	if m != nil {
+		return m.PriceMicros
+	}
+	return 0
+}
+
+func (m *Price) GetCurrencyCode() string {
+	if m != nil {
+		return m.CurrencyCode
+	}
+	return ""
+}
+
+func (m *Price) GetPricingOptionTag() string {
+	if m != nil {
+		return m.PricingOptionTag
+	}
+	return ""
+}
+
+// [START taxrate_definition]
+// A tax rate applied when charging the user for a service, and which can be set
+// on either a per merchant, or per service basis.
+type TaxRate struct {
+	// A tax rate in millionths of one percent, effectively giving 6 decimals of
+	// precision. For example, if the tax rate is 7.253%, this field should be set
+	// to 7253000.
+	//
+	// If this field is left unset or set to 0, the total price charged to a user
+	// for any service provided by this merchant is the exact price specified by
+	// Service.price. The service price is assumed to be exempt from or already
+	// inclusive of applicable taxes. Taxes will not be shown to the user as a
+	// separate line item.
+	//
+	// If this field is set to any nonzero value, the total price charged to a
+	// user for any service provided by this merchant will include the service
+	// price plus the tax assessed using the tax rate provided here. Fractions of
+	// the smallest currency unit (for example, fractions of one cent) will be
+	// rounded using nearest even rounding. Taxes will be shown to the user as a
+	// separate line item. (required)
+	MicroPercent int32 `protobuf:"varint,1,opt,name=micro_percent,json=microPercent" json:"micro_percent,omitempty"`
+}
+
+func (m *TaxRate) Reset()                    { *m = TaxRate{} }
+func (m *TaxRate) String() string            { return proto.CompactTextString(m) }
+func (*TaxRate) ProtoMessage()               {}
+func (*TaxRate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
+
+func (m *TaxRate) GetMicroPercent() int32 {
+	if m != nil {
+		return m.MicroPercent
+	}
+	return 0
+}
+
+// [START schedulingrules_definition]
+// The scheduling rules for a service.
+type SchedulingRules struct {
+	// The minimum advance notice in seconds required to book an appointment.
+	// (optional)
+	MinAdvanceBooking int64 `protobuf:"varint,1,opt,name=min_advance_booking,json=minAdvanceBooking" json:"min_advance_booking,omitempty"`
+	// The minimum advance notice in seconds required to cancel a booked
+	// appointment online. (optional)
+	MinAdvanceOnlineCanceling int64 `protobuf:"varint,2,opt,name=min_advance_online_canceling,json=minAdvanceOnlineCanceling" json:"min_advance_online_canceling,omitempty"`
+	// The fee for canceling within the minimum advance notice period.
+	LateCancellationFee *Price `protobuf:"bytes,3,opt,name=late_cancellation_fee,json=lateCancellationFee" json:"late_cancellation_fee,omitempty"`
+	// The fee for no-show without canceling.
+	NoshowFee *Price `protobuf:"bytes,4,opt,name=noshow_fee,json=noshowFee" json:"noshow_fee,omitempty"`
+}
+
+func (m *SchedulingRules) Reset()                    { *m = SchedulingRules{} }
+func (m *SchedulingRules) String() string            { return proto.CompactTextString(m) }
+func (*SchedulingRules) ProtoMessage()               {}
+func (*SchedulingRules) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
+
+func (m *SchedulingRules) GetMinAdvanceBooking() int64 {
+	if m != nil {
+		return m.MinAdvanceBooking
+	}
+	return 0
+}
+
+func (m *SchedulingRules) GetMinAdvanceOnlineCanceling() int64 {
+	if m != nil {
+		return m.MinAdvanceOnlineCanceling
+	}
+	return 0
+}
+
+func (m *SchedulingRules) GetLateCancellationFee() *Price {
+	if m != nil {
+		return m.LateCancellationFee
+	}
+	return nil
+}
+
+func (m *SchedulingRules) GetNoshowFee() *Price {
+	if m != nil {
+		return m.NoshowFee
+	}
+	return nil
+}
+
+// An empty boilplate proto for the Ingestion Queue in Spanner.
+type IngestionQueuePayload struct {
+}
+
+func (m *IngestionQueuePayload) Reset()                    { *m = IngestionQueuePayload{} }
+func (m *IngestionQueuePayload) String() string            { return proto.CompactTextString(m) }
+func (*IngestionQueuePayload) ProtoMessage()               {}
+func (*IngestionQueuePayload) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
+
+type IngestionStatus struct {
+	// The code of the status.
+	Code IngestionStatus_Code `protobuf:"varint,1,opt,name=code,enum=v3.IngestionStatus_Code" json:"code,omitempty"`
+	// Microseconds since epoch when the ingestion updates its status code.
+	TimestampMicros int64 `protobuf:"varint,2,opt,name=timestamp_micros,json=timestampMicros" json:"timestamp_micros,omitempty"`
+	// A human description of the error if any.
+	InternalErrorDetails       string `protobuf:"bytes,3,opt,name=internal_error_details,json=internalErrorDetails" json:"internal_error_details,omitempty"`
+	PartnerVisibleErrorDetails string `protobuf:"bytes,4,opt,name=partner_visible_error_details,json=partnerVisibleErrorDetails" json:"partner_visible_error_details,omitempty"`
+}
+
+func (m *IngestionStatus) Reset()                    { *m = IngestionStatus{} }
+func (m *IngestionStatus) String() string            { return proto.CompactTextString(m) }
+func (*IngestionStatus) ProtoMessage()               {}
+func (*IngestionStatus) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} }
+
+func (m *IngestionStatus) GetCode() IngestionStatus_Code {
+	if m != nil {
+		return m.Code
+	}
+	return IngestionStatus_STATUS_UNKNOWN
+}
+
+func (m *IngestionStatus) GetTimestampMicros() int64 {
+	if m != nil {
+		return m.TimestampMicros
+	}
+	return 0
+}
+
+func (m *IngestionStatus) GetInternalErrorDetails() string {
+	if m != nil {
+		return m.InternalErrorDetails
+	}
+	return ""
+}
+
+func (m *IngestionStatus) GetPartnerVisibleErrorDetails() string {
+	if m != nil {
+		return m.PartnerVisibleErrorDetails
+	}
+	return ""
+}
+
+// [START timerange_definition]
+// A closed-open time range, i.e. [begin_sec, end_sec)
+type TimeRange struct {
+	// Seconds of UTC time since Unix epoch (required)
+	BeginSec int64 `protobuf:"varint,1,opt,name=begin_sec,json=beginSec" json:"begin_sec,omitempty"`
+	// Seconds of UTC time since Unix epoch (required)
+	EndSec int64 `protobuf:"varint,2,opt,name=end_sec,json=endSec" json:"end_sec,omitempty"`
+}
+
+func (m *TimeRange) Reset()                    { *m = TimeRange{} }
+func (m *TimeRange) String() string            { return proto.CompactTextString(m) }
+func (*TimeRange) ProtoMessage()               {}
+func (*TimeRange) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} }
+
+func (m *TimeRange) GetBeginSec() int64 {
+	if m != nil {
+		return m.BeginSec
+	}
+	return 0
+}
+
+func (m *TimeRange) GetEndSec() int64 {
+	if m != nil {
+		return m.EndSec
+	}
+	return 0
+}
+
+// [START noshowfee_definition]
+// A fee that a user may be charged if they have made a booking but do not
+// show up.
+type NoShowFee struct {
+	// The amount the user may be charged if they do not show up for their
+	// reservation.
+	Fee *Price `protobuf:"bytes,1,opt,name=fee" json:"fee,omitempty"`
+	// Defines how the fee is determined from the availability.
+	FeeType PriceType `protobuf:"varint,3,opt,name=fee_type,json=feeType,enum=v3.PriceType" json:"fee_type,omitempty"`
+}
+
+func (m *NoShowFee) Reset()                    { *m = NoShowFee{} }
+func (m *NoShowFee) String() string            { return proto.CompactTextString(m) }
+func (*NoShowFee) ProtoMessage()               {}
+func (*NoShowFee) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} }
+
+func (m *NoShowFee) GetFee() *Price {
+	if m != nil {
+		return m.Fee
+	}
+	return nil
+}
+
+func (m *NoShowFee) GetFeeType() PriceType {
+	if m != nil {
+		return m.FeeType
+	}
+	return PriceType_FIXED_RATE_DEFAULT
+}
+
+// [START deposit_definition]
+// A deposit that the user may be charged or have a hold on their credit card
+// for.
+type Deposit struct {
+	// Deposit amount.
+	Deposit *Price `protobuf:"bytes,1,opt,name=deposit" json:"deposit,omitempty"`
+	// Minimum advance cancellation for the deposit.
+	MinAdvanceCancellationSec int64 `protobuf:"varint,2,opt,name=min_advance_cancellation_sec,json=minAdvanceCancellationSec" json:"min_advance_cancellation_sec,omitempty"`
+	// Defines how the deposit is determined from the availability.
+	DepositType PriceType `protobuf:"varint,3,opt,name=deposit_type,json=depositType,enum=v3.PriceType" json:"deposit_type,omitempty"`
+}
+
+func (m *Deposit) Reset()                    { *m = Deposit{} }
+func (m *Deposit) String() string            { return proto.CompactTextString(m) }
+func (*Deposit) ProtoMessage()               {}
+func (*Deposit) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} }
+
+func (m *Deposit) GetDeposit() *Price {
+	if m != nil {
+		return m.Deposit
+	}
+	return nil
+}
+
+func (m *Deposit) GetMinAdvanceCancellationSec() int64 {
+	if m != nil {
+		return m.MinAdvanceCancellationSec
+	}
+	return 0
+}
+
+func (m *Deposit) GetDepositType() PriceType {
+	if m != nil {
+		return m.DepositType
+	}
+	return PriceType_FIXED_RATE_DEFAULT
+}
+
+// [START ActionLink_definition]
+// An action URL with associated language and list of countries restricted to.
+type ActionLink struct {
+	// The entry point URL for this action link.
+	Url string `protobuf:"bytes,1,opt,name=url" json:"url,omitempty"`
+	// The BCP-47 language tag identifying the language in which the content
+	// from this URI is available.
+	Language string `protobuf:"bytes,2,opt,name=language" json:"language,omitempty"`
+	// ISO 3166-1 alpha-2 country code. Leave empty for unrestricted visibility.
+	RestrictedCountry []string `protobuf:"bytes,3,rep,name=restricted_country,json=restrictedCountry" json:"restricted_country,omitempty"`
+}
+
+func (m *ActionLink) Reset()                    { *m = ActionLink{} }
+func (m *ActionLink) String() string            { return proto.CompactTextString(m) }
+func (*ActionLink) ProtoMessage()               {}
+func (*ActionLink) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} }
+
+func (m *ActionLink) GetUrl() string {
+	if m != nil {
+		return m.Url
+	}
+	return ""
+}
+
+func (m *ActionLink) GetLanguage() string {
+	if m != nil {
+		return m.Language
+	}
+	return ""
+}
+
+func (m *ActionLink) GetRestrictedCountry() []string {
+	if m != nil {
+		return m.RestrictedCountry
+	}
+	return nil
+}
+
+// [START message_slot]
+// An inventory slot
+type Slot struct {
+	// ID of the merchant for the slot (required)
+	MerchantId string `protobuf:"bytes,1,opt,name=merchant_id,json=merchantId" json:"merchant_id,omitempty"`
+	// ID of the merchant service (required)
+	ServiceId string `protobuf:"bytes,2,opt,name=service_id,json=serviceId" json:"service_id,omitempty"`
+	// Start time of the appointment slot in seconds of UTC time since Unix epoch.
+	// (required)
+	StartSec int64 `protobuf:"varint,3,opt,name=start_sec,json=startSec" json:"start_sec,omitempty"`
+	// Duration of the appointment slot (required)
+	DurationSec int64 `protobuf:"varint,4,opt,name=duration_sec,json=durationSec" json:"duration_sec,omitempty"`
+	// Opaque tag that identifies the availability slot and matches the value
+	// provided in the availability feed (optional)
+	AvailabilityTag string `protobuf:"bytes,5,opt,name=availability_tag,json=availabilityTag" json:"availability_tag,omitempty"`
+	// The set of resources that disambiguates the appointment slot, e.g. by
+	// indicating the staff member and room selected by the user (optional)
+	Resources *ResourceIds `protobuf:"bytes,6,opt,name=resources" json:"resources,omitempty"`
+}
+
+func (m *Slot) Reset()                    { *m = Slot{} }
+func (m *Slot) String() string            { return proto.CompactTextString(m) }
+func (*Slot) ProtoMessage()               {}
+func (*Slot) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} }
+
+func (m *Slot) GetMerchantId() string {
+	if m != nil {
+		return m.MerchantId
+	}
+	return ""
+}
+
+func (m *Slot) GetServiceId() string {
+	if m != nil {
+		return m.ServiceId
+	}
+	return ""
+}
+
+func (m *Slot) GetStartSec() int64 {
+	if m != nil {
+		return m.StartSec
+	}
+	return 0
+}
+
+func (m *Slot) GetDurationSec() int64 {
+	if m != nil {
+		return m.DurationSec
+	}
+	return 0
+}
+
+func (m *Slot) GetAvailabilityTag() string {
+	if m != nil {
+		return m.AvailabilityTag
+	}
+	return ""
+}
+
+func (m *Slot) GetResources() *ResourceIds {
+	if m != nil {
+		return m.Resources
+	}
+	return nil
+}
+
+// [START message_lease]
+// Temporary lease for an inventory slot
+type Lease struct {
+	// ID of the lease.
+	// Not populated in CreateLeaseRequest. The value is chosen by the partner and
+	// has to be returned in the response of CreateLease. (required)
+	LeaseId string `protobuf:"bytes,1,opt,name=lease_id,json=leaseId" json:"lease_id,omitempty"`
+	// The appointment slot that the lease is created for. (required)
+	Slot *Slot `protobuf:"bytes,2,opt,name=slot" json:"slot,omitempty"`
+	// Unique identifier for this lease, chosen by Reserve with Google. Serves as
+	// an idempotency token for CreateLease requests. (required)
+	UserReference string `protobuf:"bytes,3,opt,name=user_reference,json=userReference" json:"user_reference,omitempty"`
+	// Expiration time of the lease in UTC Timestamp (required)
+	LeaseExpirationTimeSec int64 `protobuf:"varint,4,opt,name=lease_expiration_time_sec,json=leaseExpirationTimeSec" json:"lease_expiration_time_sec,omitempty"`
+}
+
+func (m *Lease) Reset()                    { *m = Lease{} }
+func (m *Lease) String() string            { return proto.CompactTextString(m) }
+func (*Lease) ProtoMessage()               {}
+func (*Lease) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12} }
+
+func (m *Lease) GetLeaseId() string {
+	if m != nil {
+		return m.LeaseId
+	}
+	return ""
+}
+
+func (m *Lease) GetSlot() *Slot {
+	if m != nil {
+		return m.Slot
+	}
+	return nil
+}
+
+func (m *Lease) GetUserReference() string {
+	if m != nil {
+		return m.UserReference
+	}
+	return ""
+}
+
+func (m *Lease) GetLeaseExpirationTimeSec() int64 {
+	if m != nil {
+		return m.LeaseExpirationTimeSec
+	}
+	return 0
+}
+
+// Reference to a Lease that has been created via CreateLease.
+type LeaseReference struct {
+	// Lease ID (required)
+	LeaseId string `protobuf:"bytes,1,opt,name=lease_id,json=leaseId" json:"lease_id,omitempty"`
+}
+
+func (m *LeaseReference) Reset()                    { *m = LeaseReference{} }
+func (m *LeaseReference) String() string            { return proto.CompactTextString(m) }
+func (*LeaseReference) ProtoMessage()               {}
+func (*LeaseReference) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{13} }
+
+func (m *LeaseReference) GetLeaseId() string {
+	if m != nil {
+		return m.LeaseId
+	}
+	return ""
+}
+
+// [START message_booking]
+// A booking for an inventory slot
+type Booking struct {
+	// ID of this booking (required)
+	BookingId string `protobuf:"bytes,1,opt,name=booking_id,json=bookingId" json:"booking_id,omitempty"`
+	// The appointment slot of this booking (required)
+	Slot *Slot `protobuf:"bytes,2,opt,name=slot" json:"slot,omitempty"`
+	// Personal information of the user making the appointment (required)
+	UserInformation *UserInformation `protobuf:"bytes,3,opt,name=user_information,json=userInformation" json:"user_information,omitempty"`
+	// Status of the booking (required)
+	Status BookingStatus `protobuf:"varint,4,opt,name=status,enum=v3.BookingStatus" json:"status,omitempty"`
+	// Information about payment transactions that relate to the booking.
+	// (optional)
+	PaymentInformation *PaymentInformation `protobuf:"bytes,5,opt,name=payment_information,json=paymentInformation" json:"payment_information,omitempty"`
+}
+
+func (m *Booking) Reset()                    { *m = Booking{} }
+func (m *Booking) String() string            { return proto.CompactTextString(m) }
+func (*Booking) ProtoMessage()               {}
+func (*Booking) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{14} }
+
+func (m *Booking) GetBookingId() string {
+	if m != nil {
+		return m.BookingId
+	}
+	return ""
+}
+
+func (m *Booking) GetSlot() *Slot {
+	if m != nil {
+		return m.Slot
+	}
+	return nil
+}
+
+func (m *Booking) GetUserInformation() *UserInformation {
+	if m != nil {
+		return m.UserInformation
+	}
+	return nil
+}
+
+func (m *Booking) GetStatus() BookingStatus {
+	if m != nil {
+		return m.Status
+	}
+	return BookingStatus_BOOKING_STATUS_UNSPECIFIED
+}
+
+func (m *Booking) GetPaymentInformation() *PaymentInformation {
+	if m != nil {
+		return m.PaymentInformation
+	}
+	return nil
+}
+
+// [START user_definition]
+// Personal information about the person making a booking
+type UserInformation struct {
+	// Unique ID of the user to the partner, chosen by Reserve with Google.
+	// (required)
+	UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"`
+	// Given name of the user (required)
+	GivenName string `protobuf:"bytes,2,opt,name=given_name,json=givenName" json:"given_name,omitempty"`
+	// Family name of the user (required)
+	FamilyName string `protobuf:"bytes,3,opt,name=family_name,json=familyName" json:"family_name,omitempty"`
+	// Address of the user (optional)
+	Address *PostalAddress `protobuf:"bytes,4,opt,name=address" json:"address,omitempty"`
+	// Phone number of the user (required)
+	Telephone string `protobuf:"bytes,5,opt,name=telephone" json:"telephone,omitempty"`
+	// Email address of the user (required)
+	Email string `protobuf:"bytes,6,opt,name=email" json:"email,omitempty"`
+}
+
+func (m *UserInformation) Reset()                    { *m = UserInformation{} }
+func (m *UserInformation) String() string            { return proto.CompactTextString(m) }
+func (*UserInformation) ProtoMessage()               {}
+func (*UserInformation) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{15} }
+
+func (m *UserInformation) GetUserId() string {
+	if m != nil {
+		return m.UserId
+	}
+	return ""
+}
+
+func (m *UserInformation) GetGivenName() string {
+	if m != nil {
+		return m.GivenName
+	}
+	return ""
+}
+
+func (m *UserInformation) GetFamilyName() string {
+	if m != nil {
+		return m.FamilyName
+	}
+	return ""
+}
+
+func (m *UserInformation) GetAddress() *PostalAddress {
+	if m != nil {
+		return m.Address
+	}
+	return nil
+}
+
+func (m *UserInformation) GetTelephone() string {
+	if m != nil {
+		return m.Telephone
+	}
+	return ""
+}
+
+func (m *UserInformation) GetEmail() string {
+	if m != nil {
+		return m.Email
+	}
+	return ""
+}
+
+// [START paymentprocessing_definition]
+type PaymentProcessingParameters struct {
+	// The payment processor used to process payment for a given booking.
+	// (required)
+	//
+	// Replaced by the payment_processor field.
+	Processor PaymentProcessingParameters_PaymentProcessor `protobuf:"varint,1,opt,name=processor,enum=v3.PaymentProcessingParameters_PaymentProcessor" json:"processor,omitempty"`
+	// The token representing the payment method that will be used to pay
+	// for this booking. This token can be only used once. This token can be
+	// only used for the merchant associated with this booking.
+	//
+	// Each processor may choose its own format for this field.
+	// An example of Stripe's token is "tok_1C3orL2eZvKYlo2CxReMgS4K".
+	//
+	// Replaced by unparsed_payment_method_token, which contains
+	// payment_method_token as one of its fields.
+	// For example, for Stripe, unparsed_payment_method_token is a serialized
+	// JSON object documented at https://stripe.com/docs/api#token_object.
+	// payment_method_token is the 'id' field parsed out of that.
+	PaymentMethodToken string `protobuf:"bytes,2,opt,name=payment_method_token,json=paymentMethodToken" json:"payment_method_token,omitempty"`
+	// The full token received from Google Payments.  This is typically a
+	// serialized JSON object.  See documentation from Google Payments and your
+	// payment processor for the JSON format of the token for your processor.
+	// https://developers.google.com/pay/api/#participating-google-pay-processors
+	//
+	// This token can only be used once, and only for the merchant associated with
+	// this booking.
+	UnparsedPaymentMethodToken string `protobuf:"bytes,5,opt,name=unparsed_payment_method_token,json=unparsedPaymentMethodToken" json:"unparsed_payment_method_token,omitempty"`
+	// The payment processor API version that the given payment token is valid
+	// for.
+	//
+	// Each processor may choose its own format for this field.
+	// Stripe uses a date (e.g. "2017-06-15"). (required)
+	Version string `protobuf:"bytes,3,opt,name=version" json:"version,omitempty"`
+	// The payment processor whose configuration was used to generate this token.
+	// (required)
+	PaymentProcessor string `protobuf:"bytes,4,opt,name=payment_processor,json=paymentProcessor" json:"payment_processor,omitempty"`
+}
+
+func (m *PaymentProcessingParameters) Reset()                    { *m = PaymentProcessingParameters{} }
+func (m *PaymentProcessingParameters) String() string            { return proto.CompactTextString(m) }
+func (*PaymentProcessingParameters) ProtoMessage()               {}
+func (*PaymentProcessingParameters) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{16} }
+
+func (m *PaymentProcessingParameters) GetProcessor() PaymentProcessingParameters_PaymentProcessor {
+	if m != nil {
+		return m.Processor
+	}
+	return PaymentProcessingParameters_PAYMENT_PROCESSOR_UNSPECIFIED
+}
+
+func (m *PaymentProcessingParameters) GetPaymentMethodToken() string {
+	if m != nil {
+		return m.PaymentMethodToken
+	}
+	return ""
+}
+
+func (m *PaymentProcessingParameters) GetUnparsedPaymentMethodToken() string {
+	if m != nil {
+		return m.UnparsedPaymentMethodToken
+	}
+	return ""
+}
+
+func (m *PaymentProcessingParameters) GetVersion() string {
+	if m != nil {
+		return m.Version
+	}
+	return ""
+}
+
+func (m *PaymentProcessingParameters) GetPaymentProcessor() string {
+	if m != nil {
+		return m.PaymentProcessor
+	}
+	return ""
+}
+
+// [START userpaymentoption_definition]
+// This describes a payment option, such as a pack, membership, or
+// single-session pass after it has been purchased by a user. It includes an
+// identifier for the user payment option, as well as some information about
+// the payment option with which it is associated.
+type UserPaymentOption struct {
+	// A unique identifier for the user payment option. This Id MUST be unique
+	// for all UserPaymentOptions across all merchants and users. (required)
+	UserPaymentOptionId string `protobuf:"bytes,1,opt,name=user_payment_option_id,json=userPaymentOptionId" json:"user_payment_option_id,omitempty"`
+	// The user payment option will be valid (usable) between start_time and
+	// end_time set in UTC. Attempts to use a user payment option to make a
+	// booking outside of this interval will fail. (both optional)
+	ValidStartTimeSec int64 `protobuf:"varint,2,opt,name=valid_start_time_sec,json=validStartTimeSec" json:"valid_start_time_sec,omitempty"`
+	ValidEndTimeSec   int64 `protobuf:"varint,3,opt,name=valid_end_time_sec,json=validEndTimeSec" json:"valid_end_time_sec,omitempty"`
+	// The type of the payment option associated with this user payment option.
+	// This can be unlimited for a membership or subscription, multi-use for a
+	// pack, or single-use. (required)
+	Type PaymentOptionType `protobuf:"varint,4,opt,name=type,enum=v3.PaymentOptionType" json:"type,omitempty"`
+	// The original number of uses for this user payment option when it was
+	// purchased. This value is ignored for unlimited payment options. (required)
+	OriginalCount int32 `protobuf:"varint,5,opt,name=original_count,json=originalCount" json:"original_count,omitempty"`
+	// The number of uses remaining for this user payment option. If this number
+	// is 0 for a pack, attempts to use this payment option to make a booking will
+	// fail. (required)
+	CurrentCount int32 `protobuf:"varint,6,opt,name=current_count,json=currentCount" json:"current_count,omitempty"`
+	// The id of the payment option that has been used to purchase this user
+	// payment option. (required)
+	PaymentOptionId string `protobuf:"bytes,7,opt,name=payment_option_id,json=paymentOptionId" json:"payment_option_id,omitempty"`
+}
+
+func (m *UserPaymentOption) Reset()                    { *m = UserPaymentOption{} }
+func (m *UserPaymentOption) String() string            { return proto.CompactTextString(m) }
+func (*UserPaymentOption) ProtoMessage()               {}
+func (*UserPaymentOption) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{17} }
+
+func (m *UserPaymentOption) GetUserPaymentOptionId() string {
+	if m != nil {
+		return m.UserPaymentOptionId
+	}
+	return ""
+}
+
+func (m *UserPaymentOption) GetValidStartTimeSec() int64 {
+	if m != nil {
+		return m.ValidStartTimeSec
+	}
+	return 0
+}
+
+func (m *UserPaymentOption) GetValidEndTimeSec() int64 {
+	if m != nil {
+		return m.ValidEndTimeSec
+	}
+	return 0
+}
+
+func (m *UserPaymentOption) GetType() PaymentOptionType {
+	if m != nil {
+		return m.Type
+	}
+	return PaymentOptionType_PAYMENT_OPTION_TYPE_UNSPECIFIED
+}
+
+func (m *UserPaymentOption) GetOriginalCount() int32 {
+	if m != nil {
+		return m.OriginalCount
+	}
+	return 0
+}
+
+func (m *UserPaymentOption) GetCurrentCount() int32 {
+	if m != nil {
+		return m.CurrentCount
+	}
+	return 0
+}
+
+func (m *UserPaymentOption) GetPaymentOptionId() string {
+	if m != nil {
+		return m.PaymentOptionId
+	}
+	return ""
+}
+
+// [START paymentinfo_definition]
+// Payment details that are sent when creating a new booking.
+type PaymentInformation struct {
+	// Prepayment status of the booking.
+	// If the prepayment_status is PREPAYMENT_PROVIDED, then
+	// payment_transaction_id contains the associated unique transaction id for
+	// the purchase.
+	// If the prepayment status is PREPAYMENT_REFUNDED, then
+	// payment_transaction_id contains the associated unique transaction id for
+	// the refund. (required)
+	PrepaymentStatus PrepaymentStatus `protobuf:"varint,1,opt,name=prepayment_status,json=prepaymentStatus,enum=v3.PrepaymentStatus" json:"prepayment_status,omitempty"`
+	// Unique identifier for a payment transaction associated with the booking.
+	// Empty if not applicable. (required)
+	PaymentTransactionId string `protobuf:"bytes,2,opt,name=payment_transaction_id,json=paymentTransactionId" json:"payment_transaction_id,omitempty"`
+	// These fields must match the service price (specified in the Services feed)
+	// or the PaymentOption corresponding with this service.
+	// They are included in the booking request and response to verify that
+	// the price indicated in the feed has not changed since the last feed
+	// update.
+	//
+	// The price of the booking or order, exclusive of any taxes.
+	// Existence of price or taxes does not imply that they have been paid,
+	// prepayment_state should be used for that purpose. (required)
+	Price *Price `protobuf:"bytes,3,opt,name=price" json:"price,omitempty"`
+	// Taxes that are calculated to be paid for this booking.
+	// This field can only be absent in one of the following cases:
+	// (1) the price is exempt from or already inclusive of applicable taxes; or
+	// (2) the break down between taxes and fees is not available.
+	// (required when neither of the above holds)
+	TaxAmount *Price `protobuf:"bytes,4,opt,name=tax_amount,json=taxAmount" json:"tax_amount,omitempty"`
+	// Whether the partner or Google processed the payment. (required)
+	PaymentProcessedBy PaymentInformation_PaymentProcessedBy `protobuf:"varint,5,opt,name=payment_processed_by,json=paymentProcessedBy,enum=v3.PaymentInformation_PaymentProcessedBy" json:"payment_processed_by,omitempty"`
+	// The id of the payment option or user payment option associated with the
+	// booking.
+	// If a payment option is purchased as part of a booking, payment_option_id
+	// will be set with the id of that payment option.
+	// If an already purchased user payment option is being used to pay for a
+	// booking, user_payment_option_id will be set with the id of that user
+	// payment option.
+	// When included as part of a response proto, the user_payment_option_id
+	// should be set and must match the UserPaymentOption that is returned in the
+	// RPC response (e.g. the user_payment_option returned in
+	// CreateBookingResponse). (one of these required)
+	//
+	// Types that are valid to be assigned to PaymentId:
+	//	*PaymentInformation_PaymentOptionId
+	//	*PaymentInformation_UserPaymentOptionId
+	PaymentId isPaymentInformation_PaymentId `protobuf_oneof:"payment_id"`
+	// Defines how a deposit may be charged to the user. If there is a deposit,
+	// this field should be set. (optional)
+	Deposit *Deposit `protobuf:"bytes,8,opt,name=deposit" json:"deposit,omitempty"`
+	// Defines a no show fee that may be charged to the user. If the user can be
+	// charged a no show fee, this field should be set. (optional)
+	NoShowFee *NoShowFee `protobuf:"bytes,9,opt,name=no_show_fee,json=noShowFee" json:"no_show_fee,omitempty"`
+	// Total processing fees & taxes that the user needs to pay for the order;
+	// only applicable to partners that handle order based booking (e.g., with
+	// CreateOrder method). (optional)
+	FeesAndTaxes *Price `protobuf:"bytes,10,opt,name=fees_and_taxes,json=feesAndTaxes" json:"fees_and_taxes,omitempty"`
+}
+
+func (m *PaymentInformation) Reset()                    { *m = PaymentInformation{} }
+func (m *PaymentInformation) String() string            { return proto.CompactTextString(m) }
+func (*PaymentInformation) ProtoMessage()               {}
+func (*PaymentInformation) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{18} }
+
+type isPaymentInformation_PaymentId interface {
+	isPaymentInformation_PaymentId()
+}
+
+type PaymentInformation_PaymentOptionId struct {
+	PaymentOptionId string `protobuf:"bytes,6,opt,name=payment_option_id,json=paymentOptionId,oneof"`
+}
+type PaymentInformation_UserPaymentOptionId struct {
+	UserPaymentOptionId string `protobuf:"bytes,7,opt,name=user_payment_option_id,json=userPaymentOptionId,oneof"`
+}
+
+func (*PaymentInformation_PaymentOptionId) isPaymentInformation_PaymentId()     {}
+func (*PaymentInformation_UserPaymentOptionId) isPaymentInformation_PaymentId() {}
+
+func (m *PaymentInformation) GetPaymentId() isPaymentInformation_PaymentId {
+	if m != nil {
+		return m.PaymentId
+	}
+	return nil
+}
+
+func (m *PaymentInformation) GetPrepaymentStatus() PrepaymentStatus {
+	if m != nil {
+		return m.PrepaymentStatus
+	}
+	return PrepaymentStatus_PREPAYMENT_STATUS_UNSPECIFIED
+}
+
+func (m *PaymentInformation) GetPaymentTransactionId() string {
+	if m != nil {
+		return m.PaymentTransactionId
+	}
+	return ""
+}
+
+func (m *PaymentInformation) GetPrice() *Price {
+	if m != nil {
+		return m.Price
+	}
+	return nil
+}
+
+func (m *PaymentInformation) GetTaxAmount() *Price {
+	if m != nil {
+		return m.TaxAmount
+	}
+	return nil
+}
+
+func (m *PaymentInformation) GetPaymentProcessedBy() PaymentInformation_PaymentProcessedBy {
+	if m != nil {
+		return m.PaymentProcessedBy
+	}
+	return PaymentInformation_PAYMENT_PROCESSED_BY_UNSPECIFIED
+}
+
+func (m *PaymentInformation) GetPaymentOptionId() string {
+	if x, ok := m.GetPaymentId().(*PaymentInformation_PaymentOptionId); ok {
+		return x.PaymentOptionId
+	}
+	return ""
+}
+
+func (m *PaymentInformation) GetUserPaymentOptionId() string {
+	if x, ok := m.GetPaymentId().(*PaymentInformation_UserPaymentOptionId); ok {
+		return x.UserPaymentOptionId
+	}
+	return ""
+}
+
+func (m *PaymentInformation) GetDeposit() *Deposit {
+	if m != nil {
+		return m.Deposit
+	}
+	return nil
+}
+
+func (m *PaymentInformation) GetNoShowFee() *NoShowFee {
+	if m != nil {
+		return m.NoShowFee
+	}
+	return nil
+}
+
+func (m *PaymentInformation) GetFeesAndTaxes() *Price {
+	if m != nil {
+		return m.FeesAndTaxes
+	}
+	return nil
+}
+
+// XXX_OneofFuncs is for the internal use of the proto package.
+func (*PaymentInformation) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) {
+	return _PaymentInformation_OneofMarshaler, _PaymentInformation_OneofUnmarshaler, _PaymentInformation_OneofSizer, []interface{}{
+		(*PaymentInformation_PaymentOptionId)(nil),
+		(*PaymentInformation_UserPaymentOptionId)(nil),
+	}
+}
+
+func _PaymentInformation_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
+	m := msg.(*PaymentInformation)
+	// payment_id
+	switch x := m.PaymentId.(type) {
+	case *PaymentInformation_PaymentOptionId:
+		b.EncodeVarint(6<<3 | proto.WireBytes)
+		b.EncodeStringBytes(x.PaymentOptionId)
+	case *PaymentInformation_UserPaymentOptionId:
+		b.EncodeVarint(7<<3 | proto.WireBytes)
+		b.EncodeStringBytes(x.UserPaymentOptionId)
+	case nil:
+	default:
+		return fmt.Errorf("PaymentInformation.PaymentId has unexpected type %T", x)
+	}
+	return nil
+}
+
+func _PaymentInformation_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) {
+	m := msg.(*PaymentInformation)
+	switch tag {
+	case 6: // payment_id.payment_option_id
+		if wire != proto.WireBytes {
+			return true, proto.ErrInternalBadWireType
+		}
+		x, err := b.DecodeStringBytes()
+		m.PaymentId = &PaymentInformation_PaymentOptionId{x}
+		return true, err
+	case 7: // payment_id.user_payment_option_id
+		if wire != proto.WireBytes {
+			return true, proto.ErrInternalBadWireType
+		}
+		x, err := b.DecodeStringBytes()
+		m.PaymentId = &PaymentInformation_UserPaymentOptionId{x}
+		return true, err
+	default:
+		return false, nil
+	}
+}
+
+func _PaymentInformation_OneofSizer(msg proto.Message) (n int) {
+	m := msg.(*PaymentInformation)
+	// payment_id
+	switch x := m.PaymentId.(type) {
+	case *PaymentInformation_PaymentOptionId:
+		n += proto.SizeVarint(6<<3 | proto.WireBytes)
+		n += proto.SizeVarint(uint64(len(x.PaymentOptionId)))
+		n += len(x.PaymentOptionId)
+	case *PaymentInformation_UserPaymentOptionId:
+		n += proto.SizeVarint(7<<3 | proto.WireBytes)
+		n += proto.SizeVarint(uint64(len(x.UserPaymentOptionId)))
+		n += len(x.UserPaymentOptionId)
+	case nil:
+	default:
+		panic(fmt.Sprintf("proto: unexpected type %T in oneof", x))
+	}
+	return n
+}
+
+// [START bookingfailure_definition]
+// Status data that conveys why (1) creating a lease or (2) creating or updating
+// a booking fails.
+// BookingFailure is intended to primarily capture business logic errors.
+type BookingFailure struct {
+	// The reason why the booking failed. (required)
+	Cause BookingFailure_Cause `protobuf:"varint,1,opt,name=cause,enum=v3.BookingFailure_Cause" json:"cause,omitempty"`
+	// (required only if cause is PAYMENT_ERROR_CARD_TYPE_REJECTED)
+	RejectedCardType CreditCardType `protobuf:"varint,2,opt,name=rejected_card_type,json=rejectedCardType,enum=v3.CreditCardType" json:"rejected_card_type,omitempty"`
+	// This optional field is used for the partner to include additional
+	// information for debugging purpose only. (optional)
+	Description string `protobuf:"bytes,3,opt,name=description" json:"description,omitempty"`
+}
+
+func (m *BookingFailure) Reset()                    { *m = BookingFailure{} }
+func (m *BookingFailure) String() string            { return proto.CompactTextString(m) }
+func (*BookingFailure) ProtoMessage()               {}
+func (*BookingFailure) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{19} }
+
+func (m *BookingFailure) GetCause() BookingFailure_Cause {
+	if m != nil {
+		return m.Cause
+	}
+	return BookingFailure_CAUSE_UNSPECIFIED
+}
+
+func (m *BookingFailure) GetRejectedCardType() CreditCardType {
+	if m != nil {
+		return m.RejectedCardType
+	}
+	return CreditCardType_CREDIT_CARD_TYPE_UNSPECIFIED
+}
+
+func (m *BookingFailure) GetDescription() string {
+	if m != nil {
+		return m.Description
+	}
+	return ""
+}
+
+// [START message_slot_availability]
+// An inventory slot and associated count of open spots.
+type SlotAvailability struct {
+	Slot *Slot `protobuf:"bytes,1,opt,name=slot" json:"slot,omitempty"`
+	// Number of available spots.
+	// 0 indicates that the appointment slot is not available. (required)
+	CountAvailable int32 `protobuf:"varint,2,opt,name=count_available,json=countAvailable" json:"count_available,omitempty"`
+}
+
+func (m *SlotAvailability) Reset()                    { *m = SlotAvailability{} }
+func (m *SlotAvailability) String() string            { return proto.CompactTextString(m) }
+func (*SlotAvailability) ProtoMessage()               {}
+func (*SlotAvailability) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{20} }
+
+func (m *SlotAvailability) GetSlot() *Slot {
+	if m != nil {
+		return m.Slot
+	}
+	return nil
+}
+
+func (m *SlotAvailability) GetCountAvailable() int32 {
+	if m != nil {
+		return m.CountAvailable
+	}
+	return 0
+}
+
+// [START message_availability_update]
+// An update to one ore more slots indicating that the availability for the
+// associated time has potentially changed.
+type AvailabilityUpdate struct {
+	SlotAvailability []*SlotAvailability `protobuf:"bytes,1,rep,name=slot_availability,json=slotAvailability" json:"slot_availability,omitempty"`
+}
+
+func (m *AvailabilityUpdate) Reset()                    { *m = AvailabilityUpdate{} }
+func (m *AvailabilityUpdate) String() string            { return proto.CompactTextString(m) }
+func (*AvailabilityUpdate) ProtoMessage()               {}
+func (*AvailabilityUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{21} }
+
+func (m *AvailabilityUpdate) GetSlotAvailability() []*SlotAvailability {
+	if m != nil {
+		return m.SlotAvailability
+	}
+	return nil
+}
+
+// [START resources_definition]
+// Resource specification that disambiguates an appointment slot
+type ResourceIds struct {
+	// The staff ID as provided in the feed or empty if not applicable or no staff
+	// was selected. (optional)
+	StaffId string `protobuf:"bytes,1,opt,name=staff_id,json=staffId" json:"staff_id,omitempty"`
+	// The room ID as provided in the feed or empty if not applicable or no room
+	// was selected. (optional)
+	RoomId string `protobuf:"bytes,2,opt,name=room_id,json=roomId" json:"room_id,omitempty"`
+	// For Dining Reservations only: the number of seats requested in the booking.
+	// (optional)
+	PartySize int32 `protobuf:"varint,3,opt,name=party_size,json=partySize" json:"party_size,omitempty"`
+}
+
+func (m *ResourceIds) Reset()                    { *m = ResourceIds{} }
+func (m *ResourceIds) String() string            { return proto.CompactTextString(m) }
+func (*ResourceIds) ProtoMessage()               {}
+func (*ResourceIds) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{22} }
+
+func (m *ResourceIds) GetStaffId() string {
+	if m != nil {
+		return m.StaffId
+	}
+	return ""
+}
+
+func (m *ResourceIds) GetRoomId() string {
+	if m != nil {
+		return m.RoomId
+	}
+	return ""
+}
+
+func (m *ResourceIds) GetPartySize() int32 {
+	if m != nil {
+		return m.PartySize
+	}
+	return 0
+}
+
+// [START tickettype_definition]
+// TicketType is used to differentiate among tickets (where a ticket can be a
+// spot on a raft trip, an admission to a museum, etc.) with different prices
+// and/or availabilities due to different user types or different service
+// attributes.
+type TicketType struct {
+	// The ticket id is used to differentiate among different ticket types of the
+	// same service, and is only expected to be unique within a service.
+	TicketTypeId string `protobuf:"bytes,1,opt,name=ticket_type_id,json=ticketTypeId" json:"ticket_type_id,omitempty"`
+	// This can be user visible, e.g., “adult”, "child", “veteran”, “Row J”, etc.
+	ShortDescription string `protobuf:"bytes,2,opt,name=short_description,json=shortDescription" json:"short_description,omitempty"`
+	// The price of a single ticket of this type, exclusive of any taxes. The tax
+	// rate of Service is applied to its tickets.
+	Price *Price `protobuf:"bytes,3,opt,name=price" json:"price,omitempty"`
+}
+
+func (m *TicketType) Reset()                    { *m = TicketType{} }
+func (m *TicketType) String() string            { return proto.CompactTextString(m) }
+func (*TicketType) ProtoMessage()               {}
+func (*TicketType) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{23} }
+
+func (m *TicketType) GetTicketTypeId() string {
+	if m != nil {
+		return m.TicketTypeId
+	}
+	return ""
+}
+
+func (m *TicketType) GetShortDescription() string {
+	if m != nil {
+		return m.ShortDescription
+	}
+	return ""
+}
+
+func (m *TicketType) GetPrice() *Price {
+	if m != nil {
+		return m.Price
+	}
+	return nil
+}
+
+// [START lineitem_definition]
+// A single item in an order--the booking of a single service in a single time
+// slot.
+type LineItem struct {
+	// ID of the merchant service. (required)
+	ServiceId string `protobuf:"bytes,1,opt,name=service_id,json=serviceId" json:"service_id,omitempty"`
+	// Start time of the appointment slot in seconds of UTC time since Unix epoch.
+	// (required)
+	StartSec int64 `protobuf:"varint,2,opt,name=start_sec,json=startSec" json:"start_sec,omitempty"`
+	// Duration of the appointment slot in seconds. (required)
+	DurationSec int64 `protobuf:"varint,3,opt,name=duration_sec,json=durationSec" json:"duration_sec,omitempty"`
+	// Number of tickets ordered by type.
+	Tickets []*LineItem_OrderedTickets `protobuf:"bytes,4,rep,name=tickets" json:"tickets,omitempty"`
+	// In handling CreateOrderRequest and CheckOrderFulfillabilityRequest,
+	// the total price (excluding taxes) of the item must be verified to guard
+	// against price changes. In CreateOrderResponse and
+	// CheckOrderFulfillabilityResponse, the price should be updated to the
+	// correct value if the value from the request was incorrect or outdated.
+	// (reqired)
+	Price *Price `protobuf:"bytes,5,opt,name=price" json:"price,omitempty"`
+	// Status of the line item. (required in CreateOrderResponse and
+	// ListOrdersResponse; should not be set in requests)
+	Status BookingStatus `protobuf:"varint,6,opt,name=status,enum=v3.BookingStatus" json:"status,omitempty"`
+}
+
+func (m *LineItem) Reset()                    { *m = LineItem{} }
+func (m *LineItem) String() string            { return proto.CompactTextString(m) }
+func (*LineItem) ProtoMessage()               {}
+func (*LineItem) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{24} }
+
+func (m *LineItem) GetServiceId() string {
+	if m != nil {
+		return m.ServiceId
+	}
+	return ""
+}
+
+func (m *LineItem) GetStartSec() int64 {
+	if m != nil {
+		return m.StartSec
+	}
+	return 0
+}
+
+func (m *LineItem) GetDurationSec() int64 {
+	if m != nil {
+		return m.DurationSec
+	}
+	return 0
+}
+
+func (m *LineItem) GetTickets() []*LineItem_OrderedTickets {
+	if m != nil {
+		return m.Tickets
+	}
+	return nil
+}
+
+func (m *LineItem) GetPrice() *Price {
+	if m != nil {
+		return m.Price
+	}
+	return nil
+}
+
+func (m *LineItem) GetStatus() BookingStatus {
+	if m != nil {
+		return m.Status
+	}
+	return BookingStatus_BOOKING_STATUS_UNSPECIFIED
+}
+
+type LineItem_OrderedTickets struct {
+	TicketId string `protobuf:"bytes,1,opt,name=ticket_id,json=ticketId" json:"ticket_id,omitempty"`
+	Count    int32  `protobuf:"varint,2,opt,name=count" json:"count,omitempty"`
+}
+
+func (m *LineItem_OrderedTickets) Reset()                    { *m = LineItem_OrderedTickets{} }
+func (m *LineItem_OrderedTickets) String() string            { return proto.CompactTextString(m) }
+func (*LineItem_OrderedTickets) ProtoMessage()               {}
+func (*LineItem_OrderedTickets) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{24, 0} }
+
+func (m *LineItem_OrderedTickets) GetTicketId() string {
+	if m != nil {
+		return m.TicketId
+	}
+	return ""
+}
+
+func (m *LineItem_OrderedTickets) GetCount() int32 {
+	if m != nil {
+		return m.Count
+	}
+	return 0
+}
+
+// [START lineitemfulfillability_definition]
+// Fulfillability of a line item.
+type LineItemFulfillability struct {
+	// The line item of question. (required)
+	Item *LineItem `protobuf:"bytes,1,opt,name=item" json:"item,omitempty"`
+	// (required)
+	Result LineItemFulfillability_ItemFulfillabilityResult `protobuf:"varint,2,opt,name=result,enum=v3.LineItemFulfillability_ItemFulfillabilityResult" json:"result,omitempty"`
+	// Additional description of the reason if the item is unfulfillable.
+	// (optional)
+	UnfulfillableReason string `protobuf:"bytes,3,opt,name=unfulfillable_reason,json=unfulfillableReason" json:"unfulfillable_reason,omitempty"`
+	// Updated availability for this slot can be piggybacked in
+	// CheckOrderFulfillabilityResponse. (optional)
+	SpotsOpen int32 `protobuf:"varint,4,opt,name=spots_open,json=spotsOpen" json:"spots_open,omitempty"`
+	// Updated ticket types can be piggybacked in
+	// CheckOrderFulfillabilityResponse. If non-empty, all available ticket types
+	// for this slot with up-to-date prices should be listed without omitting any.
+	// (optional)
+	TicketType []*TicketType `protobuf:"bytes,5,rep,name=ticket_type,json=ticketType" json:"ticket_type,omitempty"`
+}
+
+func (m *LineItemFulfillability) Reset()                    { *m = LineItemFulfillability{} }
+func (m *LineItemFulfillability) String() string            { return proto.CompactTextString(m) }
+func (*LineItemFulfillability) ProtoMessage()               {}
+func (*LineItemFulfillability) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{25} }
+
+func (m *LineItemFulfillability) GetItem() *LineItem {
+	if m != nil {
+		return m.Item
+	}
+	return nil
+}
+
+func (m *LineItemFulfillability) GetResult() LineItemFulfillability_ItemFulfillabilityResult {
+	if m != nil {
+		return m.Result
+	}
+	return LineItemFulfillability_ITEM_FULFILLABILITY_RESULT_UNSPECIFIED
+}
+
+func (m *LineItemFulfillability) GetUnfulfillableReason() string {
+	if m != nil {
+		return m.UnfulfillableReason
+	}
+	return ""
+}
+
+func (m *LineItemFulfillability) GetSpotsOpen() int32 {
+	if m != nil {
+		return m.SpotsOpen
+	}
+	return 0
+}
+
+func (m *LineItemFulfillability) GetTicketType() []*TicketType {
+	if m != nil {
+		return m.TicketType
+	}
+	return nil
+}
+
+// [START orderfulfillability_definition]
+type OrderFulfillability struct {
+	Result OrderFulfillability_OrderFulfillabilityResult `protobuf:"varint,1,opt,name=result,enum=v3.OrderFulfillability_OrderFulfillabilityResult" json:"result,omitempty"`
+	// Fulfillability results of all line items in this order (required).
+	ItemFulfillability []*LineItemFulfillability `protobuf:"bytes,2,rep,name=item_fulfillability,json=itemFulfillability" json:"item_fulfillability,omitempty"`
+	// Additional description of the reason if the item is unfulfillable.
+	// (optional)
+	UnfulfillableReason string `protobuf:"bytes,3,opt,name=unfulfillable_reason,json=unfulfillableReason" json:"unfulfillable_reason,omitempty"`
+}
+
+func (m *OrderFulfillability) Reset()                    { *m = OrderFulfillability{} }
+func (m *OrderFulfillability) String() string            { return proto.CompactTextString(m) }
+func (*OrderFulfillability) ProtoMessage()               {}
+func (*OrderFulfillability) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{26} }
+
+func (m *OrderFulfillability) GetResult() OrderFulfillability_OrderFulfillabilityResult {
+	if m != nil {
+		return m.Result
+	}
+	return OrderFulfillability_ORDER_FULFILLABILITY_RESULT_UNSPECIFIED
+}
+
+func (m *OrderFulfillability) GetItemFulfillability() []*LineItemFulfillability {
+	if m != nil {
+		return m.ItemFulfillability
+	}
+	return nil
+}
+
+func (m *OrderFulfillability) GetUnfulfillableReason() string {
+	if m != nil {
+		return m.UnfulfillableReason
+	}
+	return ""
+}
+
+// [START order_definition]
+// An order for service appointments with a merchant.
+type Order struct {
+	// ID of this order, chosen by the booking partner who handles the order
+	// (required in CreateOrderResponse and ListOrdersResponse, must not be set in
+	// CreateOrderRequest)
+	OrderId string `protobuf:"bytes,1,opt,name=order_id,json=orderId" json:"order_id,omitempty"`
+	// Personal information of the user making the order (required)
+	UserInformation *UserInformation `protobuf:"bytes,2,opt,name=user_information,json=userInformation" json:"user_information,omitempty"`
+	// Information about payment transactions that relate to the order.
+	// (optional)
+	PaymentInformation *PaymentInformation `protobuf:"bytes,3,opt,name=payment_information,json=paymentInformation" json:"payment_information,omitempty"`
+	// The merchant that all services in this order belong to.
+	MerchantId string `protobuf:"bytes,4,opt,name=merchant_id,json=merchantId" json:"merchant_id,omitempty"`
+	// Line items in this order.
+	Item []*LineItem `protobuf:"bytes,5,rep,name=item" json:"item,omitempty"`
+}
+
+func (m *Order) Reset()                    { *m = Order{} }
+func (m *Order) String() string            { return proto.CompactTextString(m) }
+func (*Order) ProtoMessage()               {}
+func (*Order) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{27} }
+
+func (m *Order) GetOrderId() string {
+	if m != nil {
+		return m.OrderId
+	}
+	return ""
+}
+
+func (m *Order) GetUserInformation() *UserInformation {
+	if m != nil {
+		return m.UserInformation
+	}
+	return nil
+}
+
+func (m *Order) GetPaymentInformation() *PaymentInformation {
+	if m != nil {
+		return m.PaymentInformation
+	}
+	return nil
+}
+
+func (m *Order) GetMerchantId() string {
+	if m != nil {
+		return m.MerchantId
+	}
+	return ""
+}
+
+func (m *Order) GetItem() []*LineItem {
+	if m != nil {
+		return m.Item
+	}
+	return nil
+}
+
+// [START orderfailure_definition]
+// Status data that conveys why creating an order fails.
+// OrderFailure is intended to primarily capture business logic errors.
+type OrderFailure struct {
+	// The reason why the order failed. (required)
+	Cause OrderFailure_Cause `protobuf:"varint,1,opt,name=cause,enum=v3.OrderFailure_Cause" json:"cause,omitempty"`
+	// (required only if cause is ORDER_UNFULFILLABLE)
+	Fulfillability *OrderFulfillability `protobuf:"bytes,2,opt,name=fulfillability" json:"fulfillability,omitempty"`
+	// (required only if cause is PAYMENT_ERROR_CARD_TYPE_REJECTED)
+	RejectedCardType CreditCardType `protobuf:"varint,3,opt,name=rejected_card_type,json=rejectedCardType,enum=v3.CreditCardType" json:"rejected_card_type,omitempty"`
+	// This optional field is used for the partner to include additional
+	// information for debugging purpose only. (optional)
+	Description string `protobuf:"bytes,4,opt,name=description" json:"description,omitempty"`
+}
+
+func (m *OrderFailure) Reset()                    { *m = OrderFailure{} }
+func (m *OrderFailure) String() string            { return proto.CompactTextString(m) }
+func (*OrderFailure) ProtoMessage()               {}
+func (*OrderFailure) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{28} }
+
+func (m *OrderFailure) GetCause() OrderFailure_Cause {
+	if m != nil {
+		return m.Cause
+	}
+	return OrderFailure_CAUSE_UNSPECIFIED
+}
+
+func (m *OrderFailure) GetFulfillability() *OrderFulfillability {
+	if m != nil {
+		return m.Fulfillability
+	}
+	return nil
+}
+
+func (m *OrderFailure) GetRejectedCardType() CreditCardType {
+	if m != nil {
+		return m.RejectedCardType
+	}
+	return CreditCardType_CREDIT_CARD_TYPE_UNSPECIFIED
+}
+
+func (m *OrderFailure) GetDescription() string {
+	if m != nil {
+		return m.Description
+	}
+	return ""
+}
+
+// [START method_check_availability]
+// Request to check availability for a Slot.
+type CheckAvailabilityRequest struct {
+	// The appointment slot that is being checked (required)
+	Slot *Slot `protobuf:"bytes,1,opt,name=slot" json:"slot,omitempty"`
+}
+
+func (m *CheckAvailabilityRequest) Reset()                    { *m = CheckAvailabilityRequest{} }
+func (m *CheckAvailabilityRequest) String() string            { return proto.CompactTextString(m) }
+func (*CheckAvailabilityRequest) ProtoMessage()               {}
+func (*CheckAvailabilityRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{29} }
+
+func (m *CheckAvailabilityRequest) GetSlot() *Slot {
+	if m != nil {
+		return m.Slot
+	}
+	return nil
+}
+
+// Response for the CheckAvailability RPC with the availability of the
+// appointment slot.
+type CheckAvailabilityResponse struct {
+	// The requested slot. (required)
+	Slot *Slot `protobuf:"bytes,1,opt,name=slot" json:"slot,omitempty"`
+	// Number of available spots.
+	// 0 indicates that the appointment slot is not available. (required)
+	CountAvailable int32 `protobuf:"varint,2,opt,name=count_available,json=countAvailable" json:"count_available,omitempty"`
+	// The requirement to show the slots duration and/or endtime. This field will
+	// be ignored if the slot is unavailable. (optional)
+	DurationRequirement CheckAvailabilityResponse_DurationRequirement `protobuf:"varint,3,opt,name=duration_requirement,json=durationRequirement,enum=v3.CheckAvailabilityResponse_DurationRequirement" json:"duration_requirement,omitempty"`
+	// Optionally, the partner can return additional updated information about the
+	// availability for this merchant if this information is present when
+	// responding to the CheckAvailabilityRequest and if there is no negative
+	// impact on the CheckAvailability request latency.
+	// For instance an entire day of merchant availability for a superset of
+	// resources can be returned here.
+	AvailabilityUpdate *AvailabilityUpdate `protobuf:"bytes,4,opt,name=availability_update,json=availabilityUpdate" json:"availability_update,omitempty"`
+}
+
+func (m *CheckAvailabilityResponse) Reset()                    { *m = CheckAvailabilityResponse{} }
+func (m *CheckAvailabilityResponse) String() string            { return proto.CompactTextString(m) }
+func (*CheckAvailabilityResponse) ProtoMessage()               {}
+func (*CheckAvailabilityResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{30} }
+
+func (m *CheckAvailabilityResponse) GetSlot() *Slot {
+	if m != nil {
+		return m.Slot
+	}
+	return nil
+}
+
+func (m *CheckAvailabilityResponse) GetCountAvailable() int32 {
+	if m != nil {
+		return m.CountAvailable
+	}
+	return 0
+}
+
+func (m *CheckAvailabilityResponse) GetDurationRequirement() CheckAvailabilityResponse_DurationRequirement {
+	if m != nil {
+		return m.DurationRequirement
+	}
+	return CheckAvailabilityResponse_DURATION_REQUIREMENT_UNSPECIFIED
+}
+
+func (m *CheckAvailabilityResponse) GetAvailabilityUpdate() *AvailabilityUpdate {
+	if m != nil {
+		return m.AvailabilityUpdate
+	}
+	return nil
+}
+
+// [START method_get_booking_status]
+// Request to get booking status and prepayment status for a Booking.
+type GetBookingStatusRequest struct {
+	// ID of the existing booking (required)
+	BookingId string `protobuf:"bytes,1,opt,name=booking_id,json=bookingId" json:"booking_id,omitempty"`
+}
+
+func (m *GetBookingStatusRequest) Reset()                    { *m = GetBookingStatusRequest{} }
+func (m *GetBookingStatusRequest) String() string            { return proto.CompactTextString(m) }
+func (*GetBookingStatusRequest) ProtoMessage()               {}
+func (*GetBookingStatusRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{31} }
+
+func (m *GetBookingStatusRequest) GetBookingId() string {
+	if m != nil {
+		return m.BookingId
+	}
+	return ""
+}
+
+// Response for the GetBookingStatus RPC with booking status and prepayment
+// status.
+type GetBookingStatusResponse struct {
+	// ID of the booking (required)
+	BookingId string `protobuf:"bytes,1,opt,name=booking_id,json=bookingId" json:"booking_id,omitempty"`
+	// Status of the booking (required)
+	BookingStatus BookingStatus `protobuf:"varint,2,opt,name=booking_status,json=bookingStatus,enum=v3.BookingStatus" json:"booking_status,omitempty"`
+	// Prepayment status of the booking (required)
+	PrepaymentStatus PrepaymentStatus `protobuf:"varint,3,opt,name=prepayment_status,json=prepaymentStatus,enum=v3.PrepaymentStatus" json:"prepayment_status,omitempty"`
+}
+
+func (m *GetBookingStatusResponse) Reset()                    { *m = GetBookingStatusResponse{} }
+func (m *GetBookingStatusResponse) String() string            { return proto.CompactTextString(m) }
+func (*GetBookingStatusResponse) ProtoMessage()               {}
+func (*GetBookingStatusResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{32} }
+
+func (m *GetBookingStatusResponse) GetBookingId() string {
+	if m != nil {
+		return m.BookingId
+	}
+	return ""
+}
+
+func (m *GetBookingStatusResponse) GetBookingStatus() BookingStatus {
+	if m != nil {
+		return m.BookingStatus
+	}
+	return BookingStatus_BOOKING_STATUS_UNSPECIFIED
+}
+
+func (m *GetBookingStatusResponse) GetPrepaymentStatus() PrepaymentStatus {
+	if m != nil {
+		return m.PrepaymentStatus
+	}
+	return PrepaymentStatus_PREPAYMENT_STATUS_UNSPECIFIED
+}
+
+// [START method_check_order_fulfillability]
+// Request to check the fulfillability of an order.
+type CheckOrderFulfillabilityRequest struct {
+	// The merchant that this order is intended for. (required)
+	MerchantId string `protobuf:"bytes,1,opt,name=merchant_id,json=merchantId" json:"merchant_id,omitempty"`
+	// The line items in this order. All services requested must belong to the
+	// specified merchant. (required)
+	Item []*LineItem `protobuf:"bytes,2,rep,name=item" json:"item,omitempty"`
+}
+
+func (m *CheckOrderFulfillabilityRequest) Reset()         { *m = CheckOrderFulfillabilityRequest{} }
+func (m *CheckOrderFulfillabilityRequest) String() string { return proto.CompactTextString(m) }
+func (*CheckOrderFulfillabilityRequest) ProtoMessage()    {}
+func (*CheckOrderFulfillabilityRequest) Descriptor() ([]byte, []int) {
+	return fileDescriptor0, []int{33}
+}
+
+func (m *CheckOrderFulfillabilityRequest) GetMerchantId() string {
+	if m != nil {
+		return m.MerchantId
+	}
+	return ""
+}
+
+func (m *CheckOrderFulfillabilityRequest) GetItem() []*LineItem {
+	if m != nil {
+		return m.Item
+	}
+	return nil
+}
+
+// Response for the CheckOrderfulfillabilityRequest.
+type CheckOrderFulfillabilityResponse struct {
+	// Fulfillability status of the order, potentially contains updated
+	// availabilities and prices of the requested line item. (required)
+	Fulfillability *OrderFulfillability `protobuf:"bytes,1,opt,name=fulfillability" json:"fulfillability,omitempty"`
+	// Total processing fees & taxes that need to be paid for this order.
+	// (required)
+	FeesAndTaxes *Price `protobuf:"bytes,2,opt,name=fees_and_taxes,json=feesAndTaxes" json:"fees_and_taxes,omitempty"`
+}
+
+func (m *CheckOrderFulfillabilityResponse) Reset()         { *m = CheckOrderFulfillabilityResponse{} }
+func (m *CheckOrderFulfillabilityResponse) String() string { return proto.CompactTextString(m) }
+func (*CheckOrderFulfillabilityResponse) ProtoMessage()    {}
+func (*CheckOrderFulfillabilityResponse) Descriptor() ([]byte, []int) {
+	return fileDescriptor0, []int{34}
+}
+
+func (m *CheckOrderFulfillabilityResponse) GetFulfillability() *OrderFulfillability {
+	if m != nil {
+		return m.Fulfillability
+	}
+	return nil
+}
+
+func (m *CheckOrderFulfillabilityResponse) GetFeesAndTaxes() *Price {
+	if m != nil {
+		return m.FeesAndTaxes
+	}
+	return nil
+}
+
+// [START method_create_booking]
+// Request to create a Booking for an inventory slot. Consumes the lease if
+// provided.
+type CreateBookingRequest struct {
+	// The inventory slot that is being requested to make this booking.
+	// If lease_ref is provided, slot must match the lease; slot is provided for
+	// the partner to verify the lease information.
+	// If lease_ref is absent, then create the booking for the slot. (required)
+	Slot *Slot `protobuf:"bytes,1,opt,name=slot" json:"slot,omitempty"`
+	// The lease that is being confirmed to make this booking.
+	// If lease_ref is provided, then create the booking using the lease.
+	// (optional)
+	LeaseRef *LeaseReference `protobuf:"bytes,2,opt,name=lease_ref,json=leaseRef" json:"lease_ref,omitempty"`
+	// Personal information of the user making the appointment (required)
+	UserInformation *UserInformation `protobuf:"bytes,3,opt,name=user_information,json=userInformation" json:"user_information,omitempty"`
+	// Information about payments. When payment authorizations are handled by
+	// Google, if the booking request does not succeed, payment authorizations are
+	// automatically canceled. (optional)
+	PaymentInformation *PaymentInformation `protobuf:"bytes,4,opt,name=payment_information,json=paymentInformation" json:"payment_information,omitempty"`
+	// The parameters to be used if the payment is processed by the partner
+	// (i.e. payment_information.payment_processed_by is equal to
+	// PROCESSED_BY_PARTNER). (optional)
+	PaymentProcessingParameters *PaymentProcessingParameters `protobuf:"bytes,5,opt,name=payment_processing_parameters,json=paymentProcessingParameters" json:"payment_processing_parameters,omitempty"`
+	// Idempotency token for CreateBooking requests. (required)
+	IdempotencyToken string `protobuf:"bytes,6,opt,name=idempotency_token,json=idempotencyToken" json:"idempotency_token,omitempty"`
+	// A string from the user which contains any special requests or additional
+	// information that they would like to notify the merchant about. (optional)
+	AdditionalRequest string `protobuf:"bytes,7,opt,name=additional_request,json=additionalRequest" json:"additional_request,omitempty"`
+}
+
+func (m *CreateBookingRequest) Reset()                    { *m = CreateBookingRequest{} }
+func (m *CreateBookingRequest) String() string            { return proto.CompactTextString(m) }
+func (*CreateBookingRequest) ProtoMessage()               {}
+func (*CreateBookingRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{35} }
+
+func (m *CreateBookingRequest) GetSlot() *Slot {
+	if m != nil {
+		return m.Slot
+	}
+	return nil
+}
+
+func (m *CreateBookingRequest) GetLeaseRef() *LeaseReference {
+	if m != nil {
+		return m.LeaseRef
+	}
+	return nil
+}
+
+func (m *CreateBookingRequest) GetUserInformation() *UserInformation {
+	if m != nil {
+		return m.UserInformation
+	}
+	return nil
+}
+
+func (m *CreateBookingRequest) GetPaymentInformation() *PaymentInformation {
+	if m != nil {
+		return m.PaymentInformation
+	}
+	return nil
+}
+
+func (m *CreateBookingRequest) GetPaymentProcessingParameters() *PaymentProcessingParameters {
+	if m != nil {
+		return m.PaymentProcessingParameters
+	}
+	return nil
+}
+
+func (m *CreateBookingRequest) GetIdempotencyToken() string {
+	if m != nil {
+		return m.IdempotencyToken
+	}
+	return ""
+}
+
+func (m *CreateBookingRequest) GetAdditionalRequest() string {
+	if m != nil {
+		return m.AdditionalRequest
+	}
+	return ""
+}
+
+// Response with the created Booking for an inventory slot.
+type CreateBookingResponse struct {
+	// The created booking (required)
+	Booking *Booking `protobuf:"bytes,1,opt,name=booking" json:"booking,omitempty"`
+	// The updated user payment option used in this booking.
+	// If a new payment option was purchased to pay for the booking, this should
+	// be a newly created user payment option.
+	// If an already purchased user payment option was used for this booking,
+	// this should reflect an updated version of that user payment option.
+	// (optional)
+	UserPaymentOption *UserPaymentOption `protobuf:"bytes,2,opt,name=user_payment_option,json=userPaymentOption" json:"user_payment_option,omitempty"`
+	// If creating a booking fails, this field should reflect the business logic
+	// error (e.g., slot has become unavailable) and all other fields in the
+	// CreateBookingResponse message are expected to be unset. (required if
+	// failure occurs)
+	BookingFailure *BookingFailure `protobuf:"bytes,3,opt,name=booking_failure,json=bookingFailure" json:"booking_failure,omitempty"`
+}
+
+func (m *CreateBookingResponse) Reset()                    { *m = CreateBookingResponse{} }
+func (m *CreateBookingResponse) String() string            { return proto.CompactTextString(m) }
+func (*CreateBookingResponse) ProtoMessage()               {}
+func (*CreateBookingResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{36} }
+
+func (m *CreateBookingResponse) GetBooking() *Booking {
+	if m != nil {
+		return m.Booking
+	}
+	return nil
+}
+
+func (m *CreateBookingResponse) GetUserPaymentOption() *UserPaymentOption {
+	if m != nil {
+		return m.UserPaymentOption
+	}
+	return nil
+}
+
+func (m *CreateBookingResponse) GetBookingFailure() *BookingFailure {
+	if m != nil {
+		return m.BookingFailure
+	}
+	return nil
+}
+
+// [START method_create_order]
+// Request to create an order.
+type CreateOrderRequest struct {
+	// The order to create. (required)
+	Order *Order `protobuf:"bytes,1,opt,name=order" json:"order,omitempty"`
+	// The parameters to be used if the payment is processed by the partner
+	// (i.e. order.payment_information.payment_processed_by is equal to
+	// PROCESSED_BY_PARTNER). (required if payment is processed by the partner)
+	PaymentProcessingParameters *PaymentProcessingParameters `protobuf:"bytes,2,opt,name=payment_processing_parameters,json=paymentProcessingParameters" json:"payment_processing_parameters,omitempty"`
+	// Idempotency token for CreateOrder requests. (required)
+	IdempotencyToken string `protobuf:"bytes,3,opt,name=idempotency_token,json=idempotencyToken" json:"idempotency_token,omitempty"`
+}
+
+func (m *CreateOrderRequest) Reset()                    { *m = CreateOrderRequest{} }
+func (m *CreateOrderRequest) String() string            { return proto.CompactTextString(m) }
+func (*CreateOrderRequest) ProtoMessage()               {}
+func (*CreateOrderRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{37} }
+
+func (m *CreateOrderRequest) GetOrder() *Order {
+	if m != nil {
+		return m.Order
+	}
+	return nil
+}
+
+func (m *CreateOrderRequest) GetPaymentProcessingParameters() *PaymentProcessingParameters {
+	if m != nil {
+		return m.PaymentProcessingParameters
+	}
+	return nil
+}
+
+func (m *CreateOrderRequest) GetIdempotencyToken() string {
+	if m != nil {
+		return m.IdempotencyToken
+	}
+	return ""
+}
+
+// Response for the CreateOrderRequest.
+type CreateOrderResponse struct {
+	// The order created. (required)
+	Order *Order `protobuf:"bytes,1,opt,name=order" json:"order,omitempty"`
+	// If creating an order fails, this field should reflect the business logic
+	// error (e.g., slot has become unavailable or price has changed) and all
+	// other fields in the CreateOrderResponse are expected to be unset. (required
+	// if failure occurs)
+	OrderFailure *OrderFailure `protobuf:"bytes,2,opt,name=order_failure,json=orderFailure" json:"order_failure,omitempty"`
+}
+
+func (m *CreateOrderResponse) Reset()                    { *m = CreateOrderResponse{} }
+func (m *CreateOrderResponse) String() string            { return proto.CompactTextString(m) }
+func (*CreateOrderResponse) ProtoMessage()               {}
+func (*CreateOrderResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{38} }
+
+func (m *CreateOrderResponse) GetOrder() *Order {
+	if m != nil {
+		return m.Order
+	}
+	return nil
+}
+
+func (m *CreateOrderResponse) GetOrderFailure() *OrderFailure {
+	if m != nil {
+		return m.OrderFailure
+	}
+	return nil
+}
+
+// [START method_create_lease]
+// Request to create a Leaese for a slot in the inventory.  The expiration time
+// in the returned Lease may be modified by the backend, e.g. if the requested
+// lease period is too long.
+type CreateLeaseRequest struct {
+	// The lease to be created with information about the appointment slot
+	// (required)
+	Lease *Lease `protobuf:"bytes,1,opt,name=lease" json:"lease,omitempty"`
+}
+
+func (m *CreateLeaseRequest) Reset()                    { *m = CreateLeaseRequest{} }
+func (m *CreateLeaseRequest) String() string            { return proto.CompactTextString(m) }
+func (*CreateLeaseRequest) ProtoMessage()               {}
+func (*CreateLeaseRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{39} }
+
+func (m *CreateLeaseRequest) GetLease() *Lease {
+	if m != nil {
+		return m.Lease
+	}
+	return nil
+}
+
+// Response for the CreateLease RPC with the created Lease.
+type CreateLeaseResponse struct {
+	// The created Lease (required)
+	Lease *Lease `protobuf:"bytes,1,opt,name=lease" json:"lease,omitempty"`
+	// If creating a lease fails, this field should reflect the business logic
+	// error (e.g., slot has become unavailable) and lease field is expected to be
+	// unset. (required if failure occurs)
+	BookingFailure *BookingFailure `protobuf:"bytes,2,opt,name=booking_failure,json=bookingFailure" json:"booking_failure,omitempty"`
+}
+
+func (m *CreateLeaseResponse) Reset()                    { *m = CreateLeaseResponse{} }
+func (m *CreateLeaseResponse) String() string            { return proto.CompactTextString(m) }
+func (*CreateLeaseResponse) ProtoMessage()               {}
+func (*CreateLeaseResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{40} }
+
+func (m *CreateLeaseResponse) GetLease() *Lease {
+	if m != nil {
+		return m.Lease
+	}
+	return nil
+}
+
+func (m *CreateLeaseResponse) GetBookingFailure() *BookingFailure {
+	if m != nil {
+		return m.BookingFailure
+	}
+	return nil
+}
+
+// [START method_list_bookings]
+// Request to list all bookings for a user
+type ListBookingsRequest struct {
+	// ID of the user (required)
+	UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"`
+}
+
+func (m *ListBookingsRequest) Reset()                    { *m = ListBookingsRequest{} }
+func (m *ListBookingsRequest) String() string            { return proto.CompactTextString(m) }
+func (*ListBookingsRequest) ProtoMessage()               {}
+func (*ListBookingsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{41} }
+
+func (m *ListBookingsRequest) GetUserId() string {
+	if m != nil {
+		return m.UserId
+	}
+	return ""
+}
+
+// Response for the ListBookings RPC with all bookings for the requested user.
+type ListBookingsResponse struct {
+	// All bookings of the user (required)
+	Bookings []*Booking `protobuf:"bytes,1,rep,name=bookings" json:"bookings,omitempty"`
+}
+
+func (m *ListBookingsResponse) Reset()                    { *m = ListBookingsResponse{} }
+func (m *ListBookingsResponse) String() string            { return proto.CompactTextString(m) }
+func (*ListBookingsResponse) ProtoMessage()               {}
+func (*ListBookingsResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{42} }
+
+func (m *ListBookingsResponse) GetBookings() []*Booking {
+	if m != nil {
+		return m.Bookings
+	}
+	return nil
+}
+
+// [START method_list_orders]
+// Request to list orders.
+type ListOrdersRequest struct {
+	// ID of the user (required only if order_id is not set).
+	UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"`
+	// If set, return only the specified orders; otherwise, return all orders of
+	// the user. (required only if user_id is not set).
+	OrderId []string `protobuf:"bytes,2,rep,name=order_id,json=orderId" json:"order_id,omitempty"`
+}
+
+func (m *ListOrdersRequest) Reset()                    { *m = ListOrdersRequest{} }
+func (m *ListOrdersRequest) String() string            { return proto.CompactTextString(m) }
+func (*ListOrdersRequest) ProtoMessage()               {}
+func (*ListOrdersRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{43} }
+
+func (m *ListOrdersRequest) GetUserId() string {
+	if m != nil {
+		return m.UserId
+	}
+	return ""
+}
+
+func (m *ListOrdersRequest) GetOrderId() []string {
+	if m != nil {
+		return m.OrderId
+	}
+	return nil
+}
+
+// Response for the ListOrders RPC.
+type ListOrdersResponse struct {
+	// All requested orders (required)
+	Order []*Order `protobuf:"bytes,1,rep,name=order" json:"order,omitempty"`
+}
+
+func (m *ListOrdersResponse) Reset()                    { *m = ListOrdersResponse{} }
+func (m *ListOrdersResponse) String() string            { return proto.CompactTextString(m) }
+func (*ListOrdersResponse) ProtoMessage()               {}
+func (*ListOrdersResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{44} }
+
+func (m *ListOrdersResponse) GetOrder() []*Order {
+	if m != nil {
+		return m.Order
+	}
+	return nil
+}
+
+// [START method_update_booking]
+// Request to update a Booking.
+type UpdateBookingRequest struct {
+	// The booking to be updated
+	// The following fields can be set in a booking:
+	// - status, to cancel a booking.
+	// - start_time and duration in the slot, to reschedule a booking. (required)
+	Booking *Booking `protobuf:"bytes,1,opt,name=booking" json:"booking,omitempty"`
+}
+
+func (m *UpdateBookingRequest) Reset()                    { *m = UpdateBookingRequest{} }
+func (m *UpdateBookingRequest) String() string            { return proto.CompactTextString(m) }
+func (*UpdateBookingRequest) ProtoMessage()               {}
+func (*UpdateBookingRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{45} }
+
+func (m *UpdateBookingRequest) GetBooking() *Booking {
+	if m != nil {
+		return m.Booking
+	}
+	return nil
+}
+
+// Response with the updated Booking.
+type UpdateBookingResponse struct {
+	// The updated booking (required)
+	Booking *Booking `protobuf:"bytes,1,opt,name=booking" json:"booking,omitempty"`
+	// The updated user payment option originally used to pay for this booking.
+	// This should be set if the UpdateBookingRequest results in a change to
+	// the UserPaymentOption.
+	// For instance, if the booking is canceled, the UserPaymentOption should
+	// reflect an additional credit to the user. In the case of a multi-use
+	// payment option, the current_count should be increased by one to
+	// allow the user to create another booking with this payment option. In the
+	// case of a single-use payment option, a new single-use user payment option
+	// should be returned. (required if altered in update)
+	UserPaymentOption *UserPaymentOption `protobuf:"bytes,2,opt,name=user_payment_option,json=userPaymentOption" json:"user_payment_option,omitempty"`
+	// If updating a booking fails, this field should reflect the business logic
+	// error (e.g., booking is not cancellable) (required if failure occurs)
+	BookingFailure *BookingFailure `protobuf:"bytes,3,opt,name=booking_failure,json=bookingFailure" json:"booking_failure,omitempty"`
+}
+
+func (m *UpdateBookingResponse) Reset()                    { *m = UpdateBookingResponse{} }
+func (m *UpdateBookingResponse) String() string            { return proto.CompactTextString(m) }
+func (*UpdateBookingResponse) ProtoMessage()               {}
+func (*UpdateBookingResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{46} }
+
+func (m *UpdateBookingResponse) GetBooking() *Booking {
+	if m != nil {
+		return m.Booking
+	}
+	return nil
+}
+
+func (m *UpdateBookingResponse) GetUserPaymentOption() *UserPaymentOption {
+	if m != nil {
+		return m.UserPaymentOption
+	}
+	return nil
+}
+
+func (m *UpdateBookingResponse) GetBookingFailure() *BookingFailure {
+	if m != nil {
+		return m.BookingFailure
+	}
+	return nil
+}
+
+func init() {
+	proto.RegisterType((*PostalAddress)(nil), "v3.PostalAddress")
+	proto.RegisterType((*GeoCoordinates)(nil), "v3.GeoCoordinates")
+	proto.RegisterType((*Price)(nil), "v3.Price")
+	proto.RegisterType((*TaxRate)(nil), "v3.TaxRate")
+	proto.RegisterType((*SchedulingRules)(nil), "v3.SchedulingRules")
+	proto.RegisterType((*IngestionQueuePayload)(nil), "v3.IngestionQueuePayload")
+	proto.RegisterType((*IngestionStatus)(nil), "v3.IngestionStatus")
+	proto.RegisterType((*TimeRange)(nil), "v3.TimeRange")
+	proto.RegisterType((*NoShowFee)(nil), "v3.NoShowFee")
+	proto.RegisterType((*Deposit)(nil), "v3.Deposit")
+	proto.RegisterType((*ActionLink)(nil), "v3.ActionLink")
+	proto.RegisterType((*Slot)(nil), "v3.Slot")
+	proto.RegisterType((*Lease)(nil), "v3.Lease")
+	proto.RegisterType((*LeaseReference)(nil), "v3.LeaseReference")
+	proto.RegisterType((*Booking)(nil), "v3.Booking")
+	proto.RegisterType((*UserInformation)(nil), "v3.UserInformation")
+	proto.RegisterType((*PaymentProcessingParameters)(nil), "v3.PaymentProcessingParameters")
+	proto.RegisterType((*UserPaymentOption)(nil), "v3.UserPaymentOption")
+	proto.RegisterType((*PaymentInformation)(nil), "v3.PaymentInformation")
+	proto.RegisterType((*BookingFailure)(nil), "v3.BookingFailure")
+	proto.RegisterType((*SlotAvailability)(nil), "v3.SlotAvailability")
+	proto.RegisterType((*AvailabilityUpdate)(nil), "v3.AvailabilityUpdate")
+	proto.RegisterType((*ResourceIds)(nil), "v3.ResourceIds")
+	proto.RegisterType((*TicketType)(nil), "v3.TicketType")
+	proto.RegisterType((*LineItem)(nil), "v3.LineItem")
+	proto.RegisterType((*LineItem_OrderedTickets)(nil), "v3.LineItem.OrderedTickets")
+	proto.RegisterType((*LineItemFulfillability)(nil), "v3.LineItemFulfillability")
+	proto.RegisterType((*OrderFulfillability)(nil), "v3.OrderFulfillability")
+	proto.RegisterType((*Order)(nil), "v3.Order")
+	proto.RegisterType((*OrderFailure)(nil), "v3.OrderFailure")
+	proto.RegisterType((*CheckAvailabilityRequest)(nil), "v3.CheckAvailabilityRequest")
+	proto.RegisterType((*CheckAvailabilityResponse)(nil), "v3.CheckAvailabilityResponse")
+	proto.RegisterType((*GetBookingStatusRequest)(nil), "v3.GetBookingStatusRequest")
+	proto.RegisterType((*GetBookingStatusResponse)(nil), "v3.GetBookingStatusResponse")
+	proto.RegisterType((*CheckOrderFulfillabilityRequest)(nil), "v3.CheckOrderFulfillabilityRequest")
+	proto.RegisterType((*CheckOrderFulfillabilityResponse)(nil), "v3.CheckOrderFulfillabilityResponse")
+	proto.RegisterType((*CreateBookingRequest)(nil), "v3.CreateBookingRequest")
+	proto.RegisterType((*CreateBookingResponse)(nil), "v3.CreateBookingResponse")
+	proto.RegisterType((*CreateOrderRequest)(nil), "v3.CreateOrderRequest")
+	proto.RegisterType((*CreateOrderResponse)(nil), "v3.CreateOrderResponse")
+	proto.RegisterType((*CreateLeaseRequest)(nil), "v3.CreateLeaseRequest")
+	proto.RegisterType((*CreateLeaseResponse)(nil), "v3.CreateLeaseResponse")
+	proto.RegisterType((*ListBookingsRequest)(nil), "v3.ListBookingsRequest")
+	proto.RegisterType((*ListBookingsResponse)(nil), "v3.ListBookingsResponse")
+	proto.RegisterType((*ListOrdersRequest)(nil), "v3.ListOrdersRequest")
+	proto.RegisterType((*ListOrdersResponse)(nil), "v3.ListOrdersResponse")
+	proto.RegisterType((*UpdateBookingRequest)(nil), "v3.UpdateBookingRequest")
+	proto.RegisterType((*UpdateBookingResponse)(nil), "v3.UpdateBookingResponse")
+	proto.RegisterEnum("v3.IngestionSource", IngestionSource_name, IngestionSource_value)
+	proto.RegisterEnum("v3.ContentType", ContentType_name, ContentType_value)
+	proto.RegisterEnum("v3.PriceType", PriceType_name, PriceType_value)
+	proto.RegisterEnum("v3.RequireCreditCard", RequireCreditCard_name, RequireCreditCard_value)
+	proto.RegisterEnum("v3.PaymentOptionType", PaymentOptionType_name, PaymentOptionType_value)
+	proto.RegisterEnum("v3.BookingStatus", BookingStatus_name, BookingStatus_value)
+	proto.RegisterEnum("v3.CreditCardType", CreditCardType_name, CreditCardType_value)
+	proto.RegisterEnum("v3.PrepaymentStatus", PrepaymentStatus_name, PrepaymentStatus_value)
+	proto.RegisterEnum("v3.IngestionStatus_Code", IngestionStatus_Code_name, IngestionStatus_Code_value)
+	proto.RegisterEnum("v3.PaymentProcessingParameters_PaymentProcessor", PaymentProcessingParameters_PaymentProcessor_name, PaymentProcessingParameters_PaymentProcessor_value)
+	proto.RegisterEnum("v3.PaymentInformation_PaymentProcessedBy", PaymentInformation_PaymentProcessedBy_name, PaymentInformation_PaymentProcessedBy_value)
+	proto.RegisterEnum("v3.BookingFailure_Cause", BookingFailure_Cause_name, BookingFailure_Cause_value)
+	proto.RegisterEnum("v3.LineItemFulfillability_ItemFulfillabilityResult", LineItemFulfillability_ItemFulfillabilityResult_name, LineItemFulfillability_ItemFulfillabilityResult_value)
+	proto.RegisterEnum("v3.OrderFulfillability_OrderFulfillabilityResult", OrderFulfillability_OrderFulfillabilityResult_name, OrderFulfillability_OrderFulfillabilityResult_value)
+	proto.RegisterEnum("v3.OrderFailure_Cause", OrderFailure_Cause_name, OrderFailure_Cause_value)
+	proto.RegisterEnum("v3.CheckAvailabilityResponse_DurationRequirement", CheckAvailabilityResponse_DurationRequirement_name, CheckAvailabilityResponse_DurationRequirement_value)
+}
+
+func init() { proto.RegisterFile("v3.proto", fileDescriptor0) }
+
+var fileDescriptor0 = []byte{
+	// 3731 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x5a, 0xcd, 0x73, 0x1b, 0xd9,
+	0x56, 0x9f, 0xd6, 0x87, 0x6d, 0x1d, 0xdb, 0x72, 0xfb, 0xda, 0xb1, 0x95, 0x38, 0x19, 0x3b, 0x3d,
+	0x33, 0x4c, 0xe2, 0xcc, 0x78, 0xde, 0x4b, 0xde, 0x54, 0x0d, 0x45, 0xc1, 0xd0, 0x6e, 0x5d, 0x67,
+	0x9a, 0xc8, 0x2d, 0xcd, 0x55, 0x2b, 0x99, 0xc0, 0xa2, 0xe9, 0xa8, 0xaf, 0x95, 0x26, 0x52, 0xb7,
+	0x5e, 0x77, 0xcb, 0x2f, 0x7e, 0x55, 0xaf, 0xea, 0x2d, 0xd9, 0x52, 0x50, 0xf5, 0x16, 0x14, 0x54,
+	0x41, 0x15, 0xb0, 0xa4, 0x58, 0xc0, 0x1f, 0x00, 0x0b, 0x8a, 0xa2, 0xf8, 0x07, 0x58, 0xc1, 0x3f,
+	0xc0, 0x86, 0x62, 0xc3, 0x8a, 0xba, 0x1f, 0xad, 0x6e, 0xb5, 0x24, 0x3b, 0x19, 0x60, 0xf1, 0x76,
+	0xba, 0xe7, 0x9c, 0xfb, 0x71, 0x3e, 0xee, 0x39, 0xbf, 0x73, 0x5b, 0xb0, 0x76, 0xf9, 0xe4, 0x64,
+	0x1c, 0x85, 0x49, 0x88, 0x4a, 0x97, 0x4f, 0xb4, 0xbf, 0x50, 0x60, 0xb3, 0x13, 0xc6, 0x89, 0x3b,
+	0xd4, 0x3d, 0x2f, 0xa2, 0x71, 0x8c, 0x1a, 0xb0, 0xda, 0x0f, 0x27, 0x41, 0x12, 0x5d, 0x35, 0x94,
+	0x23, 0xe5, 0x41, 0x8d, 0xa4, 0x43, 0x74, 0x07, 0xd6, 0x86, 0x61, 0xdf, 0x1d, 0xfa, 0xc9, 0x55,
+	0xa3, 0xc4, 0x59, 0xd3, 0x31, 0xda, 0x83, 0x95, 0x88, 0x0e, 0xfc, 0x30, 0x68, 0x94, 0x39, 0x47,
+	0x8e, 0xd0, 0x21, 0xac, 0x8f, 0xf9, 0xf2, 0x4e, 0x3f, 0xf4, 0x68, 0xa3, 0xc2, 0x99, 0x20, 0x48,
+	0x46, 0xe8, 0x51, 0xf4, 0x09, 0xd4, 0xe3, 0x24, 0xa2, 0x34, 0x71, 0x5c, 0x71, 0x80, 0x46, 0x95,
+	0xcb, 0x6c, 0x0a, 0xaa, 0x3c, 0x95, 0xf6, 0x13, 0xa8, 0x3f, 0xa5, 0xa1, 0x11, 0x86, 0x91, 0xe7,
+	0x07, 0x6e, 0x42, 0x63, 0x7e, 0x1a, 0x37, 0xf1, 0x93, 0x89, 0x47, 0xf9, 0x41, 0x15, 0x32, 0x1d,
+	0xa3, 0xbb, 0x50, 0x1b, 0x86, 0xc1, 0x40, 0x30, 0x4b, 0x9c, 0x99, 0x11, 0xd0, 0x23, 0x58, 0x4d,
+	0xf7, 0x62, 0x87, 0x5d, 0x7f, 0xbc, 0x7d, 0x72, 0xf9, 0xe4, 0x64, 0xc6, 0x0a, 0x24, 0x95, 0xd0,
+	0x7e, 0x06, 0xd5, 0x4e, 0xe4, 0xf7, 0x29, 0xba, 0x0f, 0x1b, 0x63, 0xf6, 0xc3, 0x19, 0xf9, 0xfd,
+	0x28, 0x8c, 0xf9, 0x9e, 0x65, 0xb2, 0xce, 0x69, 0xe7, 0x9c, 0x84, 0x3e, 0x82, 0xcd, 0xfe, 0x24,
+	0x8a, 0x68, 0xd0, 0xbf, 0x12, 0xea, 0x0a, 0x2b, 0x6d, 0xa4, 0x44, 0xae, 0xf0, 0x67, 0x80, 0xd8,
+	0x1c, 0x3f, 0x18, 0x38, 0xe1, 0x38, 0xf1, 0xc3, 0xc0, 0x49, 0xdc, 0x81, 0xb4, 0x9a, 0x2a, 0x39,
+	0x6d, 0xce, 0xb0, 0xdd, 0x81, 0x76, 0x02, 0xab, 0xb6, 0xfb, 0x96, 0xb8, 0x09, 0x65, 0xab, 0xf3,
+	0xad, 0x9d, 0x31, 0x8d, 0xfa, 0x34, 0x48, 0xf8, 0x09, 0xaa, 0x64, 0x83, 0x13, 0x3b, 0x82, 0xa6,
+	0xfd, 0xa7, 0x02, 0x5b, 0xdd, 0xfe, 0x6b, 0xea, 0x4d, 0x86, 0x7e, 0x30, 0x20, 0x93, 0x21, 0x8d,
+	0xd1, 0x09, 0xec, 0x8c, 0xfc, 0xc0, 0x71, 0xbd, 0x4b, 0x37, 0xe8, 0x53, 0xe7, 0x55, 0x18, 0xbe,
+	0xf1, 0x83, 0x81, 0x54, 0x60, 0x7b, 0xe4, 0x07, 0xba, 0xe0, 0x9c, 0x0a, 0x06, 0xfa, 0x1a, 0xee,
+	0xe6, 0xe5, 0xc3, 0x60, 0xe8, 0x07, 0xd4, 0xe9, 0xb3, 0x01, 0x5b, 0x94, 0x6b, 0x55, 0x26, 0xb7,
+	0xb3, 0x89, 0x6d, 0x2e, 0x61, 0xa4, 0x02, 0x48, 0x87, 0x5b, 0x43, 0x37, 0x49, 0xa7, 0x30, 0xaf,
+	0x84, 0x81, 0x73, 0x41, 0xa9, 0x34, 0x77, 0x8d, 0x9b, 0x9b, 0xd9, 0xed, 0xb4, 0xd4, 0x50, 0xc8,
+	0x0e, 0x93, 0x35, 0x72, 0xa2, 0x67, 0x94, 0x59, 0x09, 0x82, 0x30, 0x7e, 0x1d, 0xfe, 0x84, 0xcf,
+	0xab, 0x2c, 0x9a, 0x57, 0x13, 0x02, 0x67, 0x94, 0x6a, 0xfb, 0x70, 0xcb, 0x0c, 0x06, 0x34, 0x66,
+	0xb3, 0xbf, 0x9d, 0xd0, 0x09, 0xed, 0xb8, 0x57, 0xc3, 0xd0, 0xf5, 0xb4, 0x3f, 0xae, 0xc0, 0xd6,
+	0x94, 0xd3, 0x4d, 0xdc, 0x64, 0x12, 0xa3, 0xcf, 0xa0, 0xc2, 0x9d, 0xc3, 0xf4, 0xaf, 0x3f, 0x6e,
+	0xb0, 0x45, 0x0b, 0x22, 0x27, 0xcc, 0x51, 0x84, 0x4b, 0xa1, 0x87, 0xa0, 0x26, 0xfe, 0x88, 0xc6,
+	0x89, 0x3b, 0x1a, 0xa7, 0xae, 0x17, 0x06, 0xd8, 0x9a, 0xd2, 0xa5, 0xfb, 0x7f, 0x04, 0x7b, 0x7e,
+	0x90, 0xd0, 0x28, 0x70, 0x87, 0x0e, 0x8d, 0xa2, 0x30, 0x72, 0x3c, 0x9a, 0xb8, 0xfe, 0x30, 0x96,
+	0xde, 0xdd, 0x4d, 0xb9, 0x98, 0x31, 0x9b, 0x82, 0x87, 0x74, 0xb8, 0x37, 0x76, 0xa3, 0x24, 0xa0,
+	0x91, 0x73, 0xe9, 0xc7, 0xfe, 0xab, 0x21, 0x2d, 0x4c, 0x16, 0x77, 0xe6, 0x8e, 0x14, 0x7a, 0x2e,
+	0x64, 0xf2, 0x4b, 0x68, 0x7f, 0x5b, 0x82, 0x0a, 0x8f, 0x2d, 0x04, 0xf5, 0xae, 0xad, 0xdb, 0xbd,
+	0xae, 0xd3, 0xb3, 0x9e, 0x59, 0xed, 0x17, 0x96, 0xfa, 0x01, 0x6a, 0xc0, 0xae, 0xa4, 0x9d, 0x61,
+	0xdc, 0x74, 0x7a, 0x9d, 0x56, 0x5b, 0x6f, 0xe2, 0xa6, 0xaa, 0x14, 0x39, 0xd8, 0xfa, 0xb6, 0x87,
+	0x7b, 0xb8, 0xa9, 0x96, 0x90, 0x06, 0x1f, 0xe6, 0x39, 0x1d, 0xd2, 0x36, 0x70, 0xb7, 0x6b, 0x5a,
+	0x4f, 0x9d, 0xae, 0xad, 0x13, 0x1b, 0x37, 0xd5, 0x32, 0xfa, 0x18, 0x8e, 0x96, 0xc9, 0xf4, 0x0c,
+	0x03, 0x63, 0xb6, 0x47, 0x05, 0xdd, 0x87, 0x7b, 0x4b, 0xa4, 0xce, 0x74, 0xb3, 0x85, 0x9b, 0x6a,
+	0x15, 0xdd, 0x81, 0xbd, 0xbc, 0x48, 0xb3, 0xd7, 0x69, 0x99, 0x86, 0xce, 0x36, 0x59, 0x41, 0xb7,
+	0x60, 0x5b, 0xf2, 0xf4, 0x8e, 0xe9, 0x18, 0x7a, 0x8b, 0x4d, 0x61, 0x57, 0xe1, 0x30, 0x47, 0x5e,
+	0xb8, 0xf5, 0x05, 0x3a, 0x82, 0xbb, 0x8b, 0x85, 0xe4, 0xce, 0x03, 0x4d, 0x87, 0x9a, 0xed, 0x8f,
+	0x28, 0x71, 0x83, 0x01, 0x45, 0x07, 0x50, 0x7b, 0x45, 0x07, 0x7e, 0xe0, 0xc4, 0xb4, 0x2f, 0xef,
+	0xc6, 0x1a, 0x27, 0x74, 0x69, 0x1f, 0xed, 0xc3, 0x2a, 0x0d, 0x3c, 0xce, 0x12, 0xce, 0x5f, 0xa1,
+	0x81, 0xd7, 0xa5, 0x7d, 0x8d, 0x40, 0xcd, 0x0a, 0xbb, 0x22, 0x0c, 0xd1, 0x01, 0x94, 0x59, 0xb4,
+	0x2a, 0x85, 0x68, 0x25, 0x8c, 0x8a, 0x1e, 0xc0, 0xda, 0x05, 0xa5, 0x4e, 0x72, 0x35, 0x16, 0xf7,
+	0xa0, 0xfe, 0x78, 0x73, 0x2a, 0x61, 0x5f, 0x8d, 0x29, 0x59, 0xbd, 0xa0, 0xfc, 0x87, 0xf6, 0x67,
+	0x0a, 0xac, 0x36, 0xe9, 0x38, 0x8c, 0xfd, 0x04, 0x7d, 0x04, 0xab, 0x9e, 0xf8, 0x39, 0xbf, 0x6c,
+	0xca, 0x29, 0x5e, 0xd8, 0x99, 0x6b, 0x97, 0x1d, 0x39, 0x77, 0x61, 0xf3, 0xb7, 0x8d, 0xa9, 0xf7,
+	0x03, 0xd8, 0x90, 0x6b, 0x5d, 0x73, 0xbe, 0x75, 0x29, 0xc2, 0xcf, 0xe8, 0x03, 0xe8, 0x7d, 0x36,
+	0xbd, 0xe5, 0x07, 0x6f, 0x90, 0x0a, 0xe5, 0x49, 0x34, 0x94, 0xf5, 0x82, 0xfd, 0x14, 0xd9, 0x39,
+	0x18, 0x4c, 0xdc, 0x01, 0x9d, 0xd6, 0x0a, 0x39, 0x46, 0x9f, 0x03, 0x8a, 0x68, 0x9c, 0x44, 0x7e,
+	0x3f, 0xa1, 0x9e, 0x93, 0x16, 0x9b, 0xf2, 0x51, 0xf9, 0x41, 0x8d, 0x6c, 0x67, 0x1c, 0x43, 0x30,
+	0xb4, 0x7f, 0x53, 0xa0, 0xd2, 0x1d, 0x86, 0x09, 0xab, 0x25, 0x23, 0x1a, 0xf5, 0x5f, 0xbb, 0x41,
+	0xe2, 0xf8, 0x9e, 0xdc, 0x0d, 0x52, 0x92, 0xe9, 0xa1, 0x7b, 0x00, 0x31, 0x8d, 0x2e, 0x59, 0x92,
+	0xf6, 0x3d, 0xb9, 0x6d, 0x4d, 0x52, 0x4c, 0x8f, 0x79, 0x38, 0x4e, 0xdc, 0x28, 0xe1, 0x36, 0x29,
+	0x0b, 0x0f, 0x73, 0x02, 0x33, 0xc1, 0x7d, 0xd8, 0xf0, 0x26, 0x51, 0x66, 0xb3, 0x8a, 0x48, 0xef,
+	0x29, 0x8d, 0x89, 0x3c, 0x04, 0xd5, 0xbd, 0x74, 0xfd, 0xa1, 0xfb, 0xca, 0x67, 0x35, 0x8f, 0xe7,
+	0x6d, 0x51, 0xac, 0xb6, 0xf2, 0x74, 0xdb, 0x1d, 0xa0, 0xcf, 0xa1, 0x16, 0xd1, 0x38, 0x9c, 0x44,
+	0x7d, 0x1a, 0x37, 0x56, 0xb8, 0xe3, 0xb6, 0x98, 0x35, 0x89, 0x24, 0x9a, 0x5e, 0x4c, 0x32, 0x09,
+	0xed, 0xcf, 0x15, 0xa8, 0xb6, 0xa8, 0x1b, 0x53, 0x74, 0x1b, 0xd6, 0x86, 0xec, 0x47, 0xa6, 0xe0,
+	0x2a, 0x1f, 0x9b, 0x1e, 0xba, 0x0b, 0x95, 0x78, 0x18, 0x26, 0x5c, 0xaf, 0xf5, 0xc7, 0x6b, 0x6c,
+	0x39, 0x66, 0x16, 0xc2, 0xa9, 0xac, 0x8e, 0x4e, 0x62, 0x1a, 0x39, 0x11, 0xbd, 0xa0, 0xac, 0xd8,
+	0x50, 0x99, 0x74, 0x36, 0x19, 0x95, 0xa4, 0x44, 0xf4, 0xab, 0x70, 0x5b, 0xac, 0x4f, 0xdf, 0x8e,
+	0x7d, 0xa9, 0x2e, 0xcb, 0x63, 0x39, 0x9d, 0xf7, 0xb8, 0x00, 0x9e, 0xf2, 0xd9, 0x15, 0x61, 0xa1,
+	0xfe, 0x08, 0xea, 0xfc, 0x8c, 0xd9, 0x62, 0xcb, 0x0f, 0xab, 0xfd, 0xb7, 0x02, 0xab, 0x69, 0x3d,
+	0xb9, 0x07, 0x20, 0x6b, 0x4e, 0x26, 0x58, 0x93, 0x94, 0x1b, 0xf5, 0xfa, 0x0d, 0x50, 0xb9, 0x5e,
+	0x7e, 0x70, 0x11, 0x46, 0x23, 0x7e, 0x20, 0x59, 0x46, 0x76, 0x98, 0x64, 0x2f, 0xa6, 0x91, 0x99,
+	0xb1, 0xc8, 0xd6, 0x64, 0x96, 0x80, 0x1e, 0xc2, 0x4a, 0xcc, 0x93, 0x3a, 0xd7, 0xae, 0x2e, 0x6a,
+	0xbd, 0x3c, 0x99, 0xc8, 0xf6, 0x44, 0x0a, 0xa0, 0xa7, 0xb0, 0x33, 0x76, 0xaf, 0x46, 0x94, 0x85,
+	0x57, 0x6e, 0xb7, 0x2a, 0xdf, 0x6d, 0x8f, 0x5f, 0x06, 0xc1, 0xce, 0x6f, 0x88, 0xc6, 0x73, 0x34,
+	0xed, 0x9f, 0x15, 0xd8, 0x2a, 0x1c, 0x8c, 0x65, 0x10, 0xa1, 0x47, 0x6a, 0x81, 0x15, 0x7e, 0x52,
+	0x1e, 0xb4, 0x03, 0xff, 0x92, 0x06, 0x4e, 0xe0, 0x8e, 0xd2, 0xbb, 0x52, 0xe3, 0x14, 0xcb, 0x1d,
+	0x51, 0x16, 0xf4, 0x17, 0xee, 0xc8, 0x1f, 0x5e, 0x09, 0xbe, 0x70, 0x2a, 0x08, 0x12, 0x17, 0xc8,
+	0xa1, 0x99, 0xca, 0x4d, 0x68, 0x86, 0x01, 0xa3, 0x84, 0x0e, 0xe9, 0xf8, 0x75, 0x18, 0x50, 0x19,
+	0xbb, 0x19, 0x01, 0xed, 0x42, 0x95, 0x8e, 0x5c, 0x7f, 0xc8, 0x23, 0xb6, 0x46, 0xc4, 0x40, 0xfb,
+	0x45, 0x19, 0x0e, 0xa4, 0xe2, 0x9d, 0x28, 0xec, 0xd3, 0x38, 0xf6, 0x83, 0x41, 0xc7, 0x8d, 0xdc,
+	0x11, 0x4d, 0x68, 0x14, 0x23, 0x02, 0xb5, 0xb1, 0xa0, 0x87, 0x91, 0x2c, 0xaa, 0x3f, 0xc8, 0x19,
+	0x6b, 0xd1, 0x9c, 0x02, 0x2f, 0x8c, 0x44, 0x41, 0x9f, 0x2e, 0x83, 0x7e, 0x04, 0xbb, 0xa9, 0x2b,
+	0x46, 0x34, 0x79, 0x1d, 0x7a, 0x4e, 0x12, 0xbe, 0xa1, 0x81, 0x30, 0x0f, 0x17, 0x4e, 0xed, 0x7e,
+	0xce, 0xd9, 0x36, 0xe3, 0xb2, 0x52, 0x3a, 0x09, 0xc6, 0x6e, 0x14, 0x53, 0xcf, 0x59, 0x38, 0x5d,
+	0x68, 0x7c, 0x27, 0x15, 0xea, 0xcc, 0x2f, 0xd1, 0x80, 0xd5, 0x4b, 0x1a, 0xc5, 0x19, 0x90, 0x4d,
+	0x87, 0xe8, 0x11, 0x6c, 0xa7, 0x6b, 0x66, 0xea, 0x56, 0x24, 0x6c, 0x2b, 0xa8, 0xa3, 0x79, 0xa0,
+	0x16, 0x55, 0x64, 0xa5, 0xb0, 0xa3, 0xbf, 0x3c, 0xc7, 0x96, 0x9d, 0x16, 0xa3, 0x36, 0x71, 0x7a,
+	0x56, 0xb7, 0x83, 0x0d, 0xf3, 0xcc, 0xc4, 0x4d, 0xf5, 0x03, 0xb4, 0x0b, 0x6a, 0xc6, 0xea, 0xda,
+	0xc4, 0xec, 0x60, 0x55, 0x41, 0xfb, 0xb0, 0x93, 0x51, 0x4f, 0x89, 0x6e, 0x5a, 0x36, 0xc1, 0x58,
+	0x2d, 0x69, 0xff, 0x54, 0x82, 0x6d, 0x16, 0x67, 0x72, 0x2b, 0x81, 0x1a, 0xd1, 0x13, 0xd8, 0xe3,
+	0x91, 0x96, 0x9e, 0x56, 0xa2, 0xcc, 0x69, 0xe0, 0xed, 0x4c, 0x8a, 0x53, 0x4c, 0x0f, 0x7d, 0x01,
+	0xbb, 0x97, 0xee, 0xd0, 0xf7, 0x1c, 0x91, 0x21, 0xa7, 0x29, 0x41, 0x94, 0x8e, 0x6d, 0xce, 0xeb,
+	0x32, 0x96, 0xcc, 0x06, 0xe8, 0x11, 0x20, 0x31, 0x81, 0xd5, 0xc5, 0xa9, 0xb8, 0xc8, 0xaa, 0x5b,
+	0x9c, 0x83, 0x03, 0x2f, 0x15, 0x7e, 0x08, 0x15, 0x5e, 0x57, 0xc4, 0x15, 0xbc, 0x95, 0x8b, 0x0e,
+	0x89, 0x74, 0x59, 0x7d, 0xe1, 0x22, 0x2c, 0x8f, 0x85, 0x91, 0x3f, 0xf0, 0x03, 0xde, 0x32, 0x4c,
+	0x82, 0x84, 0x3b, 0xad, 0x4a, 0x36, 0x53, 0x2a, 0x2f, 0x0b, 0x19, 0xd4, 0x4e, 0xa4, 0xd4, 0x8a,
+	0x00, 0xc3, 0x92, 0x28, 0x84, 0x8e, 0x33, 0x97, 0x65, 0x46, 0x58, 0x15, 0x19, 0x7b, 0x3c, 0x6b,
+	0x00, 0xed, 0x4f, 0xab, 0x80, 0xe6, 0xaf, 0x37, 0xd2, 0x61, 0x7b, 0x1c, 0xd1, 0x74, 0x15, 0x99,
+	0x49, 0x44, 0x90, 0xef, 0x8a, 0xf2, 0x98, 0x32, 0x65, 0x32, 0x51, 0xc7, 0x05, 0x0a, 0x83, 0x85,
+	0xe9, 0xfc, 0x24, 0x72, 0x83, 0xd8, 0xed, 0xa7, 0x47, 0x11, 0x97, 0x3d, 0x8d, 0x74, 0x3b, 0x63,
+	0x9a, 0x1e, 0x3a, 0x84, 0x2a, 0x6f, 0x2d, 0xe6, 0x30, 0x33, 0x11, 0x74, 0xf4, 0x00, 0x20, 0x71,
+	0xdf, 0x3a, 0xee, 0x88, 0xab, 0x5f, 0x44, 0xc8, 0xa4, 0x96, 0xb8, 0x6f, 0x75, 0xce, 0x43, 0xbf,
+	0x93, 0x5d, 0x26, 0x19, 0xb9, 0xd4, 0x73, 0x5e, 0x5d, 0x71, 0xc3, 0xd6, 0x1f, 0x3f, 0x5c, 0x9c,
+	0xd8, 0x0a, 0x57, 0x94, 0x7a, 0xa7, 0x57, 0xd3, 0x3b, 0x97, 0xa3, 0xa1, 0xcf, 0x16, 0xd9, 0x98,
+	0xe7, 0x8f, 0x6f, 0x3e, 0x98, 0xb3, 0x32, 0xfa, 0x72, 0x69, 0x6c, 0xae, 0xca, 0x29, 0x0b, 0xa3,
+	0xf3, 0x93, 0x0c, 0x05, 0xad, 0x71, 0x45, 0xd7, 0xd9, 0xa1, 0x25, 0x46, 0xca, 0x70, 0xd0, 0xe7,
+	0xb0, 0x1e, 0x84, 0xce, 0xb4, 0x6b, 0xa8, 0x71, 0x51, 0x8e, 0x62, 0xa6, 0x18, 0x8d, 0x75, 0x0d,
+	0x29, 0x5c, 0xfb, 0x02, 0xea, 0x17, 0x94, 0xc6, 0x8e, 0xcb, 0x22, 0xd8, 0x7d, 0x4b, 0xe3, 0x06,
+	0x14, 0xad, 0xb8, 0xc1, 0x04, 0xf4, 0xc0, 0xb3, 0x19, 0x5b, 0x1b, 0x4d, 0x43, 0x24, 0x6f, 0x81,
+	0x8f, 0xe1, 0xa8, 0x70, 0xaf, 0x71, 0xd3, 0x39, 0x7d, 0x59, 0xb8, 0xda, 0xd9, 0x25, 0x16, 0xdc,
+	0xa7, 0xed, 0xf6, 0xd3, 0x16, 0x16, 0x28, 0x7c, 0x86, 0xd1, 0xd1, 0x89, 0x6d, 0x61, 0xa2, 0x96,
+	0x4e, 0x37, 0x00, 0xa6, 0xf5, 0xc8, 0xd3, 0x7e, 0xbf, 0x02, 0x75, 0x59, 0xb7, 0xce, 0x5c, 0x7f,
+	0x38, 0x89, 0x28, 0x3a, 0x81, 0x6a, 0xdf, 0x9d, 0xc4, 0x33, 0xad, 0xcc, 0xac, 0xc8, 0x89, 0xc1,
+	0xf8, 0x44, 0x88, 0xa1, 0xdf, 0x64, 0xc0, 0xeb, 0xf7, 0xa8, 0x80, 0x5d, 0x6e, 0xe4, 0x09, 0xb0,
+	0x57, 0xe2, 0x93, 0x11, 0x9b, 0x6c, 0x44, 0xd4, 0xf3, 0x13, 0xc3, 0x8d, 0x3c, 0x7e, 0x23, 0xd5,
+	0x54, 0x3a, 0xa5, 0xa0, 0x23, 0x58, 0xf7, 0x68, 0xdc, 0x8f, 0xfc, 0x71, 0x92, 0xa5, 0xc8, 0x3c,
+	0x49, 0xfb, 0xf7, 0x12, 0x54, 0xf9, 0xa6, 0x0c, 0xbb, 0x1b, 0x7a, 0xaf, 0x8b, 0xe7, 0x73, 0x5c,
+	0xb7, 0xd5, 0xb6, 0x9d, 0x9e, 0xa5, 0x3f, 0xd7, 0xcd, 0x96, 0x7e, 0xca, 0xad, 0x70, 0x08, 0x07,
+	0x9c, 0xaa, 0xb7, 0x08, 0xd6, 0x9b, 0x2f, 0x9d, 0xd3, 0x76, 0xfb, 0x99, 0x34, 0x63, 0x97, 0x19,
+	0x03, 0x6d, 0xc3, 0x66, 0x0b, 0xeb, 0x5d, 0xec, 0xe0, 0xef, 0x3a, 0x26, 0xe1, 0x1d, 0xc8, 0x21,
+	0x1c, 0xb4, 0x7b, 0x76, 0xd7, 0x6c, 0x62, 0xc7, 0xd0, 0x2d, 0x03, 0xb7, 0x5a, 0xba, 0x6d, 0xb6,
+	0x2d, 0xe7, 0x85, 0x69, 0x35, 0xdb, 0x2f, 0xd4, 0x4a, 0xde, 0x33, 0x98, 0x90, 0x36, 0x71, 0x0c,
+	0x9d, 0x34, 0x1d, 0xfb, 0x65, 0x07, 0x3b, 0x04, 0xff, 0x16, 0x36, 0x6c, 0xde, 0x7f, 0x1c, 0xc2,
+	0xc1, 0x02, 0xa9, 0x26, 0x36, 0x5a, 0xa6, 0xc5, 0x9b, 0x90, 0xbb, 0xd0, 0x48, 0x05, 0xda, 0x1d,
+	0xbe, 0x83, 0xd5, 0xb6, 0x9d, 0xe7, 0x7a, 0xcb, 0x6c, 0xaa, 0xab, 0xec, 0x60, 0x33, 0xd3, 0xd5,
+	0x35, 0xd6, 0x3e, 0xb1, 0x53, 0xb3, 0x53, 0x31, 0x49, 0x66, 0x83, 0xd9, 0x05, 0xd4, 0x1a, 0xba,
+	0x07, 0xb7, 0x99, 0x8e, 0xac, 0x1f, 0x49, 0x75, 0x96, 0x4a, 0xe0, 0xa6, 0x0a, 0xe8, 0x00, 0xf6,
+	0x53, 0x36, 0x5b, 0x22, 0xd5, 0x8f, 0x19, 0x6b, 0x5d, 0x7b, 0x09, 0x2a, 0x43, 0x48, 0x7a, 0x0e,
+	0x74, 0x4e, 0x51, 0x94, 0xb2, 0x10, 0x45, 0x7d, 0x0a, 0x5b, 0x3c, 0x4d, 0x3a, 0x12, 0xa8, 0x0e,
+	0x85, 0xdb, 0xab, 0xa4, 0xce, 0xc9, 0x7a, 0x4a, 0xd5, 0x5e, 0x00, 0xca, 0x2f, 0xdb, 0x1b, 0x7b,
+	0x6e, 0x42, 0x59, 0x16, 0x64, 0xcb, 0x38, 0x79, 0x98, 0xdb, 0x50, 0x8e, 0xca, 0x0f, 0xd6, 0x45,
+	0x16, 0x2c, 0x9e, 0x86, 0xa8, 0x71, 0x81, 0xa2, 0xfd, 0x2e, 0xac, 0xe7, 0xc0, 0x2f, 0x83, 0x8e,
+	0x71, 0xe2, 0x5e, 0x5c, 0xe4, 0xa0, 0x23, 0x1f, 0x9b, 0x1e, 0x43, 0x4a, 0x51, 0x18, 0x8e, 0xb2,
+	0x04, 0xb9, 0xc2, 0x86, 0x02, 0x29, 0xb1, 0x26, 0xf8, 0xca, 0x89, 0xfd, 0x9f, 0x8a, 0xbc, 0x58,
+	0x25, 0x35, 0x4e, 0xe9, 0xfa, 0x3f, 0xa5, 0xda, 0xcf, 0x15, 0x00, 0xdb, 0xef, 0xbf, 0xa1, 0xbc,
+	0x43, 0x41, 0x1f, 0x43, 0x3d, 0xe1, 0x23, 0x1e, 0xe5, 0xd9, 0x3e, 0x1b, 0xc9, 0x54, 0xc6, 0xf4,
+	0x58, 0x55, 0x8f, 0x5f, 0x87, 0x51, 0xe2, 0xe4, 0xc3, 0x5a, 0x6c, 0xab, 0x72, 0x46, 0x33, 0xa3,
+	0xdf, 0x98, 0x93, 0xb5, 0xbf, 0x29, 0xc1, 0x5a, 0xcb, 0x0f, 0xa8, 0x99, 0xd0, 0x51, 0xa1, 0x1b,
+	0x51, 0xae, 0xed, 0x46, 0x4a, 0x37, 0x74, 0x23, 0xe5, 0xf9, 0x6e, 0xe4, 0x4b, 0x58, 0x15, 0x9a,
+	0x30, 0xdc, 0xc7, 0x3c, 0x71, 0xc0, 0x8e, 0x93, 0xee, 0x7e, 0xd2, 0x8e, 0x3c, 0x1a, 0x51, 0x4f,
+	0x18, 0x24, 0x26, 0xa9, 0x6c, 0xa6, 0x43, 0x75, 0x49, 0x5d, 0xc9, 0x00, 0xf3, 0xca, 0x0d, 0x80,
+	0xf9, 0x8e, 0x01, 0xf5, 0xd9, 0x6d, 0x98, 0x52, 0xd2, 0xe8, 0x53, 0x95, 0xd7, 0x04, 0xc1, 0xf4,
+	0x18, 0xbc, 0x14, 0xb5, 0x5a, 0x84, 0x9e, 0x18, 0x68, 0xff, 0x5a, 0x86, 0xbd, 0xf4, 0xd4, 0x67,
+	0x93, 0xe1, 0x85, 0x3f, 0x9c, 0xc6, 0xf4, 0x11, 0x54, 0xfc, 0x84, 0x8e, 0x64, 0x4c, 0x6f, 0xe4,
+	0xf5, 0x23, 0x9c, 0x83, 0x9e, 0xc1, 0x4a, 0x44, 0xe3, 0xc9, 0x30, 0x91, 0x59, 0xec, 0x49, 0x5e,
+	0x66, 0x76, 0xb5, 0x93, 0x79, 0x12, 0xe1, 0x53, 0x89, 0x5c, 0x02, 0xfd, 0x10, 0x76, 0x27, 0xc1,
+	0x45, 0x2a, 0x31, 0xa4, 0x4e, 0x44, 0xdd, 0x78, 0x9a, 0xe5, 0x76, 0x66, 0x78, 0x84, 0xb3, 0xb8,
+	0x8f, 0xc7, 0x61, 0x12, 0x3b, 0xe1, 0x98, 0x06, 0xbc, 0x08, 0x57, 0x49, 0x8d, 0x53, 0xda, 0x63,
+	0x1a, 0xa0, 0x2f, 0x60, 0x3d, 0x17, 0x83, 0x8d, 0x2a, 0xf7, 0x53, 0x9d, 0x9d, 0x31, 0x0b, 0x54,
+	0x02, 0x59, 0x40, 0x6a, 0xff, 0xa2, 0x40, 0x63, 0xd9, 0x39, 0xd1, 0x31, 0xfc, 0x8a, 0x69, 0xe3,
+	0x73, 0xe7, 0xac, 0xd7, 0x3a, 0x33, 0x59, 0x32, 0x30, 0x5b, 0xa6, 0xfd, 0xd2, 0x21, 0xb8, 0xdb,
+	0x6b, 0xd9, 0x85, 0x2c, 0xbb, 0x05, 0xeb, 0x86, 0x6e, 0xa5, 0xa2, 0xaa, 0xb2, 0x30, 0xed, 0x96,
+	0x58, 0x86, 0xec, 0x59, 0xd3, 0xf5, 0x5a, 0xd8, 0xb1, 0x4d, 0xe3, 0x19, 0xb6, 0x1d, 0xa3, 0x7d,
+	0x7e, 0x6a, 0x5a, 0x3c, 0x9d, 0xaa, 0x65, 0xb4, 0x03, 0x5b, 0xa6, 0x65, 0xb4, 0x09, 0xc1, 0x06,
+	0xab, 0x71, 0xa6, 0x81, 0xd5, 0x0a, 0xfa, 0x08, 0x0e, 0xf9, 0x69, 0x66, 0xe7, 0xb7, 0xed, 0x6f,
+	0x30, 0x71, 0x08, 0xd6, 0xbb, 0x6d, 0x4b, 0xad, 0x6a, 0x7f, 0x59, 0x86, 0x1d, 0x1e, 0x22, 0x05,
+	0xcf, 0x9a, 0x53, 0xbf, 0x89, 0xd2, 0xf5, 0x43, 0x66, 0x93, 0x05, 0x82, 0x8b, 0x68, 0x05, 0xaf,
+	0x3d, 0x83, 0x1d, 0x16, 0x0a, 0xce, 0xc5, 0x8c, 0x50, 0xa3, 0xc4, 0x6d, 0x7d, 0x67, 0x79, 0x3c,
+	0x10, 0xe4, 0xcf, 0x47, 0xdc, 0xfb, 0x87, 0x80, 0xf6, 0x0f, 0x0a, 0xdc, 0x5e, 0x7a, 0x4a, 0xf4,
+	0x08, 0x3e, 0x6d, 0x93, 0x26, 0x26, 0xdf, 0xcf, 0x69, 0x07, 0xb0, 0x3f, 0x6b, 0x5e, 0x56, 0x92,
+	0x1c, 0x66, 0x76, 0xb5, 0x84, 0x3e, 0x81, 0xfb, 0xb3, 0xcc, 0x2e, 0x26, 0xcf, 0x4d, 0x03, 0x17,
+	0x9c, 0xf7, 0x31, 0x1c, 0x89, 0x13, 0x5c, 0xe3, 0xa8, 0x8a, 0xf6, 0x1f, 0x0a, 0x54, 0xb9, 0x16,
+	0x2c, 0x33, 0x87, 0xec, 0x47, 0x2e, 0x33, 0xf3, 0xb1, 0xe9, 0x2d, 0xec, 0xc5, 0x4b, 0xef, 0xd1,
+	0x8b, 0x2f, 0x69, 0xb0, 0xcb, 0xef, 0xdb, 0x60, 0x17, 0x5f, 0x82, 0x2a, 0x73, 0x2f, 0x41, 0x69,
+	0xe6, 0x10, 0x37, 0x6e, 0x41, 0xe6, 0xd0, 0xfe, 0xab, 0x04, 0x1b, 0xc2, 0x6d, 0x12, 0x4c, 0x7d,
+	0x36, 0x0b, 0xa6, 0xf6, 0xb2, 0x88, 0x5c, 0x04, 0xa5, 0xbe, 0x86, 0xfa, 0x5c, 0xc0, 0x31, 0x2d,
+	0xf6, 0x97, 0x04, 0x32, 0x29, 0x88, 0x2f, 0xc1, 0x62, 0xe5, 0xef, 0x8f, 0xc5, 0x2a, 0xf3, 0x58,
+	0xec, 0x0f, 0x94, 0x1b, 0xb0, 0xd8, 0x3e, 0xec, 0x2c, 0x88, 0x0d, 0x55, 0x79, 0x27, 0xe4, 0x54,
+	0xba, 0x09, 0x39, 0x95, 0xe7, 0xb1, 0x51, 0x45, 0xfb, 0x0a, 0x1a, 0xc6, 0x6b, 0xda, 0x7f, 0x33,
+	0x03, 0x17, 0xe8, 0x8f, 0x27, 0x34, 0x4e, 0xae, 0xc7, 0x30, 0xda, 0xcf, 0xcb, 0x70, 0x7b, 0xc1,
+	0xd4, 0x78, 0x1c, 0x06, 0x31, 0xfd, 0x3f, 0xc2, 0x3f, 0xc8, 0x83, 0xdd, 0x69, 0xe1, 0x8d, 0xe8,
+	0x8f, 0x27, 0x7e, 0x44, 0x59, 0xf0, 0x49, 0xc7, 0xf0, 0x34, 0xb5, 0xf4, 0x0c, 0x27, 0x4d, 0x39,
+	0x93, 0x64, 0x13, 0xc9, 0x8e, 0x37, 0x4f, 0x64, 0x17, 0x61, 0xe6, 0x25, 0x71, 0xc2, 0x61, 0x96,
+	0x6c, 0xe2, 0x78, 0xe4, 0xcd, 0x83, 0x30, 0x82, 0xdc, 0x39, 0x9a, 0x36, 0x82, 0x9d, 0x05, 0x9b,
+	0x32, 0xf7, 0x35, 0x7b, 0x44, 0xa0, 0x61, 0x82, 0xbf, 0xed, 0x99, 0x04, 0x73, 0x27, 0xcc, 0x7a,
+	0xbf, 0x01, 0xbb, 0xcd, 0x36, 0x87, 0x97, 0xdd, 0x6f, 0xda, 0x2f, 0x9c, 0x74, 0x86, 0xaa, 0xa0,
+	0x3d, 0x40, 0xe7, 0xbd, 0x6e, 0x91, 0x5e, 0xd2, 0xbe, 0x82, 0xfd, 0xa7, 0x34, 0x99, 0x05, 0x03,
+	0xd2, 0x77, 0xd7, 0x3f, 0xf2, 0x69, 0x7f, 0xa7, 0x40, 0x63, 0x7e, 0xaa, 0xf4, 0xdd, 0x0d, 0x0f,
+	0x84, 0x5f, 0x41, 0x3d, 0x65, 0x4b, 0x64, 0x52, 0x5a, 0x86, 0x4c, 0x36, 0x5f, 0xe5, 0x87, 0x8b,
+	0xbb, 0xf7, 0xf2, 0xfb, 0x74, 0xef, 0x9a, 0x07, 0x87, 0xdc, 0xe1, 0x0b, 0x53, 0xbc, 0x50, 0xfd,
+	0xc6, 0x77, 0xe9, 0x34, 0x1b, 0x95, 0x96, 0x66, 0xa3, 0x3f, 0x52, 0xe0, 0x68, 0xf9, 0x36, 0xd2,
+	0x4c, 0xf3, 0x39, 0x47, 0x79, 0xbf, 0x9c, 0x33, 0xdf, 0xf0, 0x96, 0xae, 0x6f, 0x78, 0xff, 0xba,
+	0x0c, 0xbb, 0x46, 0x44, 0xdd, 0x24, 0xfd, 0x36, 0xf8, 0x4e, 0x37, 0x15, 0x7d, 0x01, 0x35, 0xf1,
+	0x2e, 0x1c, 0xd1, 0x0b, 0xb9, 0x05, 0x4f, 0x69, 0xb3, 0xcf, 0xc7, 0x44, 0x3c, 0x1e, 0x13, 0x7a,
+	0xf1, 0xbf, 0x7e, 0xe4, 0x5d, 0x52, 0x58, 0x2a, 0xef, 0x5d, 0x58, 0xfa, 0x70, 0xaf, 0xf0, 0x54,
+	0xc2, 0xa2, 0x6e, 0x3c, 0x7d, 0xb8, 0x94, 0xa8, 0xf9, 0xf0, 0x86, 0xf7, 0x4d, 0x72, 0x30, 0xbe,
+	0xe6, 0xc1, 0xf4, 0x11, 0x6c, 0xfb, 0x1e, 0x1d, 0x8d, 0xc3, 0x84, 0x7f, 0x29, 0x16, 0x4f, 0x93,
+	0xe2, 0xc9, 0x55, 0xcd, 0x31, 0xc4, 0x83, 0xe4, 0xe7, 0x80, 0x5c, 0xcf, 0xf3, 0xd9, 0xe9, 0xdc,
+	0x21, 0x4f, 0x49, 0x34, 0x4e, 0xe4, 0x23, 0xd6, 0x76, 0xc6, 0x91, 0x8e, 0xd1, 0xfe, 0x5e, 0x81,
+	0x5b, 0x05, 0x8f, 0xc9, 0xe8, 0xf9, 0x04, 0x56, 0xf3, 0x5f, 0x7e, 0xe5, 0x1b, 0x4a, 0x2a, 0x95,
+	0xf2, 0x10, 0x86, 0x9d, 0x05, 0x2f, 0x34, 0xd2, 0x8b, 0xb7, 0x52, 0x6f, 0xcc, 0x3c, 0xd0, 0x90,
+	0xed, 0xb9, 0x37, 0x1b, 0xf4, 0x6b, 0xb0, 0x95, 0xde, 0xd9, 0x0b, 0x51, 0x3f, 0xa5, 0x43, 0xd1,
+	0xfc, 0x23, 0x05, 0x49, 0xaf, 0xb7, 0x1c, 0x6b, 0xff, 0xa8, 0x00, 0x12, 0x4a, 0xf0, 0xa8, 0xce,
+	0xee, 0x59, 0x95, 0x23, 0x91, 0xfc, 0x97, 0x30, 0x21, 0x20, 0xe8, 0x37, 0x7b, 0xaf, 0xf4, 0xff,
+	0xe5, 0xbd, 0xf2, 0x62, 0xef, 0xb1, 0xfc, 0x3c, 0xa3, 0x88, 0xf4, 0xc5, 0x8d, 0x9a, 0x7c, 0x09,
+	0x9b, 0x02, 0x84, 0xa5, 0xc6, 0x13, 0x27, 0x57, 0x8b, 0xa0, 0x84, 0x6c, 0x84, 0xb9, 0x91, 0xf6,
+	0x65, 0x6a, 0x37, 0x79, 0xd3, 0xa6, 0x76, 0xe3, 0x37, 0x2d, 0xbf, 0x9b, 0x10, 0x10, 0x74, 0x2d,
+	0x4e, 0x4f, 0x29, 0xa7, 0x65, 0xa7, 0xbc, 0x76, 0xde, 0x22, 0x27, 0x97, 0xde, 0xd9, 0xc9, 0x27,
+	0xb0, 0xd3, 0xf2, 0xe3, 0xb4, 0x22, 0x4c, 0xeb, 0xc8, 0xb2, 0xef, 0x24, 0xda, 0xd7, 0xb0, 0x3b,
+	0x2b, 0x2f, 0x4f, 0xf9, 0x29, 0xac, 0xc9, 0x95, 0x63, 0xf9, 0x24, 0x31, 0x13, 0xd8, 0x53, 0xa6,
+	0xf6, 0x14, 0xb6, 0xd9, 0x02, 0xdc, 0x7c, 0x37, 0x6e, 0x37, 0x03, 0x83, 0x4b, 0xfc, 0xd3, 0x64,
+	0x0a, 0x83, 0x99, 0x95, 0xf3, 0x0b, 0xcd, 0xfb, 0xb4, 0xbc, 0xc8, 0xa7, 0xda, 0xaf, 0xc3, 0xae,
+	0xa8, 0xda, 0x85, 0x5c, 0xfa, 0x6e, 0x17, 0x93, 0xdf, 0xec, 0xc2, 0xfc, 0x5f, 0xba, 0x9b, 0x7d,
+	0x7c, 0x96, 0xff, 0x3b, 0x06, 0x7f, 0x0c, 0xe2, 0xff, 0x59, 0x68, 0xf7, 0x88, 0x81, 0x73, 0xff,
+	0x59, 0xd8, 0x82, 0x75, 0x49, 0x3b, 0xc3, 0xfc, 0xaf, 0x0a, 0x75, 0x00, 0x49, 0xd0, 0x3b, 0xa6,
+	0x5a, 0x3a, 0xfe, 0x2b, 0x05, 0xd6, 0x8d, 0x30, 0x48, 0x68, 0x20, 0x1e, 0x7b, 0x76, 0x60, 0xcb,
+	0x68, 0x5b, 0xb6, 0xc0, 0x38, 0xe9, 0x2a, 0xbb, 0xa0, 0xa6, 0xc4, 0x73, 0x4c, 0x8c, 0x6f, 0x74,
+	0xcb, 0x56, 0x95, 0xbc, 0xa8, 0x6c, 0x98, 0xd4, 0x12, 0x83, 0x42, 0x29, 0x51, 0xb6, 0xc7, 0xbc,
+	0x4d, 0x53, 0xcb, 0xe8, 0x0e, 0xec, 0xa5, 0x9c, 0xc2, 0x1b, 0x5e, 0x05, 0x69, 0xf0, 0xe1, 0x62,
+	0xde, 0x74, 0xe5, 0xea, 0xf1, 0x13, 0xa8, 0x4d, 0x3f, 0xa1, 0x33, 0x5c, 0x75, 0x66, 0x7e, 0x87,
+	0x9b, 0x0e, 0xd1, 0x6d, 0xec, 0x34, 0xf1, 0x99, 0xde, 0x6b, 0xd9, 0xea, 0x07, 0x4c, 0xbd, 0x0e,
+	0x26, 0x4e, 0x07, 0x13, 0xd6, 0x8d, 0x29, 0xc7, 0x3f, 0x83, 0x6d, 0x09, 0xe7, 0xb2, 0x2e, 0x80,
+	0x35, 0xdc, 0x12, 0xcb, 0x39, 0x06, 0xc1, 0x4d, 0xd3, 0x16, 0x70, 0x7b, 0x16, 0xd3, 0x2d, 0x11,
+	0x32, 0xda, 0x56, 0xd3, 0x64, 0x27, 0xd3, 0x59, 0x5b, 0xf9, 0x21, 0xdc, 0x59, 0x24, 0xa4, 0xb7,
+	0x5e, 0xe8, 0x2f, 0xbb, 0x6a, 0xe9, 0xf8, 0x17, 0x0a, 0x6c, 0xcf, 0x7d, 0x9f, 0x61, 0x4b, 0x17,
+	0xb4, 0xe4, 0xfd, 0xc0, 0xec, 0xfe, 0xf7, 0xe0, 0x76, 0xd1, 0x14, 0xa6, 0xf5, 0xb4, 0x85, 0x9d,
+	0x5e, 0x97, 0xf5, 0x15, 0xf3, 0x4f, 0xa9, 0xe7, 0xbd, 0x96, 0x6d, 0x72, 0x6e, 0x09, 0x1d, 0xc1,
+	0xdd, 0x02, 0xb7, 0x67, 0xb5, 0xcc, 0x73, 0xd3, 0xc6, 0x4d, 0x2e, 0x51, 0x3e, 0xfe, 0x43, 0x05,
+	0x36, 0x67, 0x10, 0x1f, 0xd3, 0x25, 0x7d, 0x28, 0x9d, 0xfe, 0xf5, 0x25, 0x7f, 0xa0, 0x4d, 0xa8,
+	0x19, 0x6d, 0xeb, 0xcc, 0x24, 0xe7, 0x3c, 0x90, 0xee, 0xc3, 0xbd, 0x0e, 0xb6, 0x9a, 0x4c, 0x3c,
+	0x8d, 0x09, 0x47, 0xf2, 0x25, 0xc8, 0x45, 0x1b, 0xb0, 0x26, 0x9e, 0x5b, 0x79, 0x0b, 0xb3, 0x0e,
+	0xab, 0x56, 0x9b, 0x03, 0x61, 0xb5, 0xc2, 0xda, 0x28, 0x39, 0x70, 0x3a, 0xd8, 0xd2, 0x5b, 0xe6,
+	0x6f, 0xe3, 0xa6, 0x5a, 0x3d, 0x1e, 0x43, 0x7d, 0xb6, 0x5b, 0x63, 0x9a, 0xe4, 0x2d, 0xbb, 0xc0,
+	0x50, 0x6b, 0x50, 0x79, 0x6e, 0x76, 0x75, 0x11, 0xdb, 0xe7, 0x7a, 0xd7, 0xc6, 0x84, 0x89, 0xaa,
+	0x25, 0x16, 0xb6, 0xfa, 0x39, 0x26, 0xa6, 0xa1, 0x5b, 0x0e, 0xfe, 0xae, 0x43, 0x70, 0xb7, 0xab,
+	0x96, 0xd9, 0xa9, 0x9a, 0x66, 0xd7, 0x68, 0x3f, 0xc7, 0x44, 0xad, 0x1c, 0xff, 0x89, 0x02, 0x6a,
+	0x11, 0xbc, 0x72, 0xdd, 0x08, 0x4e, 0x2d, 0xb8, 0xd0, 0x1a, 0xfc, 0x2b, 0x04, 0xce, 0x7d, 0xae,
+	0x78, 0x6e, 0x8a, 0xff, 0x02, 0x1d, 0xc0, 0x7e, 0x8e, 0xc1, 0x7a, 0x82, 0x29, 0xb3, 0x54, 0x98,
+	0x45, 0xf0, 0x59, 0xcf, 0x6a, 0x72, 0xe3, 0xcc, 0x32, 0x84, 0xc6, 0xb8, 0xa9, 0x56, 0x5e, 0xad,
+	0xf0, 0x7f, 0x18, 0x3e, 0xf9, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x84, 0x9d, 0xca, 0x4f, 0x6d,
+	0x28, 0x00, 0x00,
+}