# Overview

An overview of the Travel Personalization Platform.

## Platform Overview

Guestlogix provides a platform for airlines to optimize ancillary revenues and increase traveler loyalty throughout the entire journey. The Travel Personalization Platform leverages machine learning and AI to provide travellers with highly personalized offers from within an airline’s existing mobile app. The company’s approach to the travel experience transforms how airlines provide value to their passengers and empowers them to become better retailers. While Guestlogix’s roots were in onboard retail and payments, the new platform streamlines the management of offers for ancillary revenue teams and enables them to provide travellers with the products and services they are looking for at every phase of their journey, from planning through to the end of their trip.

The platform is offered via API, iOS and Android SDKs  A web based Management Console supports all 3 giving configuration, support, reporting, and analytic insights to your business.

## Stakeholders

The documentation is grouped by the stakeholders for which Guestlogix has developed tooling. All stakeholders are serviced from a common backend, however the resources and actions vary between them. This tooling is predominately comprised of RESTful APIs and Mobile SDKs. The stakeholders outlined are:

1. Partner - See [Overview](/partner/overview)
2. Traveler - See [Overview](/traveler/guest-app-overview)

## RESTful APIs

Should tooling for an end user need to be built outside of the scope of the native mobile SDKs, requests directly to the RESTful API may be made. They will require the same API Key that is used to initialize the SDKs. Not surprisingly, the SDKs ultimately wrap these APIs.

There are two distinct APIs

* [Traveler API](/traveler/api) - This represents all resources and actions that an end user of the SDK would need. Functionality such as browsing a catalog, making orders or viewing flights.
* [Partner API](/partner/api)- This represents global company level tooling that an administrator of an SDK implementation may need. The Management Console provides a user interface for this, however sometimes it's useful to be able to programatically administer the tool via the API directly.

## Mobile SDKs

Guestlogix's offerings are made available by implementing native iOS and Android SDKs.  For class level developer documentation see [Android Reference](https://android.guestlogix.io), and [iOS Reference](https://ios.guestlogix.io).

## Requirements

* You must be a Guestlogix Partner


# Release Notes

Release notes for the Guestlogix platform

{% content-ref url="/pages/-LaLM1mrY7fqrsFd-1Qc" %}
[2019 Release Notes](/release-notes/2019-release-notes)
{% endcontent-ref %}


# 2019 Release Notes

### Release


# Quick Start

The minimum, concise steps to get working with the Traveler SDK

### 1) Obtain Keys

To utilize any of the tooling outlined in this guide, one must obtain the Publishable, and Secret keys, as they authorize usage. To obtain these keys, visit the Management Console.

#### Publishable Key

This key can be included in client side source code, and is used to both uniquely identify, as well as authorize access to Guestlogix resources.

#### Secret Key

This key is NOT to be included in any client side source code. It is only to be sent to Guestlogix servers in a server-side pattern.

### 2) Initialize SDKs

With access keys in hand, you may now initialize the SDK of your choosing, for more see the desired getting started guide.

### iOS SDK

{% content-ref url="/pages/-LbOH9EJaOSqGaT7zX3Z" %}
[Getting Started](/traveler/mobile-sdks/ios/getting-started)
{% endcontent-ref %}

### Android SDK

{% content-ref url="/pages/-LbUp-7DarmEMcqRJbuG" %}
[Getting Started](/traveler/mobile-sdks/android/getting-started)
{% endcontent-ref %}


# Configuration settings

The Guestlogix platform can be configured to meet your airline's needs.

Each settings must be defined at the initial airline setup. If there is a need to change post setup, please submit a support request.  In the future, capabilities to change these settings will be provided within the Management Console.

| Setting              | Description                                                                                                                                                                                                                                                                         | Set via       |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| Promoted Cities      | Up to 2 cities can be defined as promoted destinations.  If there are no flights added by the traveler, these 2 cities will be displayed by default on the home page with experiences displayed for preview.                                                                        | Initial setup |
| Experience radius    | Experience radius will return catalog items that are within the target radius from the destination city.  Radius is defined in Kilometer (KM) and defaulted to 100 KM.                                                                                                              | Initial setup |
| Layover time limit   | If the flight added by a traveler has a lay over then the airport and city will be displayed within the Home page if the duration is above the threshold specified.  Default is set to 3 hours.                                                                                     | Initial setup |
| Statement descriptor | Modify what would a traveler see in their credit card statement.  As Guestlogix is the merchant of record, the billing party will be Guestlogix but additional information can be included to make it clear to the traveler.  Example: "Guestlogix - 3 Hour tour of Sydney Harbour" | Initial setup |
| From email address   | Once a traveler has purchased an experience, the tickets are sent via email.                                                                                                                                                                                                        | Initial setup |
| Logo                 | Provide a logo that would be included on the management console and traveler tickets                                                                                                                                                                                                | Initial setup |


# Environments

Distinctions of the backend deployments.

## Summary

Guestlogix's solution is multi tenanted, and therefore no separate provisioning of environments needs to happen. All a developer needs to get started are the [API Key](/quick-start#api-key), and [Secret](/quick-start#secret-key) Key.

## Production

Using the production API and Secret keys will make requests to the live production server. This means that credit cards will actually be processed, and content procured from the vendors. Take care in using these keys, and ensure they're only made use of in a live environment.

## Sandbox

Should the SDK be initialized with sandbox keys, all interactions with Guestlogix servers will be through a separate, test only environment. This means that no real credit card numbers will be accepted, booking of products and inventory will not actually be processed. This is useful when testing the application.&#x20;


# Domain Whitelist

All required domains to support Guestlogix web based tooling

## Traveler Web

This table outlines the host names, and their purpose that must be accessible in order for the traveler web application to function.

| Host | Purpose |
| ---- | ------- |
|      |         |


# Overview

Traveler Overview

## Purpose

This section outlines all tooling that pertains to usage by the end user of the system - the Traveler. This stakeholder will consume and view products made available to them. Guestlogix provides modules varying from full UI implementations to HTTPS endpoints depending on the level of configurability needed for the application.

{% content-ref url="/pages/-LaBswlaDm5VZG3\_mjiA" %}
[Mobile SDKs](/traveler/mobile-sdks)
{% endcontent-ref %}

{% content-ref url="/pages/-LaBneuAwwgU5a-eaITk" %}
[Traveler API](/traveler/api)
{% endcontent-ref %}


# Mobile SDKs


# Overview

The Traveler mobile SDKs come in three tiers, to allow maximum customization.

![SDK Tiers](https://1567453499-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-La1LLlqdqbG_qfZs0kr%2F-LaLGBeKkgGoSqEYPv4Y%2F-LaLGflev38_OIqEj8UC%2Fimage.png?alt=media\&token=c59381e2-3bee-47e6-a65c-bab2945cbcd7)

## Core (TravelerKit)&#x20;

This layer is the main API layer that is used to fetch catalogs, item details, all the way to placing an order and making a booking.

The core layer uses a facade object serving as a front-facing interface masking more complex underlying code. This makes it easy and consistent to integrate on multiple platforms.

## UI (TravelerKitUI)

This layer will contain helpful UI components as well as entire flows for your convenience and ease of integration. We highly recommend using as much of these flows and UI elements as possible for the best user experience.

## Payment Provider

In order to facilitate collection of payments, we currently only support Stripe, and as such have bundled all our Stripe integration components into one SDK to alleviate the developer from having to go through that process.&#x20;


# Minimum Requirements

## iOS

iOS 12.1 minimum

## Android

minSdkVersion 16 (Jelly Bean - 4.1)\
targetSdkVersion 28 (Pie - 9)


# iOS


# Installation

## Carthage

To install the SDK via Carthage add the following to your Cartfile and run the `carthage update` command from the terminal to fetch the SDKs onto your local machine.

```
github "Guestlogix/traveler-ios" "master"
```

This will download all three SDKs, include the ones you are interested in your Xcode project. For further information on how to include frameworks built by Carthage into your project read the [Carthage installation guide](https://github.com/Carthage/Carthage#quick-start).


# Getting Started

To initialize the SDK, add the following to your AppDelegate; including your [Publishable Key](/quick-start#publishable-key) in the `initialize` method.&#x20;

If you are integrating into an iPhone or iPad app, you should also include the UI SDK and initialize that as well. However in order to properly utilize the UI SDK a payment provider is required. Currently we only support [Stripe](https://stripe.com) as a payment provider so be sure to include that as well.

```swift
import TravelerKit
import TravelerStripePaymentProvider
import TravelerKitUI

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        // TravelerSDK

        Traveler.initialize(apiKey: "YOUR_API_KEY_GOES_HERE", device: UIDevice.current, sandboxMode: true)
        
        let paymentCollectorPackage = StripePaymentProvider(sandboxModeEnabled: true).paymentCollectorPackage()
        TravelerUI.initialize(paymentHandler: paymentCollectorPackage.1, paymentViewController: paymentCollectorPackage.0)

        return true
    }
}
```


# Android


# Installation

## Gradle

Add the following to the gradle dependencies section of you `build.gradle` file and sync.

```java
implementation "com.guestlogix.traveler:traveler_core"
implementation "com.guestlogix.traveler:traveler_ui"
implementation "com.guestlogix.traveler:traveler_stripe_payment_provider"
```

Also include the following repository reference.

```java
repositories {
    maven {
        url 'http://dl.bintray.com/guestlogix-it/Traveler'
    }
}
```


# Getting Started

To initialize the SDK, add the following to your Application subclass; including your [Publishable Key](/quick-start#publishable-key) in the `initialize` method.&#x20;

You should also include the UI SDK and initialize that as well. However in order to properly utilize the UI SDK a payment provider is required. Currently we only support [Stripe](https://stripe.com) as a payment provider so be sure to include that as well.

```java
public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        
        Traveler.initialize("YOUR_KEY_GOES_HERE", getApplicationContext());
        TravelerUI.initialize(new StripePaymentProvider());
    }
}

```

For this you must subclass the `Application` class and set it as the application in your `AndroidManifest.xml`. If you haven't done so already, create a class like above in your main application's project and be sure to add it to the application tag in your manifest like below

```markup
    <application
            android:name=".application.MyApplication"
            ...>
    </applcation>
```


# Usage


# Booking Item Search

Use this method to fetch a list of booking items based on a search Query.

You can search our catalog for [`BookingItems`](https://ios.guestlogix.io/Structs/BookingItem.html#/s:11TravelerKit11BookingItemV11isAvailableSbvp) with the `searchBookingItems` method. This method can be called through two options. Via completion blocks or through delegates.&#x20;

A complete working example on how this method can be used is available [here](https://github.com/Guestlogix/traveler-ios/blob/master/traveler-ios-ui/TravelerKitUI/ViewControllers/BookingItemSearchResultViewController.swift)

### Searching with delegates

To execute a booking search it is necessary to inject a `BookingItemQuery` object into the method and to declare an entity conforming to the `BookingItemSearchDelegate`. The method signature also includes an optional identifier. This identifier is meant to be used for pagination purposes, and it is not required.

The example below shows how to execute a basic search

{% tabs %}
{% tab title="iOS" %}

```swift
//In an existing ExampleViewController.swift
let searchQuery = BookingItemQuery(text: "Tours in Toronto", range: nil, boundingBox: nil)
Traveler.searchBookingItems(searchQuery: searchQuery, identifier: nil, delegate: self)
}

extension ExampleViewController: BookingItemSearchDelegate {
    func bookingItemSearchDidSucceedWith(_ result: BookingItemSearchResult, identifier: AnyHashable?) {
    // Successful search, deal with results here
    }
    
    func bookingItemsearchDidFailWith(_ error: Error, identifier: AnyHashable?) {
    // Unsuccessul search, deal with error here
    }
}
```

{% endtab %}

{% tab title="Android" %}

{% endtab %}
{% endtabs %}

This approach returns a [`BookingItemSearchResult`](https://ios.guestlogix.io/Structs/BookingItemSearchResult.html) through the delegates. The [`BookingItemSearchDelegate`](https://ios.guestlogix.io/Protocols/BookingItemSearchDelegate.html) also contains methods to deal with paginated results. These have default no-op implementations, so they're not required to conform to the protocol.

Pagination is handled by the SDK by receiving the initial or previous results and merging them to the new results if the search is consistent between calls. Both the previous result and the merged result are transmitted through delegates.

Paginated results can be handled as follows

{% tabs %}
{% tab title="iOS" %}

```swift
//In an existing PaginatedViewController.swift
var previousResult: BookingItemSearchResult?
let searchQuery = BookingItemQuery(page: page, for: searchQuery)
Traveler.searchBookingItems(searchQuery: searchQuery, identifier: page, delegate: self)
}

//Suggested approach: Extend booking query to have an initializer that takes pages
extension BookingItemQuery {
    static let pageSize = 10
    init(page: Int, for query: BookingItemQuery) {
        self.init(offset: page * BookingItemQuery.pageSize, take: query.limit, text: query.text, range: query.priceRange, categories: query.categories, boundingBox: query.boundingBox)
    }
}

extension PaginatedViewController: BookingItemSearchDelegate {
    func bookingITemSearchDidSucceedWith(_ result: BookingItemSearchResult, identifier: AnyHashable?) {
        // Deal with successful search
    }
    
    func bookingItemSearchDidReceive(_ result_ BookingItemSearchResult, identifier: AnyHashable?) {
        // Deal with merged results. 
    }
    
    func bookingItemSearchDidFailWith(_ error: Error, identifier: AnyHashable?) {
        // Deal with error while searching
    }
    
    public func previousResult() -> BookingItemSearchResult? {
        // Return previous results to the SDK. 
        return previousResult
    }
}
```

{% endtab %}

{% tab title="Android" %}

{% endtab %}
{% endtabs %}

### Searching with completion blocks

Search with completion blocks is an alternative approach to delegates. Structure is fairly similar, although a minor difference is that the approach with delegates allows the user to ignore pagination (see performing basic search above) whereas this approach forces the user to deal with pagination from the get go.

{% tabs %}
{% tab title="iOS" %}

```swift

// In an existing PaginatedViewController.swift
var previousResult: BookingItemSearchResult?
let searchQuery = BookingItemQuery(page: page, for: searchQuery)
Traveler.searchBookingItems(searchQuery: query, identifier: page, previousResultBlock: { () -> BookingItemSearchResult? in
            //Send previous result
            return previousResult
        }, resultBlock: { (mergedResults, identifier) in
            // deal with merged results
        }) { (searchResults, error, identifier) in
            //Deal with search results or error
        }
}

//Suggested approach: Extend booking query to have an initializer that takes pages
extension BookingItemQuery {
    static let pageSize = 10
    init(page: Int, for query: BookingItemQuery) {
        self.init(offset: page * BookingItemQuery.pageSize, take: query.limit, text: query.text, range: query.priceRange, categories: query.categories, boundingBox: query.boundingBox)
    }
}
```

{% endtab %}

{% tab title="Android" %}

{% endtab %}
{% endtabs %}


# Booking Item Search UI

{% tabs %}
{% tab title="iOS" %}
There is a complete flow in the UI layer of our SDK that deals with search. Like all of our flows it is designed using the Model-View-Controller architecture. To combat the problem of massive view controllers, this implementation makes heavy use of state machines and delegation.&#x20;

### Storyboard

An image of the search storyboard can be found below. The flow of information is color coded with blue arrows being information transmitted through segues and green arrows being information transmitted through delegates

![](https://1567453499-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-La1LLlqdqbG_qfZs0kr%2F-LrAF-Z5qSxtPnJuKYmM%2F-LrAUyhl8MlAvCj78LEP%2FBookingFlow.svg?alt=media\&token=491f19df-5aae-4360-b9d8-08fe5972dd91)

### ViewControllers

#### BookingItemSearchViewController

This is the first view controller in the storyboard and it is the entry view controller. This controller performs as a state machine. The complete source code for this view controller can be found [here](https://github.com/Guestlogix/traveler-ios/blob/master/traveler-ios-ui/TravelerKitUI/ViewControllers/BookingItemSearchViewController.swift).

The main responsibility of this view controller is to receive the text input from the user and execute a query from that text.&#x20;

* This view controller instantiates a [`UISearchController`](https://developer.apple.com/documentation/uikit/uisearchcontroller) and conforms to the [`UISearchBarDelegate`](https://developer.apple.com/documentation/uikit/uisearchbardelegate) protocol to handle search inputs
* Once the search is executed, this controller executes a search by calling the [searchBookingItems](/traveler/mobile-sdks/stripe-payment-sdk/booking-item-search) method.&#x20;
* While the search is being execute it performs a segue to the loading screen so a loading spinner renders
* In the delegate methods for search, if the error function executes then this view controller will trigger a segue to the `RetryViewController`. If the success function executes then the controller will trigger a segue to the `BookingItemSearchResultViewController`
* When executing a segue to the `BookingItemSearchResultViewController`, this controller will pass the search query and the search results in the `prepare(for segue: UIStoryboardSegue, sender: Any?)` method.
* This view controller also conforms to the `RetryViewControllerDelegate` protocol which has a function that executes when the retry button is pressed. Should this function execute, then this view controller will make the search call again.&#x20;

#### BookingItemSearchResultViewController

This view controller displays the items contained in the [`BookingItemSearchResult`](https://ios.guestlogix.io/Structs/BookingItemSearchResult.html) the complete source code for this view controller can be found [here](https://github.com/Guestlogix/traveler-ios/blob/master/traveler-ios-ui/TravelerKitUI/ViewControllers/BookingItemSearchResultViewController.swift).

The main responsibility of this view controller is to display the paginated results of a text search into a collection view.

Whenever the user taps into one of the items, this view controller will trigger a segue to a [`CatalogItem`](https://ios.guestlogix.io/Protocols/CatalogItem.html) flow that will display the details of that particular item. That flow is represented as a storyboard reference in the diagram above.&#x20;

#### RetryViewController

This view controller displays an error message and a retry button that will trigger a delegate function to inform its parent view controller that a retry was requested.
{% endtab %}

{% tab title="Android" %}

{% endtab %}
{% endtabs %}

###


# Flight Search

Use this method to provide real time flight search capabilities to your app.

{% tabs %}
{% tab title="iOS" %}

```swift
let query = FlightQuery(number: "AC01", date: Date())
Traveler.flightSearch(query: query) { (flights, error) in 
    // ...
}
```

Alternatively you can use the delegate pattern

```swift
Traveler.flightSearch(query: query, delegate: self)
```

```swift
extension MyViewController: FlightSearchDelegate {
    func flightSearchDidSucceedWith(_ result: [Flight]) {
    
    }
    
    func flightSearchDidFailWith(_ error: Error) {
    
    }
}
```

{% endtab %}

{% tab title="Android" %}

```java
FlightQuery query = new FlightQuery("AC01", new Date());
Traveler.flightSearch(query, new FlightSearchCallback() {
    @Override
    public void onFlightSearchSuccess(List<Flight> flights) {
    
    }
    
    @Override
    public void onFlightSearchError(Error error) {
    
    }
});
```

{% endtab %}
{% endtabs %}


# Catalog

Use this method to fetch a personalized catalog of purchasable items

{% tabs %}
{% tab title="iOS" %}

```swift
let query = CatalogQuery()
Traveler.fetchCatalog(query: query) { (catalog, error) in 

}
```

Alternatively you can use the delegate pattern

```swift
Traveler.fetchCatalog(query: query, delegate: self)
```

```swift
extension MyViewController: CatalogFetchDelegate {
    func catalogFetchDidSucceedWith(_ result: Catalog) {
    
    }
    
    func catalogFetchDidFailWith(_ error: Error) {
    
    }
}
```

The UI SDK ships with a view controller which you can use (and/or subclass) to display the catalog. If you wish you can also use them via storyboards, just remember to pass along the `Catalog` instance.

```swift
let catalogResultVC = CatalogResultViewController()
catalogResultVC.catalog = catalog
present(catalogResultVC, animated: true)
```

Should you require further customization, the UI SDK ships with a `CatalogView` that provides the basics of displaying two dimensional data.
{% endtab %}

{% tab title="Android" %}

```java
CatalogQuery query = new CatalogQuery();
Traveler.fetchCatalog(query, new CatalogSearchCallback() {
    @Override
    public void onCatalogSearchSuccess(Catalog catalog) {
    
    }
    
    @Override
    public void onCatalogSearchError(Error error) {
    
    }
});
```

The UI SDK ships with a fragment to handle the display of the fetched Catalog. To include this fragment add a `<FrameLayout>` to your Activity's layout XML:

```markup
    <FrameLayout
            android:id="@+id/catalogContainer"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
```

And in your Activity's `onCreate()` the `CatalogFragment`

```java
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
        
    CatalogFragment catalogFragment = CatalogFragment.newInstance(catalog);
        
    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    transaction.replace(R.id.catalogContainer, catalogFragment);
    
    transaction.commit();    
}
```

{% endtab %}
{% endtabs %}


# Catalog Item Details

For every item presented in the `Catalog` you can fetch details such as locations, contact information, prices and etc using the following method.

{% tabs %}
{% tab title="iOS" %}

```swift
let catalogItem = catalog.groups[0].items[0]
Traveler.fetchCatalogItemDetails(catalogItem) { (details, error) in

}
```

Alternatively you can use the delegate pattern

```swift
Traveler.fetchCatalogItemDetails(catalogItem, delegate: self)
```

```swift
extension MyViewController: CatalogItemDetailsFetchDelegate {
    func catalogItemDetailsFetchDidSucceedWith(_ result: CatalogItemDetails) }
    
    }
    
    func catalogItemDetailsFetchDidFailWith(_ error: Error) {
    
    }
}
```

It is recommended that you display the details of this item in a modal. The UI SDK ships with a storyboard for your convenience (`CatalogItem.storyboard`) so that if you wish to use our recommended flows from here all the way to making a booking, you can simply just use it as a reference in your own storybaords inside Xcode's Interface Builder. If you are not using storyboards, you can always instantiate the flow via code like below.

```swift
let storyboard = UIStoryboard(name: "CatalogItem", bundle: Bundle(for: CatalogItemViewController.self))
if let vc = storyboard.instantiateInitialViewController() {
    present(vc, animated: true)
}
```

{% endtab %}

{% tab title="Android" %}

```java
Traveler.fetchCatalogItemDetails(catalogItem, new CatalogItemDetailsCallback() {
    @Override
    void onCatalogItemDetailsSuccess(CatalogItemDetails catalog) {
    
    }
    
    @Override
    void onCatalogItemDetailsError(Error error) {
    
    }
});
```

It is recommended that you display the details of this item in a separate Activity. The UI SDK ships with an Activity for your convenience (`CatalogItemDetailsActivity`) so that if you wish to use our recommended flows from here all the way to making a booking, you can simply just start that activity inside yours using the designated Intent like below

```java
Intent i = TravelerUI.getCatalogItemDetailsIntent(catalogItem, this);
startActivity(i);
```

{% endtab %}
{% endtabs %}

&#x20;If you choose to use our recommended flow for the details screen and onwards, you can stop right here as our UI SDK will handle the rest all the way to booking and placing an order; however if you like to implement your own cusom UI and flow, you will be required to make a few more calls and collect more information from your user.


# Availabilities

To fetch the availability of a `Product` (`CatalogItem` or `CatalogItemDetails`) , you may use the following method, passing in the date range you are interested in. If you are only interested in a single day, just pass in the same end date as the start date.

This method will asynchronously return an `Availability` type for every date for which the desired experience is available.

{% tabs %}
{% tab title="iOS" %}

```swift
Traveler.fetchAvailabilities(product: catalogItemDetails, 
                           startDate: Date(), 
                             endDate: Date()) { (availabilities, error) in
  
}
```

Alternatively you can use the delegate pattern

```swift
Traveler.fetchAvailabilities(product: catalogItemDetails, 
                           startDate: Date(), 
                             endDate: Date()),
                            delegate: self)
```

```swift
extension MyViewController: AvailabilitiesFetchDelegate {
    func availabilitiesFetchDidFailWith(_ error: Error) {
    
    }
    
    func availabilitiesFetchDidSucceedWith(_ availabilities: [Availability]) {
    
    }
}
```

{% endtab %}

{% tab title="Android" %}

```java
Traveler.fetchAvailabilities(catalogItem, new Date(), new Date(), new FetchAvailabilitiesCallback() {
    @Override
    void onAvailabilitySuccess(List<Availability> availabilities) {
    
    }
    
    @Overrider
    void onAvailabilityError(Error error) {
    
    }
});
```

{% endtab %}
{% endtabs %}

Embedded inside each `Availability` there may optionally be a `BookingOptionSet` that provide the different `BookingOption`s that may exist for that date. An example of a `BookingOption` may be the different times that are available for that date.


# Getting Passes

Once you have the `Availability` the user is interested in, you can then fetch a list of `Pass`es that are available for the given `Product` and `Availability` (and optionally a `BookingOption`).  An example of a `Pass` might be "Adult" or "Child" passes that correspond to a tour. Passes may have different prices.

{% tabs %}
{% tab title="iOS" %}

```swift
Traveler.fetchPasses(product: catalogItem, 
                availability: selectedAvailability,
                      option: nil) { (passes, error) in
                      
}
```

Alternatively you can use the delegate pattern

```swift
Traveler.fetchPasses(product: catalogItem, 
                availability: selectedAvailability,
                      option: nil,
                    delegate: self)
```

```swift
extension MyViewController: PassFetchDelegate {
    func passFetchDidSucceedWith(_ result: [Pass]) {
    
    }
    
    func passFetchDidFailWith(_ error: Error) {
    
    }
}
```

{% endtab %}

{% tab title="Android" %}

```java
Traveler.fetchPasses(catalogItemDetail, availability, null, new FetchPassesCallback() {
    @Override
    void onSuccess(List<Pass> pass) {
    
    }
    
    @Override
    void onError(Error error) {
    
    }
});
```

{% endtab %}
{% endtabs %}


# Booking Form

Generally, [bookable products](/traveler/payments#payment-strategies) require some information about the user and or the individuals attending. Once the user has selected all the passes they are interested in, you must fetch a  `BookingForm` and provide an interface for the user to complete this form.

Note that the `Pass`es in the arguments is a flattened array of `Pass`es. For example if the user requires two of a single pass (i.e. two adult passes) then the array holds two of the same `Pass` type.

{% tabs %}
{% tab title="iOS" %}

```swift
Traveler.fetchBookingForm(product: catalogItemDetails,
                           passes: selectedPasses) { (form, error) in

}
```

Alternatively you can use the delegate pattern

```swift
Traveler.fetchBookingForm(product: catalogItemDetails,
                           passes: selectedPasses,
                         delegate: self)
```

```swift
extension MyViewController: BookingFormFetchDelegate {
    func bookingFormFetchDidFailWith(_ error: Error) {
    
    }
    
    func bookingFormFetchDidSucceedWith(_ bookingForm: BookingForm) {
    
    }
}
```

{% endtab %}

{% tab title="Android" %}

```java
Traveler.fetchBookingForm(catalogItemDetail, passes, new FetchBookingFormCallback() {
    @Override
    void onBookingFormFetchSuccess(BookingForm bookingForm) {
    
    }
    
    @Override
    void onBookingFormFetchError(Error error) {
    
    }
});
```

{% endtab %}
{% endtabs %}


# Questions

The `BookingForm` has in it an array of `QuestionGroup`s. Each `QuestionGroup` has a title, an optional disclaimer, and an array of `Question`s. Each `Question` then has a title, a description, a`Type` as well as some `VaidationRule`s

You are to ask the user all the questions presented inside a `BookingForm`


# Answers

To record an `Answer` to a `Question`, the `BookingForm` provides the following method

{% tabs %}
{% tab title="iOS" %}

```swift
let answer = TextualAnwer("John", question: question)
bookingForm.addAnswer(answer)
```

{% endtab %}

{% tab title="Android" %}

```java
Answer answer = TextualAnswer("John", question);
bookingForm.addAnswer(answer);
```

{% endtab %}
{% endtabs %}


# Validation

The `BookingForm` you submit to create an `Order` must be complete and valid. You can check the validity of the form (though some validations will only be checked at the time of order creation and you must handle the error properly)

{% tabs %}
{% tab title="iOS" %}

```swift
let errors: [BookingFormError] = bookingForm.validate()
```

{% endtab %}

{% tab title="Android" %}

```java
List<BookingFormError> errors = bookingForm.validate();
```

{% endtab %}
{% endtabs %}


# Creating an Order

Now that the user has completed the `BookingForm`, it is time to create the `Order`. The following method will create the `Order` which you can then present to the user for review.

{% tabs %}
{% tab title="iOS" %}

```swift
Traveler.createOrder(bookingForm: bookingForm) { (order, error) in

}
```

Alternatively you can use the delegate pattern

```swift
Traveler.createOrder(bookingForm: bookingForm, delegate: self)
```

```swift
extension MyViewController: OrderCreateDelegate {
    func orderCreationDidSucceed(_ order: Order) {
    
    }
    
    func orderCreationDidFail(_ error: Error) {
    
    }
}
```

{% endtab %}

{% tab title="Android" %}

```java
Traveler.createOrder(bookingForm, new OrderCreateCallback() {
    @Override
    void onOrderCreateSuccess(Order order) {
    
    }

    @Override
    void onOrderCreateFailure(Error error) {
    
    }
});
```

{% endtab %}
{% endtabs %}


# Processing an Order

Finally when the user has reviewed the `Order` and entered in their `Payment` information, you may process the order using the following method.

Currently the only acceptable payment strategy is through Stripe and you can use our StripePaymentProvider SDK together with the UI SDK to collect and process payment info.

This call will asynchronously return a `Receipt` which you can show to the user as a successful confirmation of the order.

{% tabs %}
{% tab title="iOS" %}

```swift
Traveler.processOrder(order, payment: payment) { (receipt, order) in 

}
```

Alternatively you can use the delegate pattern

```swift
Traveler.processOrder(order, payment: payment, delegate: self)
```

```swift
extension MyViewController: OrderProcessDelegate {
    func order(_ order: Order, didSucceedWithReceipt receipt: Receipt) {
    
    }
    
    func order(_ order: Order, didFailWithError error: Error) {
    
    }
}
```

{% endtab %}

{% tab title="Android" %}

```java
Traveler.processOrder(order, payment, new ProcessOrderCallback() {
    @Override
    void onOrderProcessSuccess(Receipt receipt) {
    
    }
    
    @Override
    void onOrderProcessError(Error error) {
    
    }
});

```

{% endtab %}
{% endtabs %}


# Errors


# Traveler API

Architecture of the Guestlogix RESTful API

## Documentation

The Traveler REST API utilizes Swagger to autogenerate the specification. It can be found [here](https://traveler.dev.guestlogix.io/v1/swagger/index.html). The conventions around naming, data types etc. can be found in the [API Convention](/glossary/api-convention#api-convention) page.

## Device Information

Any request made to the Traveler API must include device specific information. This required headers are outlined below.

| Header             | Type   | Example Value                          | Purpose                                                                                                                                                                                  |
| ------------------ | ------ | -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `x-device-id`      | String | `50565c00-6bba-4b7f-bfc2-593c50520e21` | A value representing a unique installation of the application on a user's device.                                                                                                        |
| `x-os-version`     | String | `iOS12.1`                              | The version of the operating system of the device making the request.                                                                                                                    |
| `x-language`       | String | `en`                                   | The [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) two letter language code of the user's device.                                                                    |
| `x-locale`         | String | `en-US`                                | The Locale as defined by [Apple guidelines](https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPInternational/LanguageandLocaleIDs/LanguageandLocaleIDs.html). |
| `x-region`         | String | `CA`                                   | The [ISO-3166](https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes) two character country code from which the requesting device is from.                                        |
| `x-application-id` | String | `com.guestlogix.traveler`              | The Unique identifier of the application that is using the SDK or API.                                                                                                                   |
| `x-timezone`       | String | `UTC`                                  | The [timezone abbreviation](https://en.wikipedia.org/wiki/List_of_time_zone_abbreviations) that the device is displaying time in.                                                        |


# Payments

All information regarding payments within the Guest solution.

## Orders

Every payment accepted within the Guest solution is associated to an Order. This can be thought of as a container or 'cart' for all products, tangible and physical, that are part a single purchase.

We do not support multiple payment types for a single order. Only a single credit card may be used for the entirety of the order.

## Stripe

[Stripe](https://stripe.com) is a 3rd party API that allows the Guest solution to tokenize, and process consumer credit cards.

### Test Data

All uses of the SDK or API with a Sandbox API Key, will be creating dummy transactions, that will not actually be processed by a bank. Stripe makes a very clear distinction between dummy/test charges and actual production charges. This allows developers to test end to end cases, without incurring actual costs on a real credit card.

{% hint style="warning" %}
No real credit card numbers will work within the Sandbox. For a complete list of demo cards see [here](https://stripe.com/docs/testing#cards).
{% endhint %}

### Captured Transactions

Stripe allows for the pre-authorization of a purchase, which will guarantee the funds on the payment card for up to seven days. This will happen in the solution while a booking is being confirmed by the supplier. See the [Stripe documentation](https://stripe.com/docs/charges#auth-capture) for more details.

## Payment Strategies

The Guest app employs two different booking strategies, **Buyable** and **Bookable**.

### Bookable Content

Bookable content requires confirmation from the selling party that the booking was indeed accepted and authorized. There also exists some supplementary information as part of the checkout flow that is required by the party offering the bookable content (e.g. Name of ticket holder, dietary restrictions etc.) These questions are defined by the supplier, and surfaced through the SDK.

### Buyable Content

{% hint style="danger" %}
This strategy is not currently implemented
{% endhint %}

Buyable content refers to content that needs no confirmation.


# Overview

Partner Overview

## Purpose

A Partner stakeholder is a user that administers the offerings, and experience of a [Traveler](/traveler/guest-app-overview). The tooling provided serves up insights about the performance of any Traveler tooling utilization. It also exposes methods that allow for customizations to the content exposed to a Traveler, campaign design and other organization level configurations.

There currently exists no SDK tooling, and limited read only methods exposed via the [API](/partner/api).


# Partner API

## Documentation

The Traveler API utilizes Swagger to autogenerate the specification. It can be found [here](http://guest-partner-api-develop-eb.guestlogix.io/swagger/index.html). The conventions around naming, data types etc. can be found in the [API Convention](https://guestlogix.gitbook.io/docs/~/drafts/-LaCd56FG8nJPrZ471y0/primary/glossary/api-convention#api-convention) page.


# API Convention

### API Definitions

{% hint style="info" %}
Whenever the spelling for a particular entity is ambiguous between different [lects](https://en.wikipedia.org/wiki/Variety_\(linguistics\)) of English, always side with [American English](https://en.wikipedia.org/wiki/American_English).
{% endhint %}

There are two distinct base URLs for the solution.

* [Traveler](/traveler/api) - This represents all resources and actions that an end user of the SDK would need. Functionality such as browsing a catalog, making orders or viewing flights.
* [Partner ](/partner/api)- This represents global company level tooling that an administrator of an SDK implementation may need. The Management Console provides a user interface for this, however sometimes it's useful to be able to programatically administer the tool via the API directly.

### API Convention

#### Resources

* Resources should always be singular, and should descend into its components down a path. e.g

  ```
  https://guestlogix.io/resource/{resource-id}/sub-resource/{sub-resource-id}
  ```
* Query parameters are to use lowercase ['spinal' or 'kebab' case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles). e.g.

  ```
  https://guestlogix.io/resource?query-param=x&another-query-param=y
  ```

### API Errors

Should the API consumer provide insufficient parameters, or request a resource out of order the API will return a `4xx` level status code. For more granularity, an error code and message will accompany the response. The errors are outlined in more detail in the [Error Codes](/glossary/api-convention/error-codes).

### Date and Time Formatting

In the context of JSON formatting, the following methods of representation are used:

**DateTime**

When an instance in time is needed, a fully formatted [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) string is to be used.

eg.

```javascript
{
   "dateTime" : "2018-12-10T17:05:09Z" //December 10th 2018 12:05:09pm UTC Time
}
```

**Date**

When a single calendar day is needed to be represented, and time is irrelevant, a string of the format `YYYY-MM-DD` is to be used.

eg.

```javascript
{ 
   "date" : "2018-12-10" //December 10th 2018
}
```

**Time**

When a time of day is to be used, the attribute that holds it should have the suffix `inSeconds`, `inMinutes` or `inHours` etc. and refers to corresponding integer number since midnight of a given day.

eg.

```javascript
{ 
   "timeInSeconds" : 25200, //7:00am
   "timeInMinutes": 420, //7:00am
   "timeInHours": 7 //7:00am
}
```


# Error Codes

Context to the 4 digit codes returned by the API

### General

| ErrorCode | ErrorEnum                 | Meaning                                               |
| --------- | ------------------------- | ----------------------------------------------------- |
| `1001`    | `NotFound`                | The specified entity is not found                     |
| `1002`    | `ArgumentNullOrEmpty`     | A required parameter has been omitted.                |
| `1003`    | `BadArgumentException`    | A required parameter is malformed.                    |
| `1004`    | `ConfigurationException`  | An invalid Configuration has been referenced.         |
| `1005`    | `NotImplementedException` | A requested resource or action has no implementation. |

### Orders and catalogs

| ErrorCode | ErrorEnum                  | Meaning                                                                                          |
| --------- | -------------------------- | ------------------------------------------------------------------------------------------------ |
| `2001`    | `PriceInvalid`             | The supplied price is malformed, or inconsistent.                                                |
| `2002`    | `DateTimeInvalid`          | The supplied datetime is malformed, or inconsistent.                                             |
| `2003`    | `PaymentCannotBeProcessed` | The payment cannot be processed. More information is provided as part of the message in context. |

### Flights, cities and airports

| ErrorCode | ErrorEnum                  | Meaning                                                                                                                   |
| --------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `3001`    | `OriginDestinationInvalid` | The requested origin, or destination of the flight is malformed or non existent.                                          |
| `3002`    | `IataInvalid`              | The supplied [IATA code ](https://www.nationsonline.org/oneworld/IATA_Codes/IATA_Code_A.htm)is malformed or non existent. |
| `3003`    | `GeoLocationInvalid`       | The geography supplied is malformed.                                                                                      |
| `3004`    | `FlightsInThePast`         | The requested flight exists in the past. Only present and future flights are available.                                   |
| `3005`    | `FlightNumberInvalid`      | The supplied flight number is malformed.                                                                                  |

### Users

| ErrorCode | ErrorEnum      | Meaning                                                              |
| --------- | -------------- | -------------------------------------------------------------------- |
| `4001`    | `EmailInvalid` | The provided email is malformed.                                     |
| `4002`    | `UserExists`   | An attempt was made to create a user already existing in the system. |


# API Rate Limiting

We limit API requests to 10,000 per minute


# Terminology

| Term        | Definition                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Partner     | A partner within the Guest App is the airline that Guestlogix has agreed to provide service to across the platform (SDK, White label, or APIs)                                                                                                                                                                                                                                                                                                                                                            |
| Traveler    | The entity that represents an end customer of the catalog exposed by the SDK.                                                                                                                                                                                                                                                                                                                                                                                                                             |
| Supplier    | Suppliers are the services Guestlogix has sought after to provide purchasable content within the Guest App.  Examples of a suppliers are SimpleNight, Livn, and Tiqets.                                                                                                                                                                                                                                                                                                                                   |
| Vendor      | The vendor is the experience provider for an event/item offered by the supplier.  An example of a vendor is the Royal Ontario Museum.                                                                                                                                                                                                                                                                                                                                                                     |
| Bookable    | A Payment Strategy that involves purchasing admission to some form of event. See [Payments](/traveler/payments#bookable-content)                                                                                                                                                                                                                                                                                                                                                                          |
| Buyable     | A Payment Strategy that involves purchasing a time independent good. See [Payments](/traveler/payments#buyable-content)                                                                                                                                                                                                                                                                                                                                                                                   |
| Gross price | <p>The price a traveler pays for an experience can be distributed either Gross or Net.  Gross commission is split among the airline, experience supplier, and Guestlogix.  The commission price is generally established by the supplier.  There is a transaction fee that goes to Stripe.</p><p><img src="https://firebasestorage.googleapis.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-La1LLlqdqbG_qfZs0kr%2Fuploads%2FGwdzie8pgLTkFCtuTlVD%2Ffile.png?alt=media" alt="" data-size="original"></p> |
| Net price   | <p>The price a traveler pays for an experience can be distributed either Gross or Net.  Net includes a markup price that is split among the airline and Guestlogix.  The mark up is set by Guestlogix.  There is a transaction fee that goes to Stripe and the experience supplier.</p><p></p><p><img src="https://firebasestorage.googleapis.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-La1LLlqdqbG_qfZs0kr%2Fuploads%2FYKQcF74tZKyiyBylsrzj%2Ffile.png?alt=media" alt=""></p>                      |
| Device      | The device the traveler installed the application on                                                                                                                                                                                                                                                                                                                                                                                                                                                      |

| Concept         | Description and relationship to others                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Catalog         | This is the overall collection of things that can be browsed through and bought by Traveler or Crew Member. The items in the catalogue are enabled via Management Console.                                                                                                                                                                                                                                                                                                                                                                                                                      |
| Catalogitem     | This is a specific item that can be seen in the catalogue and purchased. Its details are viewed on its detail page. It can be purchased individually or in combination with other items. The types of items include: experience item (e.g. stuff provided through Simplenight), flight service item (e.g. jump the line, upgrade seat, etc), Buy on Board item (e.g. sandwich, blanket, etc).                                                                                                                                                                                                   |
| Experience item | This is a catalogue item. These pertain to the between flights or before/after flight activities that a Traveler or Crew Member might want to do. There are 7 types: tours, activities, dining, shows, nightlife, car service, hotel food and board. There might be 1 more type coming up: parking (this is TBD). Each type has its own attributes necessary to be captured at the time of placement into shopping cart or when the item is being put into wishlist or into journey. The types have a priority we are working on them in and each one has its own user story in waffle backlog. |
| Flight          | This is specifically referring to one flight done by traveller on one plane, e.g. from Toronto to London. It could be one of the many legs in the journey that the Traveller will do. We'll be able to help Traveller construct their overall journey through the concept of journey where they would be able to specify how many legs they'll be doing. E.g. Toronto To London, London to Paris. or Toronto to London, London to Paris, Paris to London, London to Toronto. Return trip or one way.                                                                                            |


# Contact

## Slack developer community

We've got a Slack channel ready so that developers can reach out to us directly. Once you've handed the documentation off, please provide us with a list of emails of the folks who should be added to that.  You may send the contacts to **Will Mero** <wmero@guestlogix.com> and <customersupport@guestlogix.com>.


