Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 7 Current »

Introduction and Concepts

Through this guide, developers will be able to create their own widgets to embed in the web sites and from it, access via parameters to the E-COMMERCE booking functionalities.

This document explains how to obtain and connect the developed Widget with the booking engine, detailing the services and fields that must be considered in order to build the tool and achieve the searches to be displayed later in the next SPA, according to the selected flow.

The booking screen, is configurable, since different flows converge there, as listed below:

Search flight: Used only for flight searching and bookings generation

Manage my booking: Used to retrieve a booking previously generated and make changes to it

Web check-in: Dedicated to managing the check-in on a segment that is about to begin

What is a widget?

A Widget is a simple application that can be included on the airline's website aiming to extend the functionality to our e-commerce. We provide a widget that can be embedded using an HTML iframe tag into any website. Nevertheless, if this widget does not has all that is needed, a custom widget can be created using our API REST services. These services will provide all the necessary data to guarantee compatibility through the booking flow.

Embedded Widget via Iframe

Url for the iframe

In case you need to use KIU widget you can add it to yor code using an iframe <iframe src="https://ecommerce-xx-stage.kiusys.net/booking/widget/"</iframe>

Custom Widget

Assuming that the developer builds a HTML form, there are some mandatory fields to be sent in order to access the e-commerce filghtresults SPA or any other flow.

General considerations

E-COMMERCE is a client-server application, where the client is built under the Single Page Application (SPA) model. Each step of the flow is independent of the rest, and also, independent from the backend server where the business logic resides.

The widget must obtain the content and configurations stored in the e-commerce backoffice. This guide explains how to connect and get this content.

General Url to implement a custom widget

To consume the necessary services a valid url must be used, for example, this this url it is used for xx carrier int the testing enviroment

https://ecommerce-xx-stage.kiusys.net/

Services

Get Applications

E-COMMERCE is divided into applications searchflight, manage my booking y webcheckin. The flow of these apps is set in the backoffice. To get a list of the available applications this service can be used

Url:

https://ecommerce-xx-stage.kiusys.net/searchflight/api/v1/applications/xx

Implementation:

 Click here to expand...
let headers = {
    'Content-Type': 'application/json',
    'accept': 'application/json', 
    'carrier': 'xx',
    'sec-fetch-site': 'same-origin',
    'sec-fetch-mode': 'cors',
    'referer': 'https://ecommerce-xx-stage.kiusys.net/searchflight/',
    'authority': 'ecommerce-xx-stage.kiusys.net'
}
var url = 'https://ecommerce-xx-stage.kiusys.net/searchflight/api/v1/applications/xx'
fetch(url, {
 	    method: 'GET',
 	    headers: headers
    }
).then(res => res.json())
.catch(error => console.error('Error:', error))
.then(
	response => handleAppsResponse(response)
)

Response:

 response with the list of applications
{
   "kiu_internals":{
      "duration":3.25775146484375,
      "id_tracking":"backendsearchflight.5b8e970fa8d1_04245c28f792435f92d1f513d4824d41"
   },
   "response":[
      "ecommerce",
      "manage",
      "webcheckin"
   ]
}

Get Flow

GetFlow is the second service to use, where you should obtain a session key and the flow configuration of the selected app. This sessionkey it's going to be used in the next request. Additionally having the flow will give us the next screen to be rendered.

Url:

https://ecommerce-xx-stage.kiusys.net/searchflight/api/v1/flow/?carrier=xx&app=ecommerce

Implementation:

 Click here to expand...
let headers = {
    'Content-Type': 'application/json',
    'accept': 'application/json', 
    'carrier': 'xx',
    'sec-fetch-site': 'same-origin',
    'sec-fetch-mode': 'cors',
    'referer': 'https://ecommerce-xx-stage.kiusys.net/searchflight/',
    'authority': 'ecommerce-xx-stage.kiusys.net'
}
var url = 'https://ecommerce-xx-stage.kiusys.net/searchflight/api/v1/flow/?carrier=xx&app=ecommerce'
fetch(url, {
 	    method: 'GET',
 	    headers: headers
    }
).then(res => res.json())
.catch(error => console.error('Error:', error))
.then(
	response => customHandleResponseFunction(response)
)

Response:

 Click here to expand...
{
   "kiu_internals":{
      "duration":0.19812583923339844,
      "id_tracking":"backendsearchflight.29bad7c320a2_6a0a84986ffd41cc8fb90dee945baf21"
   },
   "response":{
      "flow":[
         {
            "id":1,
            "spaflow_id":1,
            "url":"/searchflight/",
            "zorder":0
         },
         {
            "id":2,
            "spaflow_id":1,
            "url":"/flightresults/",
            "zorder":1
         },
         {
            "id":5,
            "spaflow_id":1,
            "url":"/travellerdetails/",
            "zorder":2
         },
         {
            "id":8,
            "spaflow_id":1,
            "url":"/extraservices/",
            "zorder":3
         },
         {
            "id":6,
            "spaflow_id":1,
            "url":"/purchase/",
            "zorder":4
         },
         {
            "id":7,
            "spaflow_id":1,
            "url":"/endflow/",
            "zorder":5
         }
      ],
      "session_key":"fake-test-key.rPnZwFJPXkQ"
   }
}

Response dictionary:

 Click here to expand...

field

description

Value/format

flow

List of screens inside the flow

Array → Object

spaflow_id

id of the record inside the flow manager

Int

url

Path of the screen inside the flow

String, Ej. '/flightresults/'

zorder

Order of the screen

Int

Get configs

This is the main service where we will have all the selected app configuration (only for searchflight and webcheckin)

 Click here to expand...
const appsSchema = {
			ecommerce: {
			app: 'ecommerce',
			module: 'searchflight',
			needConfigs: true
		},
		manage: {
			app: 'manage',
			module: 'managebooking',
			needConfigs: false
		},
		webcheckin: {
			app: 'manage',
			module: 'retrievebooking',
			needConfigs: true
		}
};

This json is a suggestion for the developer. It shows what is needed in each app.

Url (app searchflight):

https://ecommerce-xx-stage.kiusys.net/searchflight/api/v1/configs/


Implementation:

 Click here to expand...
let headers = {
    'Content-Type': 'application/json',
    'accept': 'application/json', 
    'carrier': 'xx',
    'sec-fetch-site': 'same-origin',
    'sec-fetch-mode': 'cors',
    'referer': 'https://ecommerce-xx-stage.kiusys.net/searchflight/',
    'authority': 'ecommerce-xx-stage.kiusys.net',
    'authorization': 'Token session_key obtenido en get_sessions'
}
fetch('https://ecommerce-xx-stage.kiusys.net/searchflight/api/v1/configs/', {
 	    method: 'GET',
 	    headers: headers
    }
).then(res => res.json())
.catch(error => console.error('Error:', error))
.then(
	response => customHandleResponseFunction(response)
)

Response:

 Click here to expand...
{
   "kiu_internals":{
      "duration":2645.9577083587646,
      "id_tracking":"backendsearchflight.29bad7c320a2_3f5d1423f4504527b433ede5a4cbd14c"
   },
   "response":{
      "cabin":{
         "business":true,
         "business_default":false,
         "economy":true,
         "economy_default":false,
         "economy_premium":false,
         "economy_premium_default":false,
         "first":true,
         "first_default":true,
         "id":2,
         "setting":"0be29d7e-c626-4d07-b60f-6917cc890bc6"
      },
      "carrier":{
         "code":"XX",
         "enable":true,
         "name":"EQUIS",
         "numcode":"001",
         "uuid":"982726d9-965b-4ea4-a22b-aa765dbe8dc7"
      },
      "country_settings":[
         {
            "currency_code":"USD",
            "default":true,
            "device_id":"AEP00XXW04",
            "enable":true,
            "id":45,
            "iso_country_code":"AR",
            "setting":"0be29d7e-c626-4d07-b60f-6917cc890bc6",
            "user_id":"AEP00XXSM"
         }
      ],
      "display_logics":[
         {
            "airport_code":true,
            "airport_name":true,
            "city_code":true,
            "city_name":true,
            "country_code":true,
            "country_name":true,
            "device_type":"m",
            "id":4,
            "setting":"0be29d7e-c626-4d07-b60f-6917cc890bc6"
         },
         {
            "airport_code":true,
            "airport_name":true,
            "city_code":true,
            "city_name":true,
            "country_code":true,
            "country_name":true,
            "device_type":"d",
            "id":5,
            "setting":"0be29d7e-c626-4d07-b60f-6917cc890bc6"
         },
         {
            "airport_code":true,
            "airport_name":true,
            "city_code":true,
            "city_name":true,
            "country_code":true,
            "country_name":true,
            "device_type":"t",
            "id":6,
            "setting":"0be29d7e-c626-4d07-b60f-6917cc890bc6"
         }
      ],
      "eligibilities":[
         {
            "code":"KIU",
            "enable":true,
            "id":3,
            "setting":"0be29d7e-c626-4d07-b60f-6917cc890bc6"
         }
      ],
      "journey_type":{
         "id":2,
         "multicity":false,
         "multicity_default":false,
         "one_way":true,
         "one_way_default":true,
         "round_trip":true,
         "round_trip_default":false,
         "setting":"0be29d7e-c626-4d07-b60f-6917cc890bc6"
      },
      "languages":[
         {
            "lang":"en"
         },
         {
            "lang":"es"
         }
      ],
      "passenger_types":[
         {
            "code":"ADT",
            "enable":true,
            "id":9,
            "max_quantity":6,
            "ptc":"ADT",
            "setting":"0be29d7e-c626-4d07-b60f-6917cc890bc6"
         },
         {
            "code":"INF",
            "enable":true,
            "id":10,
            "max_quantity":6,
            "ptc":"INF",
            "setting":"0be29d7e-c626-4d07-b60f-6917cc890bc6"
         },
         {
            "code":"CHD",
            "enable":true,
            "id":11,
            "max_quantity":3,
            "ptc":"CHD",
            "setting":"0be29d7e-c626-4d07-b60f-6917cc890bc6"
         }
      ],
      "privacy_policy":{
         "confirmation_button":false,
         "enable":true,
         "id":2,
         "setting":"0be29d7e-c626-4d07-b60f-6917cc890bc6"
      },
      "promo":{
         "codes":[
            {
               "code":"PROMO1",
               "id":4,
               "promo":2
            }
         ],
         "enable":true,
         "id":2,
         "setting":"0be29d7e-c626-4d07-b60f-6917cc890bc6"
      },
      "routes":[
         {
            "carrier":"982726d9-965b-4ea4-a22b-aa765dbe8dc7",
            "destination":{
               "city":{
                  "code":"BUE",
                  "country":{
                     "code":"AR",
                     "description":"ARGENTINA",
                     "id":17
                  },
                  "description":"BUENOS AIRES",
                  "id":35
               },
               "code":"AEP",
               "description":"AEROPARQUE JORGE NEWBERY",
               "id":79
            },
            "id":47,
            "origin":{
               "city":{
                  "code":"COR",
                  "country":{
                     "code":"AR",
                     "description":"ARGENTINA",
                     "id":17
                  },
                  "description":"CORDOBA",
                  "id":26
               },
               "code":"COR",
               "description":"PAJAS BLANCAS",
               "id":27
            }
         }
      ],
      "setting":{
         "carrier":"982726d9-965b-4ea4-a22b-aa765dbe8dc7",
         "enable":true,
         "name":"init",
         "uuid":"0be29d7e-c626-4d07-b60f-6917cc890bc6"
      },
      "temporary_message":{
         "color":"primary",
         "details":[
            {
               "datetime":"2020-03-17T16:20:41.331326Z",
               "enable":true,
               "id":26,
               "link":"http:XX.com",
               "name":"b'U1\\x03\\x9d'",
               "show_datetime":false,
               "temporary_message":2
            }
         ],
         "id":2,
         "setting":"0be29d7e-c626-4d07-b60f-6917cc890bc6"
      },
      "translations":{
         "en":{
            "aaaa":"aaaa",
            "child":"Child",
            "descriptions":"xczvzxv",
            "descriptionseeeee":"dddddd",
            "language_description":"English",
            "lugateste":"lugatest",
            "luggage":"Luggage",
            "meal":"Meal",
            "pax":"Passenger",
            "test123":"test"
         },
         "es":{
            "aaaa":"12345",
            "child":"Ni\u00f1o",
            "descriptions":"zsvzvxdv",
            "descriptionseeeee":"dddd",
            "infant":"infante",
            "meal":"Comida",
            "pax":"Pasajero",
            "testing":"fff"
         },
         "kiu_internals":{
            "id_tracking":"kiu-translate.kiu-translate-qa_fe9212c0a9604a619fa34deab8341f61"
         }
      }
   }
}

Response Dictionary:

 Click here to expand...

field

next level field

description

values/format

routes

List of origin destination combinations

Array → Object

origin

Origin information, country, city, code, description

Object

destination

Destination information, country, city, code, description

Object

country_settings

Country and currency configurations. This informations it is used to build the point of sale

Array → Object

currency_code

currency code

String, Ej. ‘USD’

default

indicates whether is the defualt config

Boolean

device_id

PSS terminal_id/device_id

String. Ej. ‘AEP00XXW04’

user_id

PSS user_id/agente_id

String. Ej. ‘AEP00XXSM’

enable

indicates whether is enable

Boolean

iso_country_code

Country code

String. Ej. ‘AR’

display_logics

Backoffice configuration, indicates how to display origin and destination in the form in each device

Array → Object

airport_code

Boolean

airport_name

Boolean

city_code

Boolean

city_name

Boolean

country_code

Boolean

country_name

Boolean

device_type

m: mobile, d: desktop, t: tablet

String: Ej. ('m', ‘t', 'd’)

journey_type

Indicate the availble and default type of journey

Object

one_way

Boolean

one_way_default

Boolean

round_trip

Boolean

round_trip_default

Boolean

multicity

Boolean

multicity_default

Boolean

passenger_types

Type of passenger configuration

Array → Object

code

ADT: Adult, INF: Infant, CHD: Child

String. Ej. 'ADT'

enable

Bolean

max_quantity

Int

ptc

String. Ej. 'MIL'

eligibilities

List of eligibilities to display on the form

Array → Object

code

String

enable

Boolean

cabin

Cabin configurations

Objet

“Business“

Boolean

“Business_default“

Boolean

temporary_message

temporary messages configured at the back office

Object

color

String

details

Array -> Object

translations

translations foreach label

Object → Object

promo

promo codes configurations

Object

enable

Boolean

codes

Array → Object

privacy_policy

privacy policie configured at the backoffice

Object

confirmation_button

indicates whether confiramtion button must be shown

Boolean

enable

indicates whether is enable

Boolean

languages

list of available languages

Array → Object

Based on thius response the developer has enough information to display some fields on the widget, enable routes, different types of pax, and max quantity, types of journey, currencies, cabins, temporary messages, etc...

Url (app webcheckin):

https://ecommerce-xx-stage.kiusys.net/retrievebooking/api/v1/configs/

Implementation:

 Click here to expand...
let headers = {
    'Content-Type': 'application/json',
    'accept': 'application/json', 
    'carrier': 'xx',
    'sec-fetch-site': 'same-origin',
    'sec-fetch-mode': 'cors',
    'referer': 'https://ecommerce-xx-stage.kiusys.net/searchflight/',
    'authority': 'ecommerce-xx-stage.kiusys.net',
    'authorization': 'Token session_key obtenido en get_sessions'
}
fetch('https://ecommerce-xx-stage.kiusys.net/retrievebooking/api/v1/configs/', {
 	    method: 'GET',
 	    headers: headers
    }
).then(res => res.json())
.catch(error => console.error('Error:', error))
.then(
	response => customHandleResponseFunction(response)
)

Response:

 Click here to expand...
{
   "kiu_internals":{
      "duration":15.575170516967773,
      "id_tracking":"backend_retrieve_booking.1a3b98991b77_20b1ae1b2abf4dc5b1c0b04a1c4ddefe"
   },
   "response":[
      {
         "currency_code":"ARS",
         "default":true,
         "device_id":"AEP00XXW04",
         "enable":true,
         "id":3,
         "iso_country_code":"AR",
         "setting":"c256b8d5-dd08-45ba-a546-7057bef51199",
         "user_id":"AEP00XXSM"
      }
   ]
}

Diccionario de respuesta:

 Click here to expand...

Field

Description

Valores/formato

Country and currency configurations. This informations it is used to build the point of sale

Array

currency_code

currency code

String, Ej. ‘USD’

default

indicates whether is the defualt config

Boolean

device_id

PSS terminal_id/device_id

String. Ej. ‘AEP00XXW04’

user_id

PSS user_id/agente_id

String. Ej. ‘AEP00XXSM’

enable

indicates whether is enable

Boolean

iso_country_code

Country code

String. Ej. ‘AR’

Get Dates (Usado para searchflight)

Returns a list of dates with the availability of flights from today up to 330 days. Origin and destination must be specified

Parameters:

origin: airport code, for example 'MAD'

destination: airport code, for example 'CUN'

Url:

https://ecommerce-xx-stage.kiusys.net/searchflight/api/v1/dates/?origin=${origin}&destination=${destination}


Implementation:

 Click here to expand...

This endpoint run by GET method, with query params

let origin = 'AEP';
let destination = 'COR';
let headers = {
    'Content-Type': 'application/json',
    'accept': 'application/json', 
    'carrier': 'xx',
    'sec-fetch-site': 'same-origin',
    'sec-fetch-mode': 'cors',
    'referer': 'https://ecommerce-xx-stage.kiusys.net/searchflight/',
    'authority': 'ecommerce-xx-stage.kiusys.net',
    'authorization': 'Token session_key obtenido en get_sessions'
}
fetch(`https://ecommerce-xx-stage.kiusys.net/searchflight/api/v1/dates/?origin=${origin}&destination=${destination}`, {
 	    method: 'GET',
 	    headers: headers
    }
).then(res => res.json())
.catch(error => console.error('Error:', error))
.then(
	response => customHandleResponseFunction(response)
)

Response:

 Click here to expand...
{
   "kiu_internals":{
      "duration":39.411306381225586,
      "id_tracking":"backendsearchflight.29bad7c320a2_650ed89aeee64f209f6f9b4357a57a6a"
   },
   "response":{
      "ow":[
         "2020-04-03",
         "2020-04-04",
         "2020-04-05",
         "2020-04-06",
         "2020-04-07",
         "2020-04-08",
         "2020-04-09",
         "2020-04-10",
         "2020-04-11",
         "2020-04-12",
         "2020-04-13",
         "2020-04-14",
         "2020-04-15",
         "2020-04-16",
      ],
      "rt":[
         "2020-04-03",
         "2020-04-04",
         "2020-04-05",
         "2020-04-06",
         "2020-04-07",
         "2020-04-08",
         "2020-04-09",
         "2020-04-10",
         "2020-04-11",
         "2020-04-12",
         "2020-04-13",
         "2020-04-14",
      ]
   }
}

This response can be used to disable days in the datepicker input.

Post action (searchflight)

This service is used to send all the required data for a flight search. The request must be done using POST AJAX and after the response, a redirect must take place to the next step of the flow.

Parameters:

country_setting: Config selected by the passenger
session_key: previously obtained session_key (get_sessions)
journey_type: type of journey (ow/rt)
origin
destination
departure_date
return_date
adults
minors
infants
cabin
promo

Url:

https://ecommerce-xx-stage.kiusys.net/searchflight/api/v1/action/


Implementation:

 Click here to expand...
var formData = {
	country_setting: {
        "currency_code":"USD",
        "default":true,
        "device_id":"AEP00XXW04",
        "enable":true,
        "id":45,
        "iso_country_code":"AR",
        "setting":"0be29d7e-c626-4d07-b60f-6917cc890bc6",
        "user_id":"AEP00XXSM"
    },
	session_key: 'session_key previously obtained in get_sessions',
	journey_type: 'one_way',
	origin: 'AEP',
	destination: 'COR',
	departure_date: '2021-02-03',
	return_date: null, // if journey_type = 'round_trip' return_date must be completed
	adults: 1,
	minors: 0,
	infants: 0,
	cabin: 'economy', // not required
	promo: 'PROMO1' // not required
}
let headers = {
    'Content-Type': 'application/json',
    'accept': 'application/json', 
    'carrier': 'xx',
    'sec-fetch-site': 'same-origin',
    'sec-fetch-mode': 'cors',
    'referer': 'https://ecommerce-xx-stage.kiusys.net/searchflight/',
    'authority': 'ecommerce-xx-stage.kiusys.net',
    'authorization': 'Token session_key obtenido en get_sessions'
}
fetch('https://ecommerce-xx-stage.kiusys.net/searchflight/api/v1/action/', {
 	    method: 'POST',
 	    headers: headers,
        body: JSON.stringify(formData)
    }
).then(res => res.json())
.catch(error => console.error('Error:', error))
.then(
	response => customHandleResponseFunction(response)
)

Post action (manage booking)

This service is responsible for sending the data to search for a reservation, once the user has completed all the minimum required fields. The request must be made via POST AJAX and when obtaining the response, simply redirect to the following url according to the flow obtained, by get_flow service.

Params:

point_of_sale: At the moment, it has the "user" field, which must be the same as the carrier code (object)
record_locator: Reservation code, inserted by user. (string)
last_name_or_grp_name: Passenger lastname. (string)

Url:

https://ecommerce-xx-stage.kiusys.net/managebooking/api/v1/action/

Implementación:

 Click here to expand...
var formData = {
		point_of_sale: {
		user: 'XX',
	},
	record_locator: 'UZAZHI',
	last_name_or_grp_name: 'CARRILLO'
}
let headers = {
    'Content-Type': 'application/json',
    'accept': 'application/json', 
    'carrier': 'xx',
    'sec-fetch-site': 'same-origin',
    'sec-fetch-mode': 'cors',
    'referer': 'https://ecommerce-xx-stage.kiusys.net/booking/',
    'authority': 'ecommerce-xx-stage.kiusys.net',
    'authorization': 'Token session_key obtenido en get_sessions'
}
fetch('https://ecommerce-xx-stage.kiusys.net/managebooking/api/v1/action/', {
 	    method: 'POST',
 	    headers: headers,
        body: JSON.stringify(formData)
    }
).then(res => res.json())
.catch(error => console.error('Error:', error))
.then(
	response => customHandleResponseFunction(response)
)

Post action (Web checkin)

This service is responsible for sending the data to retrieve the reserervation to do checkin, once the user has completed all the minimum required fields. The request must be made via POST AJAX and when obtaining the response, simply redirect to the following url according to the flow obtained, by get_flow service.

Parámetros:

point_of_sale: Data obtained previously in get_configs service (object)
record_locator: Reservation code, inserted by user. (string)
last_name_or_grp_name: Passenger lastname. (string)

Url:

https://ecommerce-xx-stage.kiusys.net/retrievebooking/api/v1/action/

Implementación:

 Click here to expand...
var formData = {
	point_of_sale: {
		user: "XX",
        agent_preferred_language: "es-AR",
        kiu_device_id: "AEP00XXW04",
        agent_id: "AEP00XXSM",
        preferred_display_currency: "ARS",
        country: "AR"
	},
	record_locator: 'UZAZHI',
	last_name_or_grp_name: 'CARRILLO'
}
let headers = {
    'Content-Type': 'application/json',
    'accept': 'application/json', 
    'carrier': 'xx',
    'sec-fetch-site': 'same-origin',
    'sec-fetch-mode': 'cors',
    'referer': 'https://ecommerce-xx-stage.kiusys.net/booking/',
    'authority': 'ecommerce-xx-stage.kiusys.net',
    'authorization': 'Token session_key obtenido en get_sessions'
}
fetch('https://ecommerce-xx-stage.kiusys.net/retrievebooking/api/v1/action/', {
 	    method: 'POST',
 	    headers: headers,
        body: JSON.stringify(formData)
    }
).then(res => res.json())
.catch(error => console.error('Error:', error))
.then(
	response => customHandleResponseFunction(response)
)

Response (searchflight, manage my booking, web checkin):

 Click here to expand...

It is important to obtain a 200 status and that within response.response ['session-display'] we have the value of our session key mentioned above. In this scenario we know that we have everything ready to redirect to the next screen.

Manage booking and web checkin, you can return a 400, indicating that the reservation or the passenger does not exist. It is important to take this case into account, in order to display an error message to the user.

{
   "kiu_internals":{
      "duration":3.2041072845458984,
      "id_tracking":"backendsearchflight.29bad7c320a2_953a5c297e464e7191b869b658cfa32c"
   },
   "response":{
      "session-display":"https://ecommerce-xx-stage.kiusys.net/spa-session-display/show?app=ecommerce&session_key=fake-test-key.odfcPLsiwJY"
   }
}

Widget Build

The objective of this section is to take advantage of the content obtained in the available services, to create the corresponding search form, carry out the pertinent validations and finally be able to send information to the next screen of the corresponding flow.

Web assembly (searchflight).

To avoid attacks against the shopping service, used in the flightresults screen, a control was implemented through WebAssembly, where we generate a valid token that must be sent in the https://ecommerce-[carrier]-[env].kiusys.net/searchflight/api/v1/action/.. Since this will be validated in our backend by expiration date and data, in this sense, it is important to follow the following steps:


include wasm folder in your project:
Because the widget implemented by the carrier would have a different DNS than the one provided by Kiu, to generate the search screen, the client must include the wasm folder in its development, avoiding errors by CORS ORIGIN. In this way, you will be able to generate the webassembly token.
The wasm folder should be located so that the index where the widget is located can fetch the files.

Of the three files within the wasm folder, only the wasm.css file can be modified.

In order to serve the test.wasm file, it is essential to configure location and mimetypes on the configured server. For example, if we use nginx server, it is as shown in the following example:

 Click here to expand...
# path usado para resolver la carpeta wasm
location /wasm/ {
      alias /var/www/tests/custom_widget/wasm/test.wasm; # alias Ubicación de la carpeta
      add_header Access-Control-Allow-Origin *;
      add_header Access-Control-Request-Method GET;
}

types {
      text/css css;
      text/html html;
      text/plain txt;
      application/wasm wasm; # mimetype para test.wasm
      image/svg+xml svg svgz;
      image/gif gif;
      image/png png;
      image/jpeg jpeg jpg;
      image/webp webp;
      image/x-icon ico;
}
gzip on; # habilita servir el archivo como comprimido
gzip_types application/wasm; # especifica el mimetype del archivo a comprimir

The file test.wasm is only served using the mimetype application/wasm wasm;. Without this configuration, it cannot be resolved. Additionally, because it is a large file, it must be compressed. For this we use gzip;

Insert WASM_URL: This is required to be used within the js loaded later. Pay special attention that it ends with '/' and that the variable is injected into the window object. (The DNS must be that of the carrier)

<script type="text/javascript"> window.WASM_URL = "https://airline-webpage/wasm/"; </script>

Embed Polyfill: Makes compatibility with older version browsers possible.

<script crossorigin="anonymous" src="https://polyfill.io/v3/polyfill.min.js?features=blissfuljs%2Cdefault%2Ces2015%2Ces2016%2Ces2017%2Ces2018%2Ces5%2Ces6%2Ces7%2CBlob%2CArray.prototype.forEach"</script>

Insert validation for Microsoft IE: Internet Explorer is not supported, for this reason, it is important to warn the user that they must change the browser. For this reason, it is recommended to add the following tag, also being able to modify the alert for one of the client's preference.

<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
var ua = window.navigator.userAgent;
if ( ua.indexOf("MSIE ") > -1 || ua.indexOf("Trident/") > -1) {
alert('This website does not support your current version of your web browser')
}
});
</script>

Insert wasm.css file: The DNS must be that of the carrier.

<link rel="stylesheet" type="text/css" href="https://airline-webpage/wasm/wasm.css">

Insert wasm_load.js file: Very important tag, since it is the one that loads the WebAssembly file, responsible for generating the token. (The DNS must be that of the carrier).

<script type="text/javascript" src="https://airline-webpage/wasm/wasm_load.js"</script>

Once the scripts described above have been loaded, we can only generate the token in a single moment, after the user has completed the form, so we must generate the token when the user clicks on the "search" button. . Adding in some way the key wasm_token, to the object that will be sent by post to the backend.

We must make use of the validateForm() function (Remember that it can be invoked only once, if we want to reuse it, it is necessary to reload the screen). Assuming that our payload is inside a "formData" variable:

formData.wasm_token = validateForm(JSON.stringify(formData))

Later the post would be made towards… / action.
Note: Verify that the wasm_token is sent.

HTML

IMPORTANT NOTE

This is meant to be used an implementation guideline for developers; it is not meant to be used within the development.

This HTML should not be used as it is. It is not adapted to work on all browsers, devices, or their versions.

This widget needs to be adjusted and a certification process is required before going live where all parties must be involved (airline, website developer, Kiu)

What will be shown next is based on a simple development, using bootstrap, javascript and jquery.

In view of the fact that in this widget, we must add more than one form. A very simple way to solve it is by implementing tabs, such as those offered by boostraps. The idea is that when navigating between tabs, change the form and the necessary environment variables, in order to make a request to the corresponding backend.

In the following .zip file, you can get the home version, to implement a widget from scratch.

If you need to test it locally, you can install nodejs, and with following the readme steps, it starts. If you have an nginx server or if you prefer to test it within a VPS (for example), you can take the widgetBooking.html file and use it directly.

Test link:

Through this, it can be tested directly in the DNS of kiusys.com. You can use dev, qa, or stage. To do this, simply add via queryparams, the env key with the value you prefer, as well as change the carrier.

https://apps-dev.kiusys.com/tests/custom_widget/booking.html?env=stage&carrier=xx

Required validations

Beyond the fact that the E-COMMERCE application has its own validations in the backend, we must make certain recommendations to the developers, about some validations to be carried out on the client side (Front-end), in order to avoid inconsistent search errors and generate a more efficient process.

Reservation code - Surname:

It must be ensured that the reservation exists, and the surname is exactly the same as the one used in the reservation. Important, validate the number of characters, accents, or the letter "Ñ", for example.

Origin destiny:

The Get_config response returns the list of search-enabled routes configured in the backoffice. Based on this information, the developer can filter and validate the related options and thus optimize the search results. This filter is performed for example in the javascript function filterRoute(), This must be used in an onkeyup event

Dates:

The supported date format is YYYY-MM-DD (example: 2020-04-06). The developer can display the form in different formats according to the area in which it is located, but should consider doing the transformation to respect the supported format and thus avoid E-COMMERCE returning a format error.

Departure date:

The departure date must be considered from the current date to the future and not beyond 330 days in the future. The industry standard application supports availability searches up to 330 days in the future from the current date. We specify this in the Get_dates section, and we use it in the javascript manageDates() function.

Return date:

The return date must be validated against the departure date. This cannot be earlier than the date set as departure and must not be more than 330 days in the future.

Adult passenger:

We recommend that the default value be 1. 0 is not accepted, to avoid the request via the web sales channel of unaccompanied minors that carries with it an internal airline process for authorization. Likewise, these configurations are included in the response to Get_configs, passenger_types field.

Infant passengers:

By industry logic, an adult must first exist before adding an infant. If there is more than one Infant passenger, there must be the same number of adults since only one infant passenger and only one can be associated with an adult passenger.

Sending data to E-COMMERCE:

The Post action service is used to send search data via AJAX, it should not be used in a form submit event, since it does not support redirects. The correct use of this service is: once the response with status 200 is obtained, we must redirect to the next screen E-COMMERCE, This information is provided by the Get flow service, used first in the integration flow , whose information must be stored in the client.

To do the redirection, based on the flow, we can make use of the handlePostResponse() function, or directly, taking into account the general url, the session data obtained previously and the Post Action response. Starting from the fact that the first screen of any of the flows is the one we are in, and it would be position 0 of the list, we can simply obtain the next one, that is, position 1, and from this, obtain the corresponding path to make the re -dicection. Under that context, one option would be to use something like the following:

let nextUrl = session.flow[1].url
window.location.href = `${mainUrl}${nextUrl}?session_id=${session.session_key}`

I hope the exposed information is of your total utility. Good luck!

  • No labels