Introduction
Hi! welcome to the Booking Experts App Guide. This explains the basics concept of a Booking Experts App. If you're looking for the API reference, please see our App Api.
We hope you can find your way around. If not, please reach out to api@bookingexperts.nl. We are happy to help and discuss on new idea's.
The best way to build in integration is by using Booking Experts Apps. You could also use the deprecated Tour operator Api but we strongly advice to build Booking Expert Apps from this point onward.
Booking Experts Apps
We call it Booking Experts Apps because it's a little more than a standard integration. You can create an App for your own use or make it publicly available for other Booking Experts users.
It was born out of the many requests for new integrations we got on a weekly basis. We don't want to limit our users so we thought of a set of API's, tooling etc. to facilitate other parties.
With Booking Experts Apps you can think of Booking Experts as a platform. Booking Experts (without Apps) solves 80% of the common use cases in property rental out of the box. We provide and invest in a good and stable foundation while others can extend Booking Experts to fit their needs.
There are many use cases for which Booking Experts Apps is good fit. Examples:
- Access control
- Thermostats
- Channel management
- Tour operators
- Websites
- Payment providers
- etc.
Some use cases are quite specific. See Guides for examples.
App characteristics
An App is a little more than a one-way integration.
- Let Booking Experts call your system by using Webhooks.
- Extend the Booking Experts UI by adding Commands which can be invoked by normal Booking Experts users.
- Send e-mail and SMS messages to guests through Booking Experts by using Message Templates.
Begin with a basic App
Select all the permissions you need and install your App on a single administration. Grab the API key to start making API calls. Sign up for a Demo if you don't have access to a Booking Experts administration.
See API key
Level up with an OAuth2 flow
Drop the API key and implement the OAuth2 flow and submit your App for validation. Now other Booking Experts users can install your App on their administration.
See OAuth2 flow
Demo
Currently Booking Experts Apps is still on invite only basis. To get access to Booking Experts Apps, please use the form below.
We will give you access to a Demo administration so you can start developing.
After you have access to your demo you can create Apps through the App Store. Follow the icon in your demo administration:
App Setup
Webhooks
Webhooks can be configured in the admin UI for managing Booking Experts Apps.
You can subscribe to various events that happen in Booking Experts.
Think of events like reservation:checked_in
, reservation:checked_out
, reservation:created
, category:updated
etc.
See the admin UI for a complete list.
Requirements
In order to receive webhook events for a resource, the following conditions apply:
- You must have read permissions for the given resource. Ensure you have properly set the permissions in your App configuration;
- In case the resource belongs to a specific administration, the status of the administration must be 'Test' or 'Production'.
Target URL
When an event is triggered in Booking Experts, the target URL you specified will be called. When you have configured the webhook to wait for confirmation, the target URL will be called until a 200 Success response is returned by your server.
Payload
The webhook payload contains the subject formatted in JSON.
So when reservation:checked_in
is triggered, you will receive a Reservation
resource as documented by the Reservation schema.
Commands
Let users trigger an interaction with your App by pressing a button in the Booking Experts UI.
Example use case: - Add a button called "Open door" to every Reservation detail page that can be triggered by receptionists.
Command responses
A submitted Command will cause a payload of data to be sent from Booking Experts to your App. The App can respond in different ways using the context provided by that payload.
I-frame URL
{ "iframe_url": "http://your-app.com/action-to-perform" }
The url is loaded in an iFrame inside Booking Experts. This gives the user the feeling that it all happens inside one system. Use our the Booking Experts Design System to create UIs by using UI components that are familiar to Booking Experts users.
Note: As a security measure, most browsers will require iframe sources to be on the same domain as the parent domain. If you are planning to use iFrames, please let us know so we can support your domain (for example by adding appropriate CORS headers).
Redirect URL
{ "redirect_url": "http://your-app.com/action-to-perform" }
The user is redirected to this URL. It's the responsibility of the App to provide a way back to Booking Experts.
Notice message
{ "notice": "Great success!" }
The message is shown to the user in a flash message inside Booking Experts.
Alert message
{ "alert": "Something went wrong!" }
The alert is shown to the user in a flash message inside Booking Experts.
Context model
Choose a context model to make commands available for a specific model.
For example, when you choose reservation
, the command will be available for reservations.
Mostly on the #show page (in CRUD terms) but not exclusively.
Enabled script
# Show the button when the reservation state is confirmed
reservation.dig(:data, :attributes, :state) == 'confirmed'
# Show the button when the reservation state is confirmed and its start date is equal or greater than the current date
reservation.dig(:data, :attributes, :state) == 'confirmed' && reservation.dig(:data, :attributes, :start_date) >= Time.zone.today
# Show the button when the invoice total is greater than 1.0 + 3.0 (4.0)
invoice.dig(:data, :attributes, :total, :value) > 1.0 + 3.0
# Show the button when the invoice number is present and the unpaid total is not 0.0
invoice.dig(:data, :attributes, :invoice_nr).present? && invoice.dig(:data, :attributes, :total_open, :value) != 0.0
# Show the button when the invoice number is blank
invoice.dig(:data, :attributes, :invoice_nr).blank?
When set, this script will be evaluated to determine whether a command should be available to a user. The last line of your script will be the result of the script. When the result is truthy, the command will be enabled.
The following variables will be available to you:
- The JSON serialized context model as defined in
context_model
. For example:reservation
. Conforms to the documented schema. Time.zone.today
- The current date in the time zone of the organization or administration.
The script language MUST be Ruby. The list of method calls you are allowed to make is limited to the following:
Allowed methods on any object:
==
!=
!
>
<
>=
<=
present?
blank?
Allowed methods on hash objects:
[]
dig
Allowed calculation methods:
+
-
*
/
Message templates
Define standard templates for communication with a guest.
Booking Experts takes care of delivering the message to the guest. Messages can be delivered by e-mail or SMS. Configured templates can be modified by administrators of an administration to suit their way of communication.
Booking Experts variables
{{ reservation.greeting }},
Welcome to {{ reservation.park.name }}!
The access code for accommodation {{ accommodation.name }} is: {{ access_code }}.
See you!
Within a template, you can use variables that are provided by Booking Experts, which are interpolated when the message is sent. Please see the Templates section of our support documentation for details.
Custom variables
Aside from Booking Experts variables, you can supply your own variables. Upon sending a message the App must provide the values for these custom variables.
In the example on the right {{ access_code }}
would be a custom veriable passed by the App.
Sending a message using a message template
See POST messages
Validation
Done with making your test integration? Let's book a validation. After validation, your App will be available in the Booking Experts App Store. Users can install your App at the touch of a button. A great way to reach new customers 😉.
A validation can be requested from the App admin page. The only requirement is an implemented OAuth2 flow.
Authentication
API key
Ideal for making one off Apps for your own use.
- Configure your App through My Apps and make sure to set "API key" as the Authentication method.
- Install your App within your own organization and you will be prompted with an "API key".
OAuth2 flow
You can authenticate organizations by using OAuth2. For on the fly needs you can make use of an API key but this has limited access to only the organization and its administrations to which it is registered.
If you want others to make use of your app you will need to support OAuth2. The flow for authenticating organizations via Oauth2 is described in the following diagram:
- First, store your OAuth2 client UID and secret. These have been supplied after your app was created and can be found on the admin page of the app
- When a user installs an app on behalf of the organization, a dialog will be shown listing all permissions that the app will need. When accepted, your specified redirect URI will be called with a code in the query string and nothing else. This follows the standard OAuth2 protocol. You need to use this code to fetch a token and refresh token via the
https://api.bookingexperts.nl/oauth/token
endpoint by passing the supplied code. Most oauth2 clients will use this path by default. - Per organization that successfully installs the app, you will receive a unique code which you need to turn into a token.
- After fetching a token, you can now access the API. Usually, the first thing to do is to fetch and persist the details of the subscription for the token you just received via the endpoint
https://api.bookingexperts.nl/v3/subscription
. This will yield the current subscription ID, the adminstration IDs to which you've been granted access and a return URL back to the BookingExperts app page. - You can now render a success response to the user. This could include a message explaining that the app has successfully been installed and an introductory message of how the user should proceed. It can also include a button back to the app page in BookingExperts as returned by the subscription details.
Guides
BookingExperts API client
There is a BookingExperts client example available, written in Ruby. This client supports the following use cases:
- OAuth2 workflow
- OAuth2 token management
- Incoming request verification using the HTTP_X_BE_SIGNATURE header
- Requesting resources and resource collections
Orders & Reservations
Currently, Booking Experts only supports creating reservations for a single accommodation. Support for ordering multiple accommodations is under active development. This will be accomplished by supporting Orders. Orders will be able to contain multiple Reservations, as illustrated in the diagram below.
The current API leverages this redesigned structure by already supporting creation of orders with a single reservation via POST reservation. When creation of orders with multiple reservations is added, this will become possible via the endpoint POST order.
Sideposting
As can be seen in the diagram, a Reservation belongs to an Order and and Order belongs to a Customer. As the JSON:API specification does not yet support
submission of multiple resources at once, we have introduced the concept of Sideposting. Sideposting will allow you to post new related resources using
the standard included array. These resources don't have an ID yet, therefore it is required to link these resources by setting /meta/temp_id
. You will also
need to define what the system needs to do with these resources by specifying /meta/method
(= create or update) on the relationship.
Creating a reservation
Endpoint: POST reservation
{
"data": {
"type": "reservation",
"attributes": {
"start_date": "2014-01-08",
"end_date": "2014-01-15",
"guest_group": {
"seniors": 0,
"adults": 2,
"adolescents": 0,
"children": 0,
"babies": 0,
"pets": 0
}
},
"relationships": {
"category": {
"data": {
"id": "123",
"type": "category"
}
}
}
}
}
For a reservation to be accepted, you need to (at least) specify the following attributes:
start_date
end_date
category
guest_group
A valid example can be seen on the right.
Creating an option
Endpoint: POST reservation
{
"data": {
"type": "reservation",
"attributes": {
"start_date": "2014-01-08",
"end_date": "2014-01-15",
"option_validity": 5,
"guest_group": {
"seniors": 0,
"adults": 2,
"adolescents": 0,
"children": 0,
"babies": 0,
"pets": 0
}
},
"relationships": {
"category": {
"data": {
"id": "123",
"type": "category"
}
}
}
}
}
In Booking Experts, an option is just a kind of reservation. To create an option, you
can use the same endpoint and pass the option_validity
attribute, which defines the option validity in days.
Creating a reservation with customer and order details
Endpoint: POST reservation
{
"data": {
"type": "reservation",
"attributes": {
"start_date": "2014-01-08",
"end_date": "2014-01-15",
"late_checkout": false,
"remote_booking_nr": "12345",
"locale": "en",
"note": "Please note",
"currency": "EUR",
"price_according_to_channel": { "currency": "EUR", "value": "85.75" },
"guest_group": {
"seniors": 0,
"adults": 1,
"adolescents": 0,
"children": 1,
"babies": 0,
"pets": 0
},
"license_plates": ["19XNZ1"]
},
"relationships": {
"category": {
"data": {
"id": "123",
"type": "category"
}
},
"order": {
"data": {
"type": "order",
"meta": {
"temp_id": "order-id",
"method": "create"
}
}
},
"primary_package": {
"data": {
"id": "1",
"type": "primary_package"
}
},
"extra_order_items": {
"data": [{
"type": "extra_order_item",
"meta": {
"temp_id": "extra-id",
"method": "create"
}
},{
"type": "extra_order_item",
"meta": {
"temp_id": "extra-package-id",
"method": "create"
}
}]
},
"cancellation_rules": {
"data": [{
"type": "cancellation_rule",
"meta": {
"temp_id": "cancellation-rule-1",
"method": "create"
}
},{
"type": "cancellation_rule",
"meta": {
"temp_id": "cancellation-rule-2",
"method": "create"
}
}]
}
}
},
"included": [{
"type": "order",
"attributes": {
"after_payment_return_url": "https://www.example.com/callback",
"redeemable_codes": ["DISCOUNT2021"]
},
"relationships": {
"customer": {
"data": {
"type": "customer",
"meta": {
"temp_id": "customer-id",
"method": "create"
}
}
}
},
"meta": {
"temp_id": "order-id"
}
},{
"type": "customer",
"attributes": {
"title": "family",
"first_name": "RIV",
"last_name": "Rowe",
"email": "leonmcglynn@example.com",
"phone": "+31612345678",
"is_company": false,
"date_of_birth": "1955-05-05",
"receive_newsletter": false,
"address": "78229 Marquerite Flat",
"number": null,
"postalcode": "03756",
"city": "Amsterdam",
"country_code": "NL",
"has_custom_invoice_details": true,
"custom_invoice_details": {
"name": "Ali",
"email": "mycompany@example.com",
"address": "Het Eeftink 11-12",
"postalcode": "7541 WH",
"city": "Enschede",
"country_code": "NL"
}
},
"meta": {
"temp_id": "customer-id"
}
},{
"type": "extra_order_item",
"attributes": {
"quantity": 2,
"guest_answer": "Guest answer"
},
"relationships": {
"extra": {
"data": {
"id": "245",
"type": "extra"
}
}
},
"meta": {
"temp_id": "extra-id"
}
},{
"type": "extra_order_item",
"relationships": {
"extra": {
"data": {
"id": "101",
"type": "extra_package"
}
}
},
"meta": {
"temp_id": "extra-package-id"
}
},{
"type": "cancellation_rule",
"attributes": {
"percentage": 33.3,
"days_before_arrival": 28,
"administration_costs": { "currency": "EUR", "value": "0.00" }
},
"meta": {
"temp_id": "cancellation-rule-1"
}
},{
"type": "cancellation_rule",
"attributes": {
"percentage": 100,
"days_before_arrival": 14,
"administration_costs": { "currency": "EUR", "value": "10.00" }
},
"meta": {
"temp_id": "cancellation-rule-2"
}
}]
}
Usually, you'll want to add some Customer details. Also, certain Order attributes may be relevant as well, like redeemable codes
or an after payment return url
. In this
case, you will need to use Sideposting to include these details when creating a new reservation.
The example on the right is a more complex example that shows how this can be accomplished This example does not only specify order and customer details, but also includes
some ordered extras (ExtraOrderItem) and a couple of custom cancellation rules (CancellationRule). Resource linking has been realized by properly setting temp_id
. As
these resources are new, the method passed in each relationship is create
.
Updating a reservation
Endpoint: PATCH reservation
{
"data": {
"id": "3245",
"type": "reservation",
"attributes": {
"start_date": "2014-01-08",
"end_date": "2014-01-15",
"currency": "EUR",
"guest_group": {
"seniors": 0,
"adults": 2,
"adolescents": 0,
"children": 0,
"babies": 0,
"pets": 0
}
},
"relationships": {
"category": {
"data": {
"id": "123",
"type": "category"
}
},
"order": {
"data": {
"id": "3245",
"type": "order",
"meta": {
"method": "update"
}
}
}
}
},
"included": [{
"id": "3245",
"type": "order",
"attributes": {
"redeemable_codes": ["DISCOUNT2021", "FREEFORALL"]
}
}]
}
A reservation and its order and customer details can be updated much in the same way as creating reservations. Of course, for existing resources you are now required to pass
their actual ID in stead of their temp_id
. If you like to update a related resource, you need to explicitly specify this by setting /meta/method
to update on the relationship.
As an example, consider the code on the right. It shows an example of how to update the redeemable codes
array of the order of a reservation.
Cancelling a reservation
Endpoint: POST cancel
{
"data": {
"id": "3245",
"type": "reservation",
"attributes": {
"cancel_date": "2014-01-05",
"cancel_reason": "CORONA",
}
}
}
A reservation can be cancelled by sending an existing reservation resource. Optionally, you can pass the cancel_date
and cancel_reason
attributes to set a custom date and reason for cancelling.
Access control
Access control systems can build an App to provide access to guests or accommodation owners of an administration. Using webhooks, access can automatically be granted at the appropriate time for reservations. Furthermore, commands can be used for manual creation of access cards or exemptions.
Setup
Nearly every app will have some form of authentication. You can easily create a Settings page
for your app by defining it as a command using the context model subscription
:
{ "iframe_url": "http://your-app.com/settings" }
When called, you can then respond with a redirect to your Settings page. An example response can be seen on the right.
Automatically granting access for reservations
Typically, the following webhooks are needed for automatically granting access for reservations:
reservation|confirmed
- To grant access when a reservation is confirmed
reservation|checked_in
- To grant access when a reservation is checked in
-
reservation|moved
- Will be triggered when the stay period or accommodation of the reservation has been changed, so you can update its access.
-
reservation|checked_out
- To revoke access when the reservation is checked out
-
reservation|cancelled
- To revoke access when the reservation is cancelled
Manually granting access for reservations
Using commands, you can also add buttons to reservations to allow users of the system to manually manage access for a reservation.
Energy management
{
"data": [
{
"type": "measurement",
"attributes": {
"timestamp": "2017-05-23T11:54+02:00",
"utility": "electricity",
"rate": null,
"value": 49.9
}
},
{
"type": "measurement",
"attributes": {
"timestamp": "2017-05-23T11:54+02:00",
"utility": "gas",
"rate": null,
"value": 40.584
}
},
{
"type": "measurement",
"attributes": {
"timestamp": "2017-05-24T11:54+02:00",
"utility": "electricity",
"rate": null,
"value": 52.9
}
},
{
"type": "measurement",
"attributes": {
"timestamp": "2017-05-24T11:54+02:00",
"utility": "gas",
"rate": null,
"value": 45.223
}
}
]
}
Energy management system Apps are usually implemented in the same way as Access Control Apps: there is some initial configuration, after which all booked accommodations are managed by listening to Reservation webhook events.
Supplying measurements
As it is possible in Booking Experts to store accommodation measurements, an Energy Management App is also able to send measurements back to Booking Experts. This can be realized by creating a special command that willl only be called by Booking Experts when an App is defined as an Energy system.
The command itself must conform to the following specifications:
- Its identifier must be
measurements
- Its context model must be
rentable_identity
- The response of the command must by a list of resources that conforms to the Measurement Schema. An example response can be seen on the right.
Payments
Payment service providers can build an App to handle payments. There are a couple of requirements. See below.
Payment provider requirements
Apps that act as a payment provider must provide an command with identifier initiate_payment
and context model invoice
.
When this command is called, you will receive the following (additional) parameters:
amount
- The requested amount to be paidcurrency
- The currency of the amount as an ISO 4217 currency code
The response of this command must be a redirect URL to a payment page when no issues occur, otherwise it should return a notice or an alert.
Handling a payment
- The redirect URL you have specified will be called with a
back_url
, which should be called after a payment attempt has been done - The app itself must handle all callbacks and create a payment in Booking Experts when the invoice has been paid
- After (partial) payment, the
back_url
must be called with astatus
parameter, which is set to one of the following values:success
- when the payment was successfulopen_but_confirmed
- when a payment has been made, but is still pendingopen
- when no payment has been made yetfailure
- when the payment failed
Tour operators
A tour operator App is usually responsible for the following actions:
- Creating a channel in Booking Experts
- Creating category mappings (Booking Experts category X corresponds to external resource Y)
- Pushing the latest availability of categories
- Pushing the latest prices of categories
- Fetching new reservations and pushing updates to Booking Experts
This guide is applicable to Channel management as well.
Relevant permissions
A tour operator will usually need the following permissions:
channel::reservation|read
channel::customer|read
channel::order|read
category|read
reservation|write
channel|write
internal_message|write
Relevant webhooks
A tour operator will usually need the following webhooks:
category|reindexed
- Triggered when the availability or prices of a category have been changed. In a future version, availibility and price update events will be split into two separate events.
category|updated
- Triggered when attributes of the category have changed.
A special case is that a category can also become
archived
, which means it is not used anymore, but has not permanently been deleted because it is still asociated to certain reservations. Therefore, when the attributearchived
istrue
, the availability and prices of the category must be cleared.
- Triggered when attributes of the category have changed.
A special case is that a category can also become
category|deleted
- When a category is permanently deleted, the mapping can be removed and the availability and prices must be cleared.
Creating a channel
{
"data": {
"type": "channel",
"attributes": {
"name": "TourOperator.com",
"kind": "tour_operator",
"available_currencies": ["EUR"]
}
}
}
Channels in Booking Experts are used to track the origin of reservations. A channel can also store the pricing type used. We currently support 'simple prices' (night prices) and 'complex prices' (LOS prices). When an organization subscribes to your App, it is possible to associate a channel to each administration of the organization you get access to. However, it is also possible for the App to create a new channel instead.
To create a channel, you will need the channel|write
permission. Please see the POST channels
endpoint for more information. An example can be seen on the right.
Pushing availability and prices
Availability and prices for a category can be fetched in a couple of ways. The way to go is dependent
on the information you need and the pricing type that you use. You will need the avaiability|read
permission for these endpoints.
- When using simple night prices, use the GET night prices endpoint.
It returns the price and stock for each available date. This endpoint also supports the
If-Modified-Since
header.- When using complex LOS prices, use the GET LOS prices endpoint.
For each date, it returns a record with price and stock for each LOS. This endpoint also supports the
If-Modified-Since
header. - When using complex LOS prices, you can also use the GET availabilities endpoint instead. Besides price and availability, this will also return the rent price, original price and discount price. It also returns the expected check-in and check-out time of reservations.
- When using complex LOS prices, use the GET LOS prices endpoint.
For each date, it returns a record with price and stock for each LOS. This endpoint also supports the
Note Currently, when receiving a category_reindexed
event, you need to manually figure out which prices have changed if you only want to store differences in availability and prices.
This can easily be achieved by storing the last processed response and comparing this to the current response.
Pushing updates to Booking Experts
To create, update or cancel reservations, you can use the Channel Reservations endpoint. You will
need the reservation|write
permission to do this. More information on how to create or update reservations van be found in the Reservations guide.
When things go wrong
Occasionally, problems may occur when keeping reservations in sync. For example, a conflict may occur when a certain period has already been booked in Booking Experts. For these cases, it
is possible to send an internal message to the administration. You can use the POST internal_message endpoint. You will
need the internal_message|write
permission to do this.
Release notes
2020-05-19
Released new API version 3