Overview

As nothing showcases the functionality and structure of an API better than some concrete examples, here is a sequence of requests and responses, that constitute a common booking flow.

Please note that this example by far does not cover the complete scope of the Livn API, but is merely meant to represent one possible path from searching for products to completing a confirmed reservation.

While all resources optionally support XML formatted request and response data, we will be using the preferred and easier to read JSON format. For this reason please assume that all of the below requests, unless explicitly indicated otherwise, will include the headers Accept:application/json and Content-Type:application/json

Authentication and authorisation

All API resources, bar a few basic and public calls such as retrieving the server time / ping, need to be authenticated and authorised. This can be done in two ways:

  1. HTTP Basic Authentication: use your API credentials (login name and password) to generate and include a request header Authorization: Basic N0tR3ally4W0rk1n6K3y

  2. JWT (JSON Web Token): POST your credentials to the API resource /public/login, which itself does not require authentication and use the returned token, which has a limited validity of 24h, for all subsequent secured API requests, by adding a different header of the form Authorization: Bearer <token>

Product Search

The entire inventory can be retrieved and browsed directly via the /operators, /operators/{operatorId}/products and /products/{productId} calls. Depending on your application's needs, and in combination with keeping all properties of the inventory data required for your listing cached on your end, this may be the better entry point.

For this example we are going to take another approach, instead searching for relevant products by location, and optionally an operating date range. Let's assume the use case is a family of two adults and a child travelling to Australia. While the family will be spending several weeks in the country, their flight itinerary has them staying in Sydney for a limited and specific time, during which they are hoping to participate in some local tours and activities. The easiest way to find products that might appeal to these customers is via the product search resource, using either the IATA airport code SYD for Sydney's international airport, or a suitable set of geographic coordinates (latitude and longitude) and a specified search radius, tom retrieve a list of products operating in the area of interest.

GET https://***.livngds.com/livngds/api/products/search?airport=SYD,100&startDate=2018-12-10&endDate=2018-12-16&treeView=true

The response will be a list of all products departing from a location within a 100 kilometre radius around Sydney Kingsford Smith airport, that have open departures in the dates 10-16 December 2018. The query parameter treeView=true is used to request that multiple related bookable products, should be grouped under a common, but not directly bookable parent record. Much in the same way we could have searched products in a much smaller area, e.g. in walking distance from the hotel the customers have booked.

GET https://***.livngds.com/livngds/api/products/search?location=-33.862744,151.209255,1&startDate=2018-12-10&endDate=2018-12-16&treeView=true

This is the response, which has been truncated to only a single top level tour with several bookable variants or flavours as they are called in the Livn API (several image links have also been removed for the sake of brevity).

The above data shows a single tour product, which comes in two specific variants, representing two different times at which the tour departs, 12PM and 2PM (this operator actually uses 1 hour time slots with groups departing every few minutes in the listed hour, e.g. a group might book the 12:00PM-1PM departure window, and be assigned a departure at 12:20PM at the time of checkout, as we will see later). You would notice that the product's pricing is given as a min/max range, as rates can naturally vary over time, depending on season or other factors. Likewise at this point there is no information about availability.

Check Availability and Rates

The suppliers' various reservation systems, that lie upstream (or downstream, depending on how you want to look at it) from the Livn API, offer a surprisingly wide spectrum of functionality and flexibility when it comes to checking live availability and princing:

Some systems might allow retrieving availability and rates concurrently, whereas other require this data to be fetched in separate API calls.

The number of products that can be checked with a single API request can range from a full top level tour including all it's variations (time slots, fare types... in short the unique bookable products, that can have differing avilability and pricing on the same date) down to just a single one of these concrete bookable products. Likewise it might be possible to request the availability and/or rates for said products for an extended date range in a single request, where in other systems it may be only be possible to query this information for a single date. And finally it may not be possible to get a concrete numeric availability for a product and date, but the only functionality available on the supplier side might be to request a specific number of units of the product, and get a Yes/No, Available/Not Available type response.

Just about all our clients require and have requested functionality from us, that surpasses this in many cases far too restricted access to the suppliers' live data. Clients wish to present the day by day rates and numeric availability for a single or multiple product for an extended date range, e.g. in a calendar displaying this information for three full months at a time, with the option to scroll further into the future. Or our clients may wish to search for products, be it based on location or keywords, but are only interested in such tours and activities, that have sufficient bookable availability for a specific date range, so essentially the type of search seen above.

To make this possible Livn implemented a powerful 366 day cache, which is built on an in-memory database and uses complex rules and logic to evaluate each product-date record’s status on an ongoing basis, thus minimising the occurrence of false-positives (cache reporting sufficient availability when in fact there isn’t) and outdated pricing information, whilst keeping the amount of traffic and load on the supplier reservation systems at acceptable levels.

Going back to our previous example, let's assume the customers are keen to climb the Sydney Harbour Bridge on 14 or 15 December, but have no specific preference on the time. The next step would be to retrieve the availability and rates for this product. Checking availability and rates for this actually rather simple case, only two calendar days and two different products (12PM and 2PM are different in the sense that their availability and potentially even rates can differ), live against the operator’s reservation system could require as many as 8, and in fact even more, separate upstream API requests (2 products, 2 dates, rates and availability handled separately, and possibly you might need a separate call first, to establish some form of identifier for the date and product specific departure or product run)

Retrieving this information from Livn’s cache can be done in one simple request, using the so called getDeparturesMulti call with the top level tour’s id (3355) and specifying the date range we are interested in.

GET https://dev1.livngds.com/livngds/api/products/3355/departures-multi?includeRates=true&startDate=2018-12-14&endDate=2018-12-15

As this request is served using data from our fully in-memory cache, we have not put a limit on the date range that can be queried, apart from not accepting dates in the past (using the current lowest local date anywhere on the planet) and more than 366 days in the future. Here’s the response.

Same as in the product search results earlier, we can see that children under the age of 8 are not permitted on this tour, but participants aged 8-15 are eligible for child rates. All four departures have ample availability ("availableUnits": 12) and accept bookings ("status": "OPEN"), while the prices for the 15th are indeed $20 or $15 higher for adults and children respectively, than the day before (15 December 2018 is a Saturday, which might explain the difference).

It goes without saying, that even though we will do our utmost to serve up to date data from our cache, you may wish to check availability and possible rates live against the operator’s reservation system. This too is of course possible via the Livn API, but for the reasons outlined above, is subject to some limitations:

This would be a possible request for our current example. Note that we can only check for a single product, in this case the 12PM climb.
GET https://dev1.livngds.com/livngds/api/products/3364/checkAv?startDate=2018-12-14&endDate=2018-12-15&requiredUnits=3

With the response.

{ "availabilityCheck": { "created": "2018-05-25T11:41:08.521+10:00", "startDate": "2018-12-14", "endDate": "2018-12-15", "productId": 3364, "productCid": 50875, "requiredUnits": 3, "availabilities": [{ "date": "2018-12-14", "available": true, "availableUnits": 3, "checkFailed": false, "requestOnly": false, "created": "2018-05-25T11:41:10.643+10:00" }, { "date": "2018-12-15", "available": true, "availableUnits": 3, "checkFailed": false, "requestOnly": false, "created": "2018-05-25T11:41:12.260+10:00" }] } }

You will see that the live check confirms that the requested number of units is available for both dates ("available": true), but that the number of available units does not match that of the previous cached departures request, the reason being that this reservation system is exactly one that does not respond with a concrete number reflecting the true availability. While for the purpose of populating and updating our cache, a resource shared by many users, we will do some trickery to work out such an actual, if possibly capped, remaining unit count, doing the same for a single live availability check would not be viable.

Likewise we can check the rates again, this time live from the supplier.

GET https://dev1.livngds.com/livngds/api/products/3364/checkRates?startDate=2018-12-14&endDate=2018-12-15&paxAges=45,43,12

The response.

As expected the amounts match those returned by the getDeparturesMulti call.

Clearly these essentially proxied, live availability and rates calls are not intended, nor suitable for the purpose of clients building up their own cache of this information. In fact we firmly believe that the existence of the Livn’s in-memory cache and it’s integration into the API’s product search, should mean that you do not have to worry about caching availability and day by day rates.

Finally, while these calls are available to all clients at any time as seen above, it should be pointed out that both live checks are always automatically being carried out by the Livn API, when a new shopping cart object is received, so rates quoted during checkout will always be coming live from the supplier. On that note it may be time to make a booking.

POST and check out a cart

Our test family have decided to go on the 12PM climb on the slightly cheaper weekday, so we will make a booking for product id 3364 for 2018-12-14. Based on the product listing, we know that from the operator’s side we only need to supply a single name (which actually encompasses the first name, last name and salutation), email address and phone number for this booking. Note that a mobile number will also be accepted, as the phone and mobile fields are only separated in case both are supplied.

"paxDetails": { "dob": "NOT_REQ", "address": "NOT_REQ", "country": "NOT_REQ", "name": "ONCE", "language": "NOT_REQ", "email": "ONCE", "phone": "ONCE", "mobile": "NOT_REQ", "nationality": "NOT_REQ", "passport": "NOT_REQ" }

The fields of data marked as NOT_REQ are not required from any pax, whereas ONCE specifies details that are required once per booking, i.e. from the lead participant. A third value for these flags not seen here is ALL, marking details which have to be provided for every participant in the group booking.

Livn takes the responsibility for the protection of its customers’ private information very seriously, and we encourage you to observe these pax data requirements.

In order to initiate a booking and, as mentioned earlier, kick off another round of live availability and rates checks, we need to POST an object of the model type cart to the API resources

POST https://dev1.livngds.com/livngds/api/carts

This is a very basic cart, containing only a single product, requiring limited pax details and not using any pickups. It may be interesting for your application, that the Livn API enables you to book multiple products, from multiple suppliers in a single cart, which will be handled as a single atomic transaction, i.e. all required upstream bookings will succeed or fail together. This allows our clients to build complete itineraries without the possibility of individual segments tripping up the entire checkout.

Two fields in this request worth pointing out are the consultantName, which you can use to identify any travel agent or consultant making the booking on the customer’s behalf, as well as retailRef, which can be used to transmit a reference number for this shipping cart in the client application, and which is conveyed to the operator’s reservation system, or systems, along with a unique reference number generated by Livn. Both fields can help agents and operators alike should the need arise at a later stage for them to communicate directly and refer to the sale.

Having completed the live availability and rates checks without any issues (any problems, such as missing required details, invalid ids, or insufficient availability would be part of the returned cart object), this is the response:

The response contains the correct rates, retail commission amounts (as set for the requesting API user), terms of cancellation and other product and operator related details. As the status field says, the cart is at this stage ready to be “pushed through the checkout”, making confirmed reservations on the quoted terms, which are guaranteed for this cart for 15 minutes before it expires (an expired cart can no longer be checked out, and the client would need to make another call to postCart).

This call and other similar API calls that involve communication with our supplier’s reservation systems will by default respond synchronously, that is the response from Livn API will be sent only once all upstream requests have completed. Should you prefer to make these potentially longer running calls asynchronously, i.e. receive a near immediate response from the Livn API and then rely on polling the cart and checking for status changes, you can do so by including the optional request header Synchronous: true. As all other resources used throughout this example, you will find more details on this topic in the comprehensive API documentation.

Finding the terms of the sale agreeable, we will now proceed to the checkout by calling

GET https://dev1.livngds.com/livngds/api/carts/6951/checkout

… which also completes synchronously with this response.

So where is the booking? At this stage we have made a confirmed reservation on the quoted conditions, but based on the commercial agreements between the API user’s organisation and the wholesaling distributor, which may be our wholesale brand Livn Holidays, another wholesaler and even the same company as the Api client, there may still be the small issue of payment. The retailer (API user) may need to have a line of credit with the wholesaler as an agent, but may be set up in a way that requires authorisation of invoicing and claiming payment of the net retail total amount (i.e. the retail total minus the retail commission). Or, as in this example, the API user has been configured to require credit card payment of that same net retail amount, before the sale is ultimately confirmed, and the booking details will be released to the API user.

In either case, be it "status": "PENDING_CREDIT_CARD_PAYMENT" or "status": "PENDING_AUTHORISATION", the cart will remain in this state, waiting for the appropriate action for 40 minutes. This would for instance give a consultant in a brick and mortar travel agency ample time to collect the appropriate payment from the end customers, possibly involving split payments and swiping multiple credit cards, before finally authorising payment of, or paying the full net amount with the travel agency store’s company credit card. Failure to pay, or authorise payment in this 40 minute window, will result in the cart being timed out automatically, with all related reservations being rolled back, i.e. cancelled with the operator without incurring any cost to the business or customer.

The amount that needs to be paid can be found in the cart as the value retailTotals.netAmount, so in this case a credit card payment of $440.68 AUD is required to reconfirm the booking and finalise the sale. To do so we call:

POST https://dev1.livngds.com/livngds/api/carts/6951/ccPayment
{ "creditCardPayment": { "currency": "AUD", "amount": 440.68, "expMonth": 5, "expYear": 2020, "number": "4242424242424242", "cvc": "123" } }

Naturally this example, made on the development environment does not use real credit card details, but a number accepted by our payment processor Stripe for exactly such test purposes. It should be needless to say that Livn is compliant with PCI Data Security Standards required for this mode of payment processing, no complete credit card details are ever stored persistently by Livn, be it in any database, log files or otherwise.

Getting back to the request above, this is the subsequent response, now containing the full details of the reservations made based on the cart’s contents (in this example a single reservation).

As the status field indicates, the sale it at this point fully completed, the rollback timeout has been aborted and all information necessary to generate tickets for the customers can be found under cart.reservations. Note that the reference number of the booking, used in the operator’s reservation system, is listed in the field reservation.idExternal (the unusual value -99999 is cause by this booking only having simulated the final checkout step), alongside the reservation.id 4346 given to the same booking in this Livn endpoint, as well as the so called global reference number ("globalRef": "101-3258"), which is generated to be unique across all Livn API endpoints and for every reservation, cancellation or part thereof, and transmitted to the reservation system and operator with the booking request. It is encouraged that you please record both the reservation.id and globalRef values.

Should you prefer not to generate your own tickets, you can use the API to download PDFs for the individual reservations and reservation items, i.e. one voucher per pax and product, as well as a combined document for the entire upstream reservations or an entire cart:

GET https://dev1.livngds.com/livngds/api/tickets/7197 GET https://dev1.livngds.com/livngds/api/reservations/4346/tickets GET https://dev1.livngds.com/livngds/api/carts/6951/tickets

Finally, every confirmed reservation will include a link to the resource that can be used to cancel the booking, should the customer wish to do so.

"cancellationQuote": "https://dev1.livngds.com/livngds/api/reservations/4346/cancellationQuote"

Cancellation

Depending on the cancellation policy included in the product listings, quoted when you POST a cart and of course included in the reservation record itself, it may be possible to cancel confirmed reservations at a later time, which may or may not incur a cancellation fee, set out as a percentage of the original product value and the lead time before departure in hours, at which it comes into play. Operators or wholesalers may not offer cancellations at all, which would be signalised by a cancellation fee of 100% starting at a lead time of 8760 hours, or 365 days, which is the longest amount of time bookings can be made in advance.

The first step to make a cancellation, is to request a cancellation quote for the reservation, which essentially calculates the cost of cancellation at the currency time, based on the product departure location, local date and time of departure and the cancellation policy, and returns the resulting quote together with a generated quote number, that can subsequently be used to request the actual cancellation on the quoted terms.

Assuming the family from our example so far have decided not to go on the tour we booked, because they have changed their travel plans. We will first request a cancellation quote.

GET https://dev1.livngds.com/livngds/api/reservations/4346/cancellationQuote

We can see that even though we have booked quite a long time in advance, this cancellation is quoted to incur a 25% cancellation fee, or a retail total amount of $119.75 AUD. This is in line with the cancellation policy, which clearly stated that cancellations over 336 hours (14 days) but within 8760 (365 days) of travel carry a 25% cancellation fee. Assuming the customers agree to the quoted cancellation fee, the next step is to POST back the cancellation quote to another API resource. In a regular setup the quoteId is actually the only field required from the above quote, but we would kindly ask you to specify the reason for the cancellation in the respective field, which is transmitted to the operator.

POST https://dev1.livngds.com/livngds/api/cancellations
{ "cancellation": { "quoteId": "6a0ae03c-4e9a-403a-b65e-2741e36d1454", "cancellationReason": "Customers had to change their travel plans" } }

This will trigger the necessary calls to the operator’s reservation system, to cancel the reservation on the quoted terms. The response of this call will appear very similar to the cancellation quote, and even the reservation before it.

Having been cancelled successfully, the original reservation is obviously no longer valid and any tickets issued to the customer would no longer be accepted and honoured by the supplier. The customer should be refunded the difference of the original booking value minus the cancellation fee and any amount the retailer may wish to charge for processing the cancellation. Likewise the wholesaler would in this example issue a partial refund of the amount paid at the time of checkout to the credit card that was used.