Bókun API Documentation

Getting started

API Endpoint

RESTful

Passing Request Data

Language and currency

Output Formats

API keys and Authentication Request headers

Test sandbox access to API and Swagger UI

Java client

The Booking process and Payment processing

Activities

Search

Filtering

Sorting

Pagination

Get Activity by ID

Get Activity by Slug

Get Pick up / Drop off places for an Activity

Get availabilities for an Activity on a date range

Get upcoming availabilities for an Activity

Check prices for activity booking

Accommodation

Search

Filtering

Sorting

Pagination

Get Accommodation by ID

Get Accommodation by Slug

Get Accommodation Rooms grouped by Room Type

Get available Room Types for an Accommodation

Get Room type availabilities for Accommodations on a date range

Get Room availabilities for a given stay interval

Car Rentals

Search vehicles

Filtering

More about geo filters in an appendix later in this document.

Sorting

Pagination

Get Car Rental by ID

Get Car Rental by Slug

List all Car Rentals

Transport

List routes

Get route by ID

Check availability

Product Lists

List all Product Lists

Get Product List by ID

Get Product List by Slug

Shopping Cart

Add Products to Shopping Cart

Remove Products from Shopping Cart

Add / update / remove Extras on Products in Shopping Cart

Get the Shopping Cart

Apply promo code to shopping cart

Remove promo code from shopping cart

Bookings

Get questions for the Booking

Reserve a Booking

Move a reserved Booking back to the Shopping Cart

Abort a reserved Booking

Confirm a reserved Booking

Get a list of reserved bookings

Pay for a booking using a credit card

Reserve, Pay & Confirm Booking

Activity - Reserve and confirm single activity booking

Accommodation - Reserve and confirm single activity booking

Transport - Reserve and confirm single route booking

Operations services

Product Booking Search

Accommodation Booking Details

Activity Booking Details

Route Booking Details

Car Rental Booking Details

Cancel booking

Edit booking

Cancel product booking

Accommodation Booking - Change customer status

Activity Booking - Change customer status

Route Booking - Change customer status

Car Rental Booking - Change customer status

Update customer details

Get Ticket and Order Summary

Tags

Currencies

Languages

Countries

Appendix

Geo filtering

Geo Distance Filter

Geo Distance Range Filter

Geo Bounding Box Filter

Geo Polygon Filter

Tag filtering and Search facets

Filtering by Tags using Facet Filters

Excluding Tags using Facet Filters

Affiliate tracking

Getting started

API Endpoint

All API URLs listed in this documentation are relative to https://api.bokun.is/. For example, the /activity.json/search API call is reachable at https://api.bokun.is/activity.json/search.

RESTful

The Bókun API is a mostly RESTful API.

Passing Request Data

Request data is passed to the API by POSTing JSON objects to the API endpoints with the appropriate parameters. The documentation for each API call will contain more detail on the parameters accepted by the call.

Language and currency

All the API services that return product information accept language and currency as parameters. These parameters are always supplied as query string parameters (lang and currency) in the URL to the service.

Output Formats

We support one output format at this time: JSON.

API keys and Authentication Request headers

To access the web services, you will need an API key. The API key consists of an access key and a secret key. You will need to use these keys to create a signature header that authenticates your calls to the API.

The required request headers are:

The X-Bokun-Signature is created using the following technique:

  1. Create a string by concatenating the following:
  1. Create a signature with the secret key, taking the concatenated string as input, using the “HmacSHA1” algorithm.
  2. Base64 encode the signature.

The web service call will fail if the signature is not correct, or if the date is too far in the past.

Example:

Let’s say we’re calling the activity search service. We want the results in English and prices in Icelandic Krona (ISK). We have the following:

Let’s say our secret key is 23e2c7da7f7048e5b46f96bc91324800. Now, let’s calculate the signature. First we concatenate the values into a string:

So the string (date+accesskey+httpmethod+path) becomes:

2013-11-09 14:33:46de235a6a15c340b6b1e1cb5f3687d04aPOST/activity.json/search?lang=EN&currency=ISK

We then use this, along with the secret key to calculate the HmacSHA1 value for the signature, and Base64 encode it:

This site is good for checking your signature: http://hash.online-convert.com/sha1-generator 

For POST requests you must also indicate the content type of the post body:

Test sandbox access to API and Swagger UI

We can provide test access to the API, loaded with test data. This test access comes with a web page where all the API services can be tested by entering JSON and viewing the response. The API endpoint for the test server is https://api.bokuntest.com. The test UI can be accessed at http://bokun.github.io/api-docs/ 

Java client

Bókun provides an open source Java client for the API. You can download the Java client from https://bitbucket.org/bokundev/bokun_api.

The Booking process and Payment processing

The following diagram describes the flow of adding to the cart, reserving booking and confirming booking.

Activities

Search

POST

/activity.json/search

Get a list of all activities, and filter the list by searching. Posting a empty json object {} will return all activities available to your vendor to sell.

Example Request JSON

{

  "participants": 2,

  "startDate": "2013-11-11",

  "endDate": "2013-11-18"

}

This would search for all tours & activities that are available for 2 participants within the date range specified. Sending an empty JSON object {} will return all tours & activities.

The price returned for each item in the search results:

Filtering

The search supports various filtering options.

Availability

Filtering by availability is done by specifying the number of participants / passengers, and a date range. Only activities that have departures / start times on the specified date range with available seats for all the participants will be returned.

{

  "participants": 2,

  "startDate": "2013-11-11",

  "endDate": "2013-11-18"

}

Bókun will also return a price for each activity in the search results. The price is the lowest total price for all participants on the date range.

Many tours & activities specify different pricing based on age groups (e.g. adults, teens, children). Therefore, if you know the ages of all participants, you can specify participantsByAge for more accurate price calculation. This is simply a list of the ages of the participants. Example:

{

  "participantsByAge": [35,16,4],

  "startDate": "2013-11-11",

  "endDate": "2013-11-18"

}

Price

Results can be filtered by price.

{

  "participantsByAge": [35,16,31,4],

  "startDate": "2013-11-11",

  "endDate": "2013-11-18",

  "priceRangeFilter": {

    "from": 15000,

    "to": 40000

  }

}

You can omit either to or from to leave the range open ended. The search results will also contain information about the highest and lowest prices in the results (see the price facet under “Tag filtering and search facets” later in this document).

Text

Results can be filtered by searching for text. To use the text filter, specify the text to search for, the operator (“and” or “or”), and what parts of the content to search. Note that finding a match in title or keywords will score higher than a match in the full text.

{

  "textFilter": {

    "text": "golden circle",

    "operator": "and",

    "searchTitle": true,

    "searchKeywords": true,

    "searchFullText": false

  }

}

Location

Activities can be filtered by location. This will apply a geo filter to the locations in the activity agenda items. Bókun supports a number of geo filters. Following is an example of a geo distance filter, finding activities that have a place in the agenda which is within a set distance from a center point:

{

  "agendaLocationFilters": {

    "geoDistanceFilter": {

      "center": {

        "lat": 64.135338,

        "lng": -21.895210

      },

      "distance": "100km"

    }

  }

}

More about geo filters in an appendix later in this document.

Sorting

The activity results can be sorted by:

        BEST_SELLING_GLOBAL

        BEST_SELLING_BY_VENDOR

        BEST_SELLING_IN_CHANNEL

        ALPHABETIC

        RANDOM

For example:

{

  "sortField": "BEST_SELLING_IN_CHANNEL",

  "sortOrder": "desc"

}

Pagination

If the result set is very large, it can be useful to divide it up into pages. The API supports this. If omitted, the default page size is 20 items.

{

  "page": 1,

  "pageSize": 50

}

Get Activity by ID

GET

/activity.json/{id}

Get the full information about an Activity by supplying the ID.

Get Activity by Slug

GET

/activity.json/slug/{slug}

Get the full information about an Activity by supplying a language-dependent slug. A slug is a few words that uniquely identify the product. Slugs are usually a URL friendly version of the product title. Slugs are useful when you want a search engine friendly URL to point to a product, without using an ID in the URL. A product can have different slugs for different languages.

Get Pick up / Drop off places for an Activity

GET

/activity.json/{id}/pickup-places

Get a list of the places offered as pick up / drop off places for the Activity with the ID supplied.

Get availabilities for an Activity on a date range

GET

/activity.json/{id}/availabilities

Get a list of all availabilities for all departures / start times for the activity on the date range specified. The returned availabilities are sorted in date order.

Path parameters:

The following parameters are sent as query string parameters:

Get upcoming availabilities for an Activity

GET

/activity.json/{id}/upcoming-availabilities/{max}

Get a list of the next {max} upcoming availabilities for all departures / start times for the activity, from the date when the call is executed. The returned availabilities are sorted in date order. The parameters are sent as query string parameters:

Check prices for activity booking

POST

/activity.json/check-prices

Check how much an activity booking would cost. The request body should contain a description of the booking:

{

  "activityId": 123,

  "startTimeId": 456,

  "date": "2013-11-24",

  "pricingCategoryBookings": [

    { "pricingCategoryId": 111 },

    { "pricingCategoryId": 111 },

    { "pricingCategoryId": 112 }

  ],

  "pickup": true,

  "pickupPlaceId": 444,

  "pickupPlaceRoomNumber": "112",

  "extras": [

    { "extraId": 222, "unitCount": 1 }

  ]

}

Accommodation

Search

POST

/accommodation.json/search

Get a list of all accommodation items, and filter the list by searching.

Example Request JSON

{

  "startDate": "2013-11-11",

  "endDate": "2013-11-13",

  "rooms": [{

    "adults": 2

  }]

}

This would search for all accommodations that have a room available that can take 2 adults within the date range specified. Sending an empty JSON object {} will return all accommodations.

Filtering

The search supports various filtering options.

Availability

Filtering by availability is done by specifying the number of rooms needed (along with the number of people staying in each room), and a date range. Only accommodations that have available rooms for the query on the specified date range will be returned.

{

  "startDate": "2013-11-11",

  "endDate": "2013-11-13",

  "rooms": [{

    "adults": 2

  }]

}

Bókun will also return a price for each accommodation in the search results. The price is the lowest total price for all rooms needed at the accommodation on the date range.

If there are children staying in the rooms, you can specify their age as well (accommodations may have different rules for the min age for a separate bed). This is specified as a list of the ages of the children per room. Example:

{

  "startDate": "2013-11-11",

  "endDate": "2013-11-13",

  "rooms": [{

    "adults": 2,

    "children": [4,12]

  },{

    "adults": 1

  }]

}

Text

Results can be filtered by searching for text. To use the text filter, specify the text to search for, the operator (“and” or “or”), and what parts of the content to search. Note that finding a match in title or keywords will score higher than a match in the full text.

{

  "textFilter": {

    "text": "romantic",

    "operator": "and",

    "searchTitle": true,

    "searchKeywords": true,

    "searchFullText": false

  }

}

Location

Accommodations can be filtered by their location. Bókun supports a number of geo filters. Following is an example of a geo distance filter, finding accommodations within a set distance from a center point:

{

  "locationFilters": {

    "geoDistanceFilter": {

      "center": {

        "lat": 64.135338,

        "lng": -21.895210

      },

      "distance": "100km"

    }

  }

}

More about geo filters in an appendix later in this document.

Sorting

The activity results can be sorted by:

        BEST_SELLING_GLOBAL

        BEST_SELLING_BY_VENDOR

        BEST_SELLING_IN_CHANNEL

        DISTANCE

        ALPHABETIC

        RANDOM

For example:

{

  "sortField": "DISTANCE",

  "sortOrder": "asc"

}

Pagination

If the result set is very large, it can be useful to divide it up into pages. The API supports this. If omitted, the default page size is 20 items.

{

  "page": 1,

  "pageSize": 50

}

Get Accommodation by ID

GET

/accommodation.json/{id}

Get the full information about an Accommodation by supplying the ID.

Get Accommodation by Slug

GET

/accommodation.json/slug/{slug}

Get the full information about an Accommodation by supplying a language-dependent slug. A slug is a few words that uniquely identify the product. Slugs are usually a URL friendly version of the product title. Slugs are useful when you want a search engine friendly URL to point to a product, without using an ID in the URL. A product can have different slugs for different languages.

Get Accommodation Rooms grouped by Room Type

GET

/accommodation.json/{id}/rooms

Get a list of all rooms for a particular Accommodation.

NOTE: this will only return a valid response for the Accommodation supplier (i.e. the supplier must be the one sending the request). Resellers are not allowed to get the room list for an accommodation.

Example JSON response

You will get a JSON object back with the room availabilities:

{

"roomsGroupedByType": [

    {

      "roomType": {

        "id": 79,

        "title": "Single room"

        ...

      },

      "rooms": [

        {

          "id": 347,

          "title": "301"

        },

        {

          "id": 348,

          "title": "302"

        },

        {

          "id": 349,

          "title": "303"

        },

        {

          "id": 350,

          "title": "304"

        },

        {

          "id": 351,

          "title": "305"

        }

      ]

    }

  }

]

}

Get available Room Types for an Accommodation

POST

/accommodation.json/{id}/check-availability

Check which room types are available on a specific date range for a selected accommodation. This is useful to show available room types when an accommodation has been selected.

{

  "startDate": "2013-11-11",

  "endDate": "2013-11-13",

  "rooms": [{

    "adults": 1

  }]

}

Get Room type availabilities for Accommodations on a date range

GET

/accommodation.json/availabilities

Get a list of all availabilities for all room types for the accommodations with the IDs supplied on the date range specified. The returned availabilities are sorted in date order. This call will give you day-by-day availability for each room type (how many available rooms of each room type per day). This can be useful, for example, to draw a calendar showing available rooms for an accommodation.

The parameters are sent as query string parameters:

You will get a JSON object back, with a list which has information about the available rooms and prices for each accommodation.

{

  "startDate": "2015-07-01",

  "endDate": "2015-07-03",

  "accommodations": [

    {

      "accommodation": {

              ... info about the accommodation ...

      },

      "rooms": [

        {

                "room": {

                        ... info about the room ...

                },

                "availabilities": [

                    {

                      "date": "2015-07-01",

                      "available": 7,

                      "price": 13990

                    },

                    {

                      "date": "2015-07-02",

                      "available": 7,

                      "price": 13990

                    },

                    ...

                ]

        }

      ]

         }

  ]

}

Get Room availabilities for a given stay interval

POST

/accommodation.json/check-room-availability

Get a list of all rooms available for a given stay interval (note that this is “rooms” not “room types”).

NOTE: this will only return a valid response for the Accommodation supplier (i.e. the supplier must be the one sending the request). Resellers are not allowed to check availability of specific rooms at their supplier’s accommodation.

Example JSON request

You should POST a JSON body containing the accommodation ID, and the check in and check out dates:

{

  "accommodationId": 123,

  "checkIn": "2017-11-11",

  "checkOut": "2017-11-13"

}

Example JSON response

You will get a JSON object back with the room availabilities:

{

  "roomAvailabilities": [

    { "roomId": 123, "roomAvailable": true },

    { "roomId": 456, "roomAvailable": false },

  ]

}

Car Rentals

Search vehicles

POST

/car-rental.json/search-cars

Get a list of all rental cars, and filter the list by searching. Posting a empty json object {} will return all cars available to your vendor to sell.

Example Request JSON

{

  "startDate": "2013-11-11 12:00",

  "endDate": "2013-11-13 12:00"

}

This would search for all vehicles types that are available on the date range specified. Sending an empty JSON object {} will return all vehicle types.

Filtering

The search supports various filtering options.

Availability

Filtering by availability is done by specifying a date range. Only vehicle types that are available on the specified date range will be returned. Note that the dates must include time (hours and minutes)! The hour is specified on a 24 hour format.

{

  "startDate": "2013-11-11 12:00",

  "endDate": "2013-11-13 14:00"

}

Bókun will return the total rental price (rentalPrice) for each vehicle in the search results, and also the average rental price per day.

Text

Results can be filtered by searching for text. To use the text filter, specify the text to search for, the operator (“and” or “or”), and what parts of the content to search. Note that finding a match in title or keywords will score higher than a match in the full text.

{

  "textFilter": {

    "text": "Toyota",

    "operator": "and",

    "searchTitle": true,

    "searchKeywords": true,

    "searchFullText": false

  }

}

Vehicle properties

Vehicles can also be filtered by various properties. Here are some of the filtering options you can use (just for demonstration purposes, as you would rarely use all these combined!):

{

    "carRentalIds": [123,456],

    "carRentalSlug": "my-car-rental",

    "carTypeIds": [222,333],

    "flags": ["4x4"],

    "driverAge": 20,

    "passengers": 4,

    "luggage": 3,

    "minDoorCount": 2,

    "airConditioning": true,

    "co2EmissionFilter": {

        "to": 10

    },

    "fuelEconomyFilter": {

        "to": 8

    },

    "airConditioning": true

}

Pick up / Drop off Location

Vehicles can be filtered by their pick up / drop off location (as different vehicle types may be available at different locations). This can be done in two ways:

If you have retrieved the available rental locations for the car rental, you could display these in a dropdown box and allow the customer to select. In this case you would filter by the ID of the rental location (you can specify multiple IDs if needed):

{

  "pickupLocationIds": [123,456]

}

But you could also do this via a geo search. Bókun stores the map location for each vehicle rental location. Bókun supports a number of geo filters. Following is an example of a geo distance filter, finding vehicle types at rental locations within a set distance from a center point:

{

  "pickupLocationFilters": {

    "geoDistanceFilter": {

      "center": {

        "lat": 64.135338,

        "lng": -21.895210

      },

      "distance": "100km"

    }

  }

}

More about geo filters in an appendix later in this document.

Sorting

The activity results can be sorted by:

        BEST_SELLING_GLOBAL

        BEST_SELLING_BY_VENDOR

        BEST_SELLING_IN_CHANNEL

        DISTANCE

        ALPHABETIC

        RANDOM

For example:

{

  "sortField": "DISTANCE",

  "sortOrder": "asc"

}

Pagination

If the result set is very large, it can be useful to divide it up into pages. The API supports this. If omitted, the default page size is 20 items.

{

  "page": 1,

  "pageSize": 50

}

Get Car Rental by ID

GET

/car-rental.json/{id}

Get the full information about a Car Rental by supplying the ID. This will contain information about all rental locations, vehicle types, etc.

Get Car Rental by Slug

GET

/car-rental.json/slug/{slug}

Get the full information about a Car Rental by supplying a language-dependent slug. A slug is a few words that uniquely identify the product. Slugs are usually a URL friendly version of the product title. Slugs are useful when you want a search engine friendly URL to point to a product, without using an ID in the URL. A product can have different slugs for different languages.

List all Car Rentals

GET

/car-rental.json/list

Get a list of all available Car Rentals.

Transport

List routes

GET

/route.json/list

Get route by ID

GET

/route.json/{id}

Check availability

POST

/route.json/check-availability

Request must have a transport query in the body:

{

    "departureDate": "2016-02-22",

    "sourceStationId": 57,

    "destStationId": 58,

    "routeIds": [9],

    "pricingCategories": [{

        "categoryId": 3646,

        "passengers": 2

    }],

    "maxRoutes": 0,

    "maxLegs": 0,

    "maxPaths": 5,

    "weightType": "PRICE"

}

Which will then return an availability report for the route chosen:

{

    "departureDate": [

        2016,

        2,

        22

    ],

    "returnDate": null,

    "from": {

        "id": 57,

        "title": "Keflavik airport",

        "shortTitle": "KEF",

        ...

    },

    "to": {

        "id": 58,

        "title": "BSÍ",

        "shortTitle": "BSÍ",

        ...

    },

    "query": {

        "pricingCategories": [{

            "categoryId": 3646,

            "passengers": 2

        }],

        "passengers": 0,

        "departureDate": "2016-02-22",

        "sourceStationId": 57,

        "destStationId": 58,

        "routeIds": [

            9

        ],

        "maxRoutes": 0,

        "maxLegs": 0,

        "maxPaths": 5,

        "weightType": "PRICE"

    },

    "results": [{

        "departurePath": {

            "legs": [{

                "route": {

                    "id": 9,

                    ...

                },

                "leg": {

                    "id": 98,

                    "distance": 0,

                    "distanceUnit": "KILOMETERS",

                    "flexibleSchedule": true,

                    "from": {

                        "id": 57,

                        "title": "Keflavik airport",

                        "shortTitle": "KEF",

                        ...

                    },

                    "to": {

                        "id": 58,

                        "title": "BSÍ",

                        "shortTitle": "BSÍ",

                        ...

                    },

                    "schedules": [{

                        "id": 228,

                        "departureHour": 0,

                        "departureMinute": 0,

                        "arrivalHour": 0,

                        "arrivalMinute": 45,

                        "peak": false,

                        "flags": [

                            "daily"

                        ],

                        "departureTimeStr": "00:00",

                        "arrivalTimeStr": "00:45"

                    }]

                },

                "departure": {

                    "schedule": {

                        "id": 228,

                        "departureHour": 0,

                        "departureMinute": 0,

                        "arrivalHour": 0,

                        "arrivalMinute": 45,

                        "peak": false,

                        "flags": [

                            "daily"

                        ],

                        "departureTimeStr": "00:00",

                        "arrivalTimeStr": "00:45"

                    },

                    "availableSeats": [{

                        "fareClassId": "passengers",

                        "capacity": {

                            "capacityType": "UNLIMITED",

                            "capacity": 25

                        }

                    }],

                    "prices": {

                        "priceList": [{

                            "pricingCategory": {

                                "id": 3646,

                                "title": "Adults",

                                "ageQualified": true,

                                "minAge": 16,

                                "maxAge": 0,

                                "defaultCategory": true,

                                "fullTitle": "Adults (16+)"

                            },

                            "peak": false,

                            "returnTicket": false,

                            "price": {

                                "foundPrice": true,

                                "unModulatedPrice": {

                                    "amount": 1950,

                                    "currency": "ISK"

                                },

                                "price": {

                                    "amount": 1950,

                                    "currency": "ISK"

                                },

                                "discount": 0,

                                "discountAmount": {

                                    "amount": 0,

                                    "currency": "ISK"

                                },

                                "currency": "ISK",

                                "costMatrixId": 80,

                                "appliedModulators": [],

                                "priceWithDiscount": {

                                    "amount": 1950,

                                    "currency": "ISK"

                                }

                            }

                        }}]

                    }

                },

                "departureDate": 1456099200000

            }]

        },

        "returnPath": null,

        "resultsType": "SINGLE_ROUTE_FLEX"

    }]

}

If the results list is empty, then no route was available using the constraints supplied.

Product Lists

A product list is a list of hand-picked products - in a manually controlled order. A product list can contain a mixture of product types.

List all Product Lists

GET

/product-list.json/list

Get a list of all published Product Lists. This will return a brief description of the lists available, along with the size of each list. This service does not return the list items.

Get Product List by ID

GET

/product-list.json/{id}

Get the full information about a Product List by supplying the ID. This will contain the product list items as well. You can supply a comma separated list of flags and category IDs to filter the product list items, for example:

/product-list.json/{id}?flags=sightseeing,whales&categoryIds=1,2

If you specify flags or category IDs, then only the product list items that have all the flags you specify and are in all the categories you specify will be returned.

Get Product List by Slug

GET

/product-list.json/slug/{slug}

Get the full information about a Product List by supplying a language-dependent slug.  This will contain the product list items as well. You can supply a comma separated list of flags and category IDs to filter the product list items, for example:

/product-list.json/slug/{slug}?flags=sightseeing,whales&categoryIds=1,2

If you specify flags or category IDs, then only the product list items that have all the flags you specify and are in all the categories you specify will be returned.

Shopping Cart

Bókun supports two types of shopping carts:

For sake of brevity we’ll describe the session cart calls here, and then provide a list of the customer cart calls (as these are very similar).

Add Products to Shopping Cart

Note: all these calls can accept a tracking code parameter in the query string. The tracking code for an affiliate can be found in the extranet. This is used for affiliate tracking (see appendix). Example:

/shopping-cart.json/session/{sessionId}/activity?trackingCode=204998ac7a9d471d8c88e789fcbfe75d&lang=EN&currency=ISK

Activity

POST

/shopping-cart.json/session/{sessionId}/activity

{

    "activityId": 123,

    "startTimeId": 456,

    "date": "2013-11-24",

    "pricingCategoryBookings": [

        {

            "pricingCategoryId": 111,

            "extras": [

                {

                    "extraId": 222,

                    "answers": [{

                        "name": "extra-info",

                        "answers": [{

                            "type": "extra-question",

                            "question": "Which size do you use?",

                            "answer": "Large",

                            "questionId": 27

                        }]

                    }]

                }

            ]

        },

        {

            "pricingCategoryId": 111,

            "extras": [

                {

                    "extraId": 222,

                    "answers": [{

                        "name": "extra-info",

                        "answers": [{

                            "type": "extra-question",

                            "question": "Which size do you use?",

                            "answer": "Small",

                            "questionId": 27

                        }]

                    }]

                }

            ]

        },

        { "pricingCategoryId": 112 }

    ],

    "pickup": true,

    "pickupPlaceId": 444,

    "pickupPlaceRoomNumber": "112"

}

Accommodation

POST

/shopping-cart.json/session/{sessionId}/accommodation

{

  "accommodationId": 234,

  "checkinDate": "2013-11-24",

  "checkoutDate": "2013-11-26",

  "travelType": "LEISURE",

  "rooms": [

    {

      "roomTypeId": 121,

      "roomRateId": 333,

      "roomId": 444,

      "adults": 2,

      "children": 0,

      "infants": 0,

      "extras": [

        { "extraId": 222, "unitCount": 1 }

      ],

      "guests": [ // optional details for the guests

        {

          "firstName": "John",

          "lastName": "Doe",

          "nationality": "UK",

          "email": "john.doe@example.com",

          "phoneNumber": "+1 555 55555",

        }

      ]

    }

  ]

}

Valid values for travelType are ['BUSINESS' or 'LEISURE' or 'CONFERENCE'].

The attributes you can supply for a guest are following:

Rental car

POST

/shopping-cart.json/session/{sessionId}/car-rental

{

  "carRentalId": 345,

  "pickupDate": "2013-11-24 13:00",

  "pickupLocationId": 777,

  "dropoffDate": "2013-11-26 09:00",

  "dropoffLocationId": 778,

  "cars": [

    {

      "carTypeId": 131,

      "unitCount": 1

      "extras": [

        { "extraId": 232, "unitCount": 1 }

      ]

    }

  ]

}

Transport route

POST

/shopping-cart.json/session/{sessionId}/route

{

        "departureDate": "2016-02-20",

        "returnDate": null,

        "pathSegments": [{

            "routeId": 1,

            "returning": false,

            "departureSchedules": [{

                "routeLegId": 1,

                "scheduleId": 1,

                "pickupPlaceId": null,

                "dropoffPlaceId": null

            }],

            "returnSchedules": [],

            "passengerSpecification": {

                "fareClassId": null,

                "passengerSpecifications": [{

                    "categoryId": 4,

                    "passengers": 2

                }]

            }

        }]

}

Remove Products from Shopping Cart

Products are removed by providing the ID of the relevant product booking.

GET

/shopping-cart.json/session/{sessionId}/remove-activity/{activityBookingId}

GET

/shopping-cart.json/session/{sessionId}/remove-accommodation/{accommodationBookingId}

GET

/shopping-cart.json/session/{sessionId}/remove-room/{roomBookingId}

GET

/shopping-cart.json/session/{sessionId}/remove-car-rental/{carRentalBookingId}

GET

/shopping-cart.json/session/{sessionId}/remove-car/{carBookingId}

GET

/shopping-cart.json/session/{sessionId}/remove-route/{routeBookingId}

Add / update / remove Extras on Products in Shopping Cart

Extras can be added to products in the shopping cart. Extras can also be updated and removed.

Add or update Extra

POST

/shopping-cart.json/session/{sessionId}/add-or-update-extra/{bType}/{bId}

Here the {bType} is one of the following, depending on what type of product the extra is being added to:

The {bId} is the relevant booking ID (room booking ID / activity booking ID / car booking ID). The POST body should be on the following format:

{

  "extraId": 232,

  "unitCount": 1

  "answers": [...]

}

Remove Extra

GET

/shopping-cart.json/session/{sessionId}/remove-extra/{bType}/{bId}/{eId}

Here the {bType} and {bId} are the same as when adding/updating. The {eId} is the ID of the extra that is to be removed.

Get the Shopping Cart

This call will return the shopping cart with the item prices, and will calculate the total price for the whole cart.

GET

/shopping-cart.json/session/{sessionId}

Apply promo code to shopping cart

This call allows you to apply a promo code to the shopping cart. It will return the shopping cart with any discount applied. You supply the promo code as an URL query parameter.

GET

/shopping-cart.json/session/{sessionId}/apply-promo-code?promoCode=SALE

Remove promo code from shopping cart

This call allows you to remove any promo code from the shopping cart. It will return the updated shopping cart.

GET

/shopping-cart.json/session/{sessionId}/remove-promo-code

Bookings

The booking services generate questions that need answering from the customer, move bookings from the Shopping Cart to a RESERVED state (usually before payment), and then to a CONFIRMED state (usually after successful payment).

There is a set of services for session carts and customer carts. Here, again, we’ll cover the session (guest) ones, as the customer services are very similar (different URLs).

Get questions for the Booking

Different products will require the customer answering different questions. For example, the customer may have selected to rent hiking shoes (bookable extra) with her trip to the glacier - in which case the supplier may wish to know the shoe size.

GET

/booking.json/guest/{sessionId}/questions

This will result in JSON on the following format:

{

  "questions": [

    {

      "type": "first-name",

      "question": "First name",

      "selectFromOptions": false,

      "defaultAnswer": null,

      "answerRequired": true,

      "options": [],

      "id": null

    },

    {

      "type": "last-name",

      "question": "Last name",

      "selectFromOptions": false,

      "defaultAnswer": null,

      "answerRequired": true,

      "options": [],

      "id": null

    },

    {

      "type": "email",

      "question": "Your email address",

      "selectFromOptions": false,

      "defaultAnswer": null,

      "answerRequired": true,

      "options": [],

      "id": null

    },

    ... and more questions about the customer paying the booking ...

  ],

  "accommodationBookings": [

    ...questions related to any accommodation bookings in the cart ...

  ],

  "carRentalBookings": [

    ...questions related to any activity bookings in the cart ...

  ],

  "routeBookings": [

    ...questions related to any transport bookings in the cart ...

  ],

  "activityBookings": [

    ...questions related to any activity bookings in the cart ...

  ]

}

Each of the product booking can have some generic questions attached, but also questions related to any extras being booked. Let’s have a look at the questions for each product type.

For activity bookings, we have basic info about the activity, and the departure being booked. Then we have pick up and drop off related questions (whether to ask where to pick/drop, the list of places to select from, and whether to allow custom pick up places). Then, under “questionGroups” there may be questions that are for the activity booking. Finally, if any extras are being booked that have some questions attached, these will be listed under “extraBookings”.

{

  ...

  "activityBookings": [

    {

      "activity": {

        "id": 207,

        "title": "Blue Ice",

        "flags": []

      },

      "bookingId": 342119,

      "date": 1435276800000,

      "time": "08:30",

      "askWhereToPickup": true,

      "customPickupAllowed": false,

      "pickupPlaces": [

        {

          "id": 485,

          "title": "101 Guesthouse - Laugavegur 101",

          "askForRoomNumber": false,

          "location": {

            "address": "Laugavegi 101",

            "city": "Reykjavík",

            "countryCode": "is",

            "postCode": "101",

            "latitude": 0,

            "longitude": -19.511719,

            "zoomLevel": 6

          },

          "flags": []

        },

        "askWhereToDropoff": false,

        "customDropoffAllowed": false,

        "dropoffPlaces": [],

        "questionGroups": [

          {

            "name": "participant-info",

            "answersNeeded": 2,

            "questions": [

              {

               "type": "name",

               "question": "Participant name",

               "selectFromOptions": false,

               "defaultAnswer": null,

               "answerRequired": true,

               "options": [],

               "id": null

              }

            ]

          }

        ],

      "extraBookings": [

        {

          "bookingId": 57602,

          "extra": {

            "id": 94,

            "title": "Ice Climbing Boots",

            "flags": []

          },

          "unitCount": 2,

          "questionGroups": [

            {

              "name": "extra-info",

              "answersNeeded": 2,

              "questions": [

                {

                  "type": "extra-question",

                  "question": "What is your shoe size in European or US?",

                  "selectFromOptions": true,

                  "defaultAnswer": null,

                  "answerRequired": true,

                  "options": [

                    "36 EUR / 4.5 US",

                    "37 EUR / 5 US",

                    "38 EUR / 6 US",

                    "39 EUR / 7 US",

                    "40 EUR / 7.5 US",

                    "41 EUR / 8 US",

                    "42 EUR / 8.5 US",

                    "43 EUR / 9 US",

                    "44 EUR / 10 US",

                    "45 EUR / 11 US",

                    "46 EUR / 12 US M"

                  ],

                  "id": 151,

                  "flags": []

                }

              ]

            }

          ]

        },

        ...

      }

  ]

  ...

}

The other product types follow a similar JSON pattern.

Reserve a Booking

This involves moving everything from the shopping cart to a booking in the RESERVED state. This means that the product availability is reserved for 30 minutes. If the booking has not moved to CONFIRMED state within that time, the booking will automatically be aborted (and the availability reservation removed).

POST

/booking.json/guest/{sessionId}/reserve

The POST body should contain the answers to the questions, along with optional information about discount and payments. It will look similar to the following, which reserves an activity booking:

{

    "answers": {

        "answers": [{

            "type": "first-name",

            "answer": "John"

        }, {

            "type": "last-name",

            "answer": "Doe"

        }, {

            "type": "email",

            "answer": "john.doe@email.com"

        }, {

            "type": "phone-number",

            "answer": "+354 1234567"

        }, {

            "type": "nationality"

            "answer": "UK"

        }, {

            "type": "address",

            "answer": "123 Some St."

        }, {

            "type": "post-code",

            "answer": "101"

        }, {

            "type": "place",

            "answer": "Reykjavik"

        }, {

            "type": "country",

            "answer": "IS"

        }, {

            "type": "organization",

            "answer": "My company"

        }, {

            "type": "email-list-subscription",

            "question": "Yes, I want to subscribe to the email list",

            "answer": "true"

        }],

        "accommodationsBookings": [],

        "carRentalBookings": [],

        "activityBookings": [{

            "bookingId": 443,

            "answerGroups": [{

                "name": "participant-info",

                "answers": [{

                    "type": "name",

                    "question": "Participant name",

                    "answer": "John"

                }]

            }, {

                "name": "other",

                "answers": [{

                    "type": "special-requests",

                    "question": "Special requests",

                    "answer": "None."

                }]

            }],

            "extraBookings": [{

                "bookingId": 194,

                "answerGroups": [{

                    "name": "extra-info",

                    "answers": [{

                        "type": "extra-question",

                        "question": "Which size do you use?",

                        "answer": "Large",

                        "questionId": 27

                    }]

                }]

            }],

            "pickupPlaceDescription": "Hotel Reykjavik",

            "pickupPlaceRoomNumber": "110"

        }]

    }

}

Here is another example, for a car rental booking:

{

    "answers": {

        "answers": [{

            "type": "first-name",

            "answer": "John"

        }, {

            "type": "last-name",

            "answer": "Doe"

        }, {

            "type": "email",

            "question": "Your email address",

            "answer": "john.doe@example.com"

        }],

        "carRentalBookings": [{

            "bookingId": 70,

            "answerGroups": [{

                "name": "other",

                "answers": [{

                    "type": "special-requests",

                    "question": "Special requests",

                    "answer": "None."

                }]

            }],

            "carBookings": [{

                "bookingId": 70,

                "answerGroups": [{

                    "name": "driver-info",

                    "answers": [{

                        "type": "name",

                        "question": "Driver name",

                        "answer": "John Doe"

                    }, {

                        "type": "age",

                        "question": "Driver age",

                        "answer": "35"

                    }]

                }],

                "extraBookings": []

            }]

        }]

    },

    "createPaymentsAutomatically": false

}

If you want to specify a discount, then supply the discount as percentage:

{

    "answers": {...},

    "discountPercentage": 10

}

Or amount:

{

    "answers": {...},

    "discountAmount": 1500

}

Also, if paying a deposit then this can also be specified:

{

    "answers": {...},

    "deposit": true,

    "depositPercentage": 10

}

It can also be specified as an amount rather than percentage:

{

    "answers": {...},

    "deposit": true,

    "depositAmount": 1500

}

Move a reserved Booking back to the Shopping Cart

Sometimes the customer will realise that she wants to change the booking when she’s asked to pay. In this case this service allows you to move the booking from the RESERVED state and back into the shopping cart.

GET

/booking.json/{bookingId}/move-back-to-cart/session/{sessionId}

Abort a reserved Booking

Sometimes the customer will want to cancel the booking when she’s asked to pay. In this case this service allows you to completely aborta a RESERVED booking.

GET

/booking.json/{bookingId}/abort-reserved

Confirm a reserved Booking

Moves a booking from the RESERVED state to CONFIRMED. This will trigger a confirmation email which will be sent immediately to the email address supplied by the customer.

POST

/booking.json/{bookingId}/confirm

The {bookingId} is the booking ID returned in the booking reserve call.

You can supply information about the payments in the POST body, for example the following specifies payment information for an activity booking:

{

    "payment": {

      "amount": 15000,

      "currency": "ISK",

      "paymentType": "WEB_PAYMENT",

      "confirmed": true,

      "paymentProviderType": "VALITOR",

      "cardBrand": "VISA",

      "cardNumber": "1234********5678",

      "authorizationCode": "12345",

      "paymentReferenceId": "00101010234",

      "paymentType": "WEB_PAYMENT",

      "comment": "This is a comment"

    },

    "bookingFields": [{

        "name": "pin",

        "value": "1234"

    }]

}

The bookingPaidType must be one of the following:

The bookingFields can be used to supply a list of name/value pairs that will be stored with the booking. These pairs can also be used in the confirmation email.

Confirming a booking will result in Bókun sending an ticket and invoice to the customer for the

booking. To disable this you can add the query parameter sendCustomerNotification=false.

Get a list of reserved bookings

Sometimes it can be useful to get any reserved (unconfirmed) bookings for a user. For example, if payment fails and you wish to retrieve the booking details. This service provides the ability to get all reserved bookings for a user. Note that normally any user should only have max one reserved booking.

GET

/booking.json/guest/{sessionId}/reserved

Pay for a booking using a credit card

If the owner of the booking channel has configured a payment gateway, then you can call this service to pay for the booking using a credit card. Remember to reserve the booking first. Usually, the flow would go like this: 1) Reserve, 2) Pay, 3) Confirm (although steps 2 and 3 can be combined).

You only need to supply the booking ID and card details - the amount is calculated dynamically from the booking. Bókun abstracts away all communication details with the underlying payment gateway - this means that you communicate with this service in the same way, independent of who the payment provider is.

POST

/booking.json/{bookingId}/charge-card

You provide the card details in the POST body as JSON:

{

  "card": {

    "cardNumber": "4242424242424242",

    "expMonth": "09",

    "expYear": "18",

    "cvc": "123"

  },

  "confirmBookingOnSuccess": true

}

Note the confirmBookingOnSuccess parameter: if you set this to true, then Bókun will automatically confirm the booking if payment was successful - however if this is false, then you will need to make a separate call to the booking confirm web service to confirm the booking.

And the response will be similar to this, if the card is accepted (the booking field will only be provided if confirmBookingOnSuccess was set to true):

{

  "charge": {

    "creationDate": "2014-01-19 16:16:42",

    "amount": 4250,

    "currency": "ISK",

    "card": {

      "cardNumber": "5587 **** **** 2037",

      "expMonth": "09",

      "expYear": "14",

      "cvc": "310"

    }

  },

  "booking": {

    ...

  }

}

If there are problems with the card or the payment, then you will get a 400 - Bad Request response. The response body JSON will contain more info about what went wrong.

If confirmBookingOnSuccess was set to true, this action will confirm the booking. Confirming a booking will result in Bókun sending an ticket and invoice to the customer for the

booking. To disable this you can add the query parameter sendCustomerNotification=false.

Reserve, Pay & Confirm Booking

If the owner of the booking channel has configured a payment gateway, then you can call this service to reserve, pay and confirm booking in a single service call.

NOTE: if anything fails during this process, then the booking will be moved back to the shopping cart.

POST

/booking.json/guest/{sessionId}/reserve-pay-confirm

This will take the session shopping cart specified, reserve the availability, pay using the card details supplied, and finally confirm the booking on successful payment. The info in the POST body as JSON is practically the same as for the booking reserve call, with the addition of a chargeRequest:

{

  "answers": {

    ...

  },

  "chargeRequest": {

    "card": {

      "cardNumber": "4242424242424242",

      "expMonth": "09",

      "expYear": "18",

      "cvc": "123",

      "name": "John Doe",

    }

  }

}

If everything goes according to plan, the system will return a response with the charge info and the booking details:

{

  "charge": {

    ...

  },

  "booking": {

    ...

  }

}

Confirming a booking will result in Bókun sending an ticket and invoice to the customer for the booking. To disable this you can add the query parameter sendCustomerNotification=false.

Activity - Reserve and confirm single activity booking

A special case is when you want to directly book a single activity, without having to first add to shopping cart, then call reserve, and finally confirm. Instead, this call allows you to reserve and confirm in a single call.

POST

/booking.json/activity-booking/reserve-and-confirm

The POST body should contain the following format:

{

    "activityRequest": {

        "activityId": 1,

        "startTimeId": 1,

        "date": "2016-02-20",

        "flexibleDayOption": null,

        "pickup": false,

        "pickupPlaceId": null,

        "pickupPlaceDescription": null,

        "pickupPlaceRoomNumber": null,

        "dropoff": false,

        "dropoffPlaceId": null,

        "dropoffPlaceDescription": null,

        "pricingCategoryBookings": [{

            "pricingCategoryId": 1,

            "extras": []

        }, {

            "pricingCategoryId": 1,

            "extras": []

        }, {

            "pricingCategoryId": 2,

            "extras": []

        }, {

            "pricingCategoryId": 3,

            "extras": []

        }],

        "extras": []

    },

    "externalBookingReference": "AB-123",

    "note": "Hello world!",

    "sendCustomerNotification": false,

    "discountPercentage": null,

    "paymentOption": "NOT_PAID",

    "manualPayment": null,

    "chargeRequest": null,

    "vesselId": null,

    "harbourId": null,

    "customer": {

        "id": null,

        "created": null,

        "email": null,

        "firstName": "John",

        "lastName": "Doe",

        "language": null,

        "nationality": null,

        "sex": null,

        "dateOfBirth": null,

        "phoneNumber": null,

        "phoneNumberCountryCode": null,

        "address": null,

        "postCode": null,

        "state": null,

        "place": null,

        "country": null,

        "organization": null,

        "passportId": null,

        "passportExpMonth": null,

        "passportExpYear": null

    }

}

If all goes well, you will get the booking details in the response.

The example above assumes a “not paid” booking. If it is already paid, then you can supply information about the payment manually, like this (highlighted in bold below):

{

    "activityRequest": {...},

    "externalBookingReference": "AB-123",

    "note": "Hello world!",

    "sendCustomerNotification": false,

    "paymentOption": "ENTER_MANUALLY",

    "manualPayment": {

      "amount": 15000,

      "currency": "ISK",

      "paymentType": "WEB_PAYMENT",

      "confirmed": true,

      "paymentProviderType": "VALITOR",

      "cardBrand": "VISA",

      "cardNumber": "1234********5678",

      "authorizationCode": "12345",

      "paymentReferenceId": "00101010234",

      "paymentType": "WEB_PAYMENT",

      "comment": "This is a comment"

    },

    "customer": {...}

}

Accommodation - Reserve and confirm single activity booking

A special case is when you want to directly book a single accommodation, without having to first add to shopping cart, then call reserve, and finally confirm. Instead, this call allows you to reserve and confirm in a single call.

POST

/booking.json/accommodation-booking/reserve-and-confirm

The POST body should contain the following format:

{

    "accommodationRequest": {

        "accommodationId": 1,

        "checkinDate": "2016-02-20",

        "checkoutDate": "2016-02-27",

        "travelType": "LEISURE",

        "rooms": [{

            "roomTypeId": 1,

            "roomRateId": 11,

            "guests": [],

            "extras": [],

            "adults": 2,

            "children": 0,

            "infants": 0

        }]

    },

    "roomBookingStatus": "RESERVED",

    "externalBookingReference": "AB-123",

    "note": "Hello world!",

    "sendCustomerNotification": false,

    "discountPercentage": null,

    "paymentOption": "NOT_PAID",

    "manualPayment": null,

    "chargeRequest": null,

    "tokenChargeRequest": null,

    "vesselId": null,

    "harbourId": null,

    "customer": {

        "contactDetailsHidden": false,

        "contactDetailsHiddenUntil": null,

        "id": null,

        "created": null,

        "uuid": null,

        "email": null,

        "firstName": "John",

        "lastName": "Doe",

        "language": null,

        "nationality": null,

        "sex": null,

        "dateOfBirth": null,

        "phoneNumber": null,

        "phoneNumberCountryCode": null,

        "address": null,

        "postCode": null,

        "state": null,

        "place": null,

        "country": null,

        "organization": null,

        "passportId": null,

        "passportExpMonth": null,

        "passportExpYear": null

    }

}

If all goes well, you will get the booking details in the response.

Transport - Reserve and confirm single route booking

A special case is when you want to directly book a single route, without having to first add to shopping cart, then call reserve, and finally confirm. Instead, this call allows you to reserve and confirm in a single call.

POST

/booking.json/route-booking/reserve-and-confirm

The POST body should contain the following format:

{

    "routeRequest": {

        "departureDate": "2016-02-20",

        "returnDate": null,

        "pathSegments": [{

            "routeId": 1,

            "returning": false,

            "departureSchedules": [{

                "routeLegId": 1,

                "scheduleId": 1,

                "pickupPlaceId": null,

                "dropoffPlaceId": null

            }],

            "returnSchedules": [],

            "passengerSpecification": {

                "fareClassId": null,

                "passengerSpecifications": [{

                    "categoryId": 4,

                    "passengers": 2

                }]

            }

        }]

    }

    "externalBookingReference": "AB-123",

    "note": "Hello world!",

    "sendCustomerNotification": false,

    "discountPercentage": null,

    "paymentOption": "NOT_PAID",

    "manualPayment": null,

    "chargeRequest": null,

    "tokenChargeRequest": null,

    "vesselId": null,

    "harbourId": null,

    "customer": {

        "contactDetailsHidden": false,

        "contactDetailsHiddenUntil": null,

        "id": null,

        "created": null,

        "uuid": null,

        "email": null,

        "firstName": "John",

        "lastName": "Doe",

        "language": null,

        "nationality": null,

        "sex": null,

        "dateOfBirth": null,

        "phoneNumber": null,

        "phoneNumberCountryCode": null,

        "address": null,

        "postCode": null,

        "state": null,

        "place": null,

        "country": null,

        "organization": null,

        "passportId": null,

        "passportExpMonth": null,

        "passportExpYear": null

    }

}

If all goes well, you will get the booking details in the response.

Operations services

Bókun offers a set of web services for operations teams that need to be able to manage bookings. Please note that to access these services, your API key must have the “operations” setting enabled.

Product Booking Search

Search product bookings by confirmation code, dates, customer name, and more options.

POST

/booking.json/product-booking-search

The POST body should contain the booking query:

{

  "confirmationCode": "ABC2234-456",

  "textFilter": "Smith",

  "creationDateRange": {

    "from": "2014-03-01",

    "to": "2014-03-10"

  },

  "startDateRange": {

    "from": "2014-05-01",

    "to": "2014-05-19"

  },

  "productIds": [123,345],

  "page": 1,

  "pageSize": 100

}

None of the fields in the query are required. The creationDateRange refers to the date when the booking was created, while startDateRange refers to the date of service.

Accommodation Booking Details

Get the full details of an accommodation booking. Use the value of productConfirmationCode field returned by the product booking search.

GET

/booking.json/accommodation-booking/{productConfirmationCode}

Activity Booking Details

Get the full details of an activity booking. Use the value of productConfirmationCode field returned by the product booking search.

GET

/booking.json/activity-booking/{productConfirmationCode}

Route Booking Details

Get the full details of a route booking. Use the value of productConfirmationCode field returned by the product booking search.

GET

/booking.json/route-booking/{productConfirmationCode}

Car Rental Booking Details

Get the full details of an car rental booking. Use the value of productConfirmationCode field returned by the product booking search.

GET

/booking.json/car-rental-booking/{productConfirmationCode}

Cancel booking

Cancel a whole booking. All product bookings in this booking will be cancelled.

POST

/booking.json/cancel-booking/{bookingConfirmationCode}

The POST body should contain the following info:

{

  "note": "We had to cancel this due to weather.",

  "refund": true,

  "notify": true

}

The note field can be used to specify a comment as to why this booking was cancelled.

If refund is set to true, then the amount paid for the booking will be refunded.

If notify is set to true, then the customer and all involved suppliers will be notified of the cancellation via email.

Edit booking

POST

/booking.json/edit

The post body should contain a list of the actions to be applied to the bookings. Each action references a booking, so you can in fact edit multiple bookings in a single call.

[

  // modify pick up for activity booking

  {

    "type": "ActivityPickupAction",

    "activityBookingId": 123,

    "pickup": true,

    "pickupPlaceId": 234,

    "description": "description here",

    "roomNumber": "101"

  },

 

  // modify drop off for activity booking

  {

    "type": "ActivityDropOffAction",

    "activityBookingId": 123,

    "dropOff": true,

    "dropOffPlaceId": 234,

    "description": "description of the place"

  },

 

  // add extra booking to an activity pricing category booking

  {

    "type": "AddActivityExtraBookingAction",

    "activityBookingId": 123,

    "pricingCategoryBookingId": 345,

    "extraId": 456,

    "unitCount": 1

  },

 

  // remove extra booking from an activity pricing category booking

  {

    "type": "RemoveActivityExtraBookingAction",

    "activityBookingId": 123,

    "pricingCategoryBookingId": 345,

    "extraBookingId": 567

  },

 

  // edit extra booking on an activity pricing category booking

  {

    "type": "EditActivityExtraBookingAction",

    "activityBookingId": 123,

    "pricingCategoryBookingId": 345,

    "extraBookingId": 456,

    "unitCount": 1

  },

 

  // add participant to an activity booking

  {

    "type": "AddParticipantAction",

  "activityBookingId": 123,

  "pricingCategoryBooking": {

      "pricingCategoryId": 111,

      "extras": [

        {

          "extraId": 222,

          "unitCount": 1,

          "answers": []

        }

      ]

    }

  },

 

  // remove participant from an activity booking

  {

    "type": "RemoveParticipantAction",

    "activityBookingId": 123,

    "pricingCategoryBookingId": 345

  },

 

  // edit a participant (pricing category booking)

  {

    "type": "EditParticipantAction",

    "activityBookingId": 123,

    "pricingCategoryBookingId": 345,

    "pricingCategoryBooking": {

      ...

    }

  },

 

  // modify the date for an activity booking

  {

    "type": "ActivityChangeDateAction",

    "activityBookingId": 123,

    "date": "2016-05-15",

    "startTimeId": 999,

    "flexOption": "Afternoon departure"

  },

  // Edit answer

  {

    "type": "EditAnswerAction",

    "answerId": 123,

    "answer": "Vegetarian"

  },

 

  // Remove answer

  {

    "type": "RemoveAnswerAction",

    "answerId": 123

  }

]

Cancel product booking

Cancel an individual product booking.

POST

/booking.json/cancel-product-booking/{productConfirmationCode}

The POST body should contain the following info:

{

  "note": "We had to cancel this due to weather.",

  "refund": true,

  "refundAmount": 12.50,

  "remainInvoiced": true,

  "notify": true

}

The note and notify fields are used in the same way as when cancelling a booking.

The refundAmount can be specified if refund is set to true, and specified the amount to be refunded. If refund is true and refundAmount is not specified (or set to zero), then the total amount for this product booking will be refunded.

You can set remainInvoiced to true if you want this product booking to remain on the customer invoice. If this is false or not specified, the customer invoice will be regenerated without the cancelled product booking.

Accommodation Booking - Change customer status

Change the “arrived” status for an accommodation booking. Use the value of productConfirmationCode field returned by the product booking search. Valid values for the {status} are:

GET

/booking.json/accommodation-booking/{productConfirmationCode}/customer-status/{status}

Activity Booking - Change customer status

Change the “arrived” status for an activity booking. Use the value of productConfirmationCode field returned by the product booking search. Valid values for the {status} are:

GET

/booking.json/activity-booking/{productConfirmationCode}/customer-status/{status}

Route Booking - Change customer status

Change the “arrived” status for a route booking. Use the value of productConfirmationCode field returned by the product booking search. Valid values for the {status} are:

GET

/booking.json/route-booking/{productConfirmationCode}/customer-status/{status}

Car Rental Booking - Change customer status

Change the “arrived” status for a car rental booking. Use the value of productConfirmationCode field returned by the product booking search. Valid values for the {status} are:

GET

/booking.json/car-rental-booking/{productConfirmationCode}/customer-status/{status}

Update customer details

Change the main customer details (such as name and contact info) for a selected booking.

POST

/booking.json/update-customer/{bookingConfirmationCode}

In the body of the POST request, supply a JSON representation of the customer details, for example:

{

    "email": "John.Doe@example.com",

    "firstName": "John",

    "lastName": "Doe",

    "nationality": null,

    "sex": null,

    "dateOfBirth": null,

    "phoneNumber": null,

    "phoneNumberCountryCode": null,

    "address": null,

    "postCode": null,

    "state": null,

    "place": null,

    "country": null,

    "organization": null,

    "passportId": null,

    "passportExpMonth": null,

    "passportExpYear": null

}

All the fields are optional, so just specify the ones you actually want to update.

Get Ticket and Order Summary

Get the PDF ticket and PDF order summary for bookings.

GET

/booking.json/{bookingId}/summary

GET

/booking.json/accommodation-booking/{productBookingId}/ticket

GET

/booking.json/activity-booking/{productBookingId}/ticket

GET

/booking.json/car-rental-booking/{productBookingId}/ticket

GET

/booking.json/route-booking/{productBookingId}/ticket

Tags

This service gets all the tag groups and their tags in the language specified.

GET

/tag.json/groups

The service allows filtering by flags specified as a query string parameter:

Currencies

This service returns all the currencies that Bókun can display prices in.

GET

/currency.json/findAll

Languages

This service returns all the languages that the content is available in. These are the languages you can send as parameters to the tag and product services.

GET

/language.json/findAll

Countries

This utility service returns a list of all countries (title and ISO code). The ISO code should be used when specifying the nationality and country of residence for customers.

GET

/country.json/findAll

Appendix

Geo filtering

Bókun product search supports a range of geo filters which are described below. Note that Geo Distance Filter and Geo Distance Range Filter are mutually exclusive, that is, if Geo Distance Filter is applied, then Geo Distance Range Filter will be ignored. Similarly, Geo Bounding Box Filter and Geo Polygon Filter are mutually exclusive: if GeoBounding Box Filter is applied, then Geo Polygon Filter will be ignored.

Geo Distance Filter

The Geo Distance Filter filters results to only include hits that exists within a specific distance from a center point.

{

    "geoDistanceFilter": {

      "center": {

        "lat": 64.135338,

        "lng": -21.895210

      },

      "distance": "100km"

    }

}

Geo Distance Range Filter

The Geo Distance Range Filter filters results to only include hits that exists within a specific range from a center point.

{

    "geoDistanceRangeFilter": {

      "center": {

        "lat": 64.135338,

        "lng": -21.895210

      },

      "fromDistance": "10km",

      "toDistance": "20km",

      "includeLower": true,

      "includeUpper": true

    }

}

Geo Bounding Box Filter

The Geo Bounding Box Filter filters results to only include hits that exists within a specific box on a map.

{

    "geoBoundingBoxFilter": {

      "topLeft": {

        "lat": 64.135338,

        "lng": -21.895210

      },

      "bottomRight": {

        "lat": 64.107778,

        "lng": -21.832222

      }

    }

}

Geo Polygon Filter

The Geo Polygon Filter filters results to only include hits that fall within a polygon of points on a map.

{

    "geoPolygonFilter": {

      "points": [

          { "lat": 64.135338, "lng": -21.895210 },

          { "lat": 64.107778, "lng": -21.832222 },

          { "lat": 64.147222, "lng": -21.783333 }

      ]

    }

}

Tag filtering and Search facets

Products in Bókun can be “tagged” with Tags that describe the product. These tags are grouped into “Tag Groups”, and a product can be tagged with multiple tags from each group.

These tags can be used for advanced search filtering, as Bókun generates “search facets” for the tag groups. Each facet describes how many of the search result items matches each tag. The search facets adapt to the items in the search results, showing only the tags that apply to the results. Therefore, these tag based search facets can be used to create powerful search navigation filters that adapt to the results - never allowing the customer to filter by a tag that returns zero results.

The tag facets can be found under “tagFacets” in the search results:

...

  "tagFacets": [

    {

      "name": "activityType",

      "title": "Activity type",

      "entries": [

        {

          "title": "Sightseeing",

          "term": "98",

          "count": 3,

          "flags": []

        },

        {

          "title": "Bird watching",

          "term": "97",

          "count": 1,

          "flags": []

        },

        ...

    },

    ...

  ]

...

Filtering by Tags using Facet Filters

To apply a tag facet filter, use the “name” of the facet, and the “term” value of the facet entry you want to filter by. For example, if we want to only show results tagged with “Bird watching”, we would do:

{

    ...

    "facetFilters": [{

      "name": "activityType",

      "values": ["97"]

    }]

    ...

}

Excluding Tags using Facet Filters

You could also exclude any results tagged with “Bird watching” by adding the “excluded” attribute:

{

    ...

    "facetFilters": [{

      "name": "activityType",

      "values": ["97"],

      "excluded": true

    }]

    ...

}

Affiliate tracking

Bokun supports affiliate tracking for bookings. This is done by sending in the affiliate’s tracking code when adding products to the shopping cart. The tracking code is a unique ID created for an affiliate and can be found in the extranet.

There can be a single affiliate tracked per shopping cart. This means that if you add multiple products to the cart with multiple tracking codes, the last one added will only be stored.

The affiliate code has the same lifespan as the shopping cart. This means that if a customer adds to the cart with a tracking code today, and then comes back to the same cart in a week and finishes the booking, then the affiliate code will still be active on the cart - and the booking will be attributed to the appropriate affiliate.

Affiliate sales reports can be generated in the extranet.

The shopping cart calls accept a trackingCode parameter in the query string. This is used for affiliate tracking (see appendix). Example:

/shopping-cart.json/session/12345/activity?trackingCode=204998ac7a9d471d8c88e789fcbfe75d&lang=EN&currency=ISK