Last modified: Tue Jul 09 2019 12:33:13 GMT+0000 (Coordinated Universal Time)

How to book a stay

In this tutorial, you will learn how to actually book something.

Requirements

Step by step

Booking in Winding Tree ecosystem is done in a decentralized way. If a hotel uses Winding Tree Data Model, it should advertise a bookingUri in its published data. This bookingUri should be pointing to an instance of REST API which is implementing the booking protocol.

Note: The URI is not the booking endpoint itself. For example, the Booking API is running on https://example.com (that's the bookingUri), but the bookings themselves are supposed to go to https://example.com/booking. The endpoint names are an integral part of the booking protocol.

In order to be able to actually book a room, we have to construct a booking request in the client application. That has to contain all of the necessary information so that the hotel can validate and accept the booking request.

Customer information

Of course, we have to know who is doing the booking and the hotel has to have at least some contact information. The minimal customer information might look like this:

{
  "name": "Elizabeth",
  "surname": "Crown",
  "email": "[email protected]"
}

Booking information

Then there's the information about the booking itself. Again, the minimal form looks like this:

{
  "arrival": "2019-03-01",
  "departure": "2019-03-05",
  "guestInfo": [
    { "id": "guest-1" },
    { "id": "guest-2" }
  ],
  "rooms": [
    { "id": "room-1", "guestInfoIds": ["guest-1", "guest-2"] }
  ]
}

It might seem unnecessary to pass generic guest id, but it's a format that is easily extensible for more advanced use cases which we support, such as:

  • Booking multiple rooms
  • Assigning guests to rooms
  • Transferring personal information about guests (name, age)

Pricing information

The final section of a booking request contains the price and all other money-related information. What might be new to you is the cancellationFees field that contains conditions under which the booking can actually be cancelled by the customer. In our example, if a customer cancels the booking at any time prior to the arrival, it will cost him 30% of the price, so in this case, the refunded amount will be just about GBP 224.

{
  "currency": "GBP",
  "total": 320,
  "cancellationFees": [
    {
      "from": "2019-02-26",
      "to": "2019-03-01",
      "amount": 30
    }
  ]
}

Both the price and cancellation fees are computed from the data distributed via Winding Tree platform. To compute the data for an actual booking, you can use our open-source Javascript pricing library @windingtree/wt-pricing-algorithms.

Optionally, if you need additional pricing information, you can use the components property which can contain a day-by-day and guest-by-guest breakdown of the price. It might look like this:

{
  "components": {
    "stay": [
      {
        "date": "2019-03-02",
        "subtotal": 80,
        "guests": [
          {
            "guestId": "guest-1",
            "ratePlanId": "early-spring",
            "resultingPrice": 50
          },
          {
            "guestId": "guest-2",
            "ratePlanId": "early-spring",
            "resultingPrice": 30
          }
        ]
      },
      {
        "date": "2019-03-03",
        "subtotal": 80,
        "guests": [
          {
            "guestId": "guest-1",
            "ratePlanId": "early-spring",
            "resultingPrice": 50
          },
          {
            "guestId": "guest-2",
            "ratePlanId": "early-spring",
            "resultingPrice": 30
          }
        ]
      },
      {
        "date": "2019-03-04",
        "subtotal": 80,
        "guests": [
          {
            "guestId": "guest-1",
            "ratePlanId": "early-spring",
            "resultingPrice": 50
          },
          {
            "guestId": "guest-2",
            "ratePlanId": "early-spring",
            "resultingPrice": 30
          }
        ]
      },
      {
        "date": "2019-03-05",
        "subtotal": 80,
        "guests": [
          {
            "guestId": "guest-1",
            "ratePlanId": "early-spring",
            "resultingPrice": 50
          },
          {
            "guestId": "guest-2",
            "ratePlanId": "early-spring",
            "resultingPrice": 30
          }
        ]
      }
    ]
  }
}

Putting everything together

If we combine everything together, we will get a booking-request.json which in addition to everything we've said, contains a hotel's ID (Ethereum address).

{
  "hotelId": "0xD8b8aF90986174d5c5558aAC0905AA1DB2Ee41ce",
  "customer": {
    "name": "Elizabeth",
    "surname": "Crown",
    "email": "[email protected]"
  },
  "booking": {
    "arrival": "2019-03-01",
    "departure": "2019-03-05",
    "guestInfo": [
      { "id": "guest-1" },
      { "id": "guest-2" }
    ],
    "rooms": [
      { "id": "room-1", "guestInfoIds": ["guest-1", "guest-2"] }
    ]
  },
  "pricing": {
    "currency": "GBP",
    "total": 320.23,
    "cancellationFees": [
      {
        "from": "2019-02-26",
        "to": "2019-03-01",
        "amount": 30
      }
    ]
  }
}

Another optional field that you can set is origin which can hold a name or identifier of the system where the booking happens - such as a travel agency or an online portal. This is useful to track your traffic sources.

And finally, we tell the hotel that we want to book the property.

$ curl -X POST https://fancy-blockchain-hotel-booking.com/booking \
  -H 'Content-Type: application/json' \
  --data @booking-request.json

In case the hotel accepts the proposed conditions, the response should contain some form of a reference ID and status (currently accepted or pending).

{
  "id": "booking-id-54687",
  "status": "pending"
}

We plan to extend the protocol in the future to accommodate the typical next steps such as payment processing.

Message signing

Info

Every Booking API operator should require request signing and some level of trust to prevent spam requests and other malicious activity.

Depending on the booking API configuration it may be necessary to sign hash of the request using an Ethereum account. This provides the booking API provider with means to verify the sender, integrity of the message, and verify the necessary trust level.

When signing a booking, the request body must set originAddress field to the address of the account used for signing and send the signature in x-wt-signature header. Signature is created by web3.eth_sign method by signing the whole raw request. You can use WtJsLibs.wallet.signData convenience method instead.

Ideally, the originAddress would contain an ORG.ID address of the booking source (OTA) and the signer's address will be an associatedKey of that ORG.ID. The current implementation does not reflect that at the moment.

See the wt-booking-api readme or build a booking page for more detailed explanation and examples.

Where to next