Loopon Public API

The Loopon Public API enables 3rd party and hotel-specific integrations to the Loopon Guest Messaging & Feedback platform.
https://api.loopon.com/public
API Introduction

The Loopon API is a RESTful JSON API accessible through HTTPS, using OAuth 2 for authorisation with the Client Credentials grant type for authentication. If you are familiar with this type of APIs you should hopefully not find a lot of surprises here.

If you need any help at all, please write to support@loopon.com or chat with us at https://www.loopon.com/

If nothing else is explicitly mentioned, all data formats are as follows:

Type Format Example Documentation
Content type JSON https://en.wikipedia.org/wiki/JSON
Text encoding UTF-8 https://en.wikipedia.org/wiki/UTF-8
Date (& Time) ISO 8601 in Zulu time 2017-11-20T01:42:41Z https://en.wikipedia.org/wiki/ISO_8601
Language ISO 639-1 sv for Swedish, nb for Norwegian Bokmål https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes

Notes on request parameters / body parameters:

Through-out the Loopon API, the following convention is followed:

  • Parameters which affect the behaviour of a query, such as the difference between listing all units or searching for a specific unit, are given as Request Parameters (i.e. in the query uri)
  • Data provided to POST/PUT requests that will update contents in our database, such as the data about a specific stay when registering a guest stay, are provided as Body Parameters in JSON format
Authentication

Loopon uses the industry standard OAuth 2 for authorization of API requests. In the naming convention of OAuth 2, the Loopon API acts as both a Resource Server and Authorization Server. For authentication we currently only support the Client Credentials Grant Type.

The relevant endpoints you need to be aware of are:

Endpoint URL
Token https://api.loopon.com/oauth2/token
API Base https://api.loopon.com/public

The possible scopes your API client might have access to are:

Scope Explanation
basic Basic access to API for a given unit, required to use API at all.
read_scores Possibility to read all/private scores of a unit.
read_answers Read detailed answers through the ‘get answer documents’ endpoint.
manage_stays Ability to register new guest stays and trigger guest communication.
chat_sessions Manage real-time chat session, registering callbacks and push messages to guests.
read_public_reviews Possibility to read public reviews for a unit, and units registered in competitive sets for unit.

An example how to receive an access token would be:

$ curl -X POST -d "grant_type=client_credentials" -d "client_id=<CLIENT_ID>" --data-urlencode "client_secret=<SHARED_SECRET>" -d "scope=basic" "https://api.loopon.com/oauth2/token"

Which should return something like:

{"token_type":"Bearer","expires_in":3600,"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImEzMGQ0ZGM4OGY4MDIxY2Q5YWQ1OWE2MTVjZTk5MzM4MWViYmJmMWI3YjUzMjhiMjdhN2E1MTUzM2Y0NTQwOThkOWVkOGNhNjQzYjBkMzQzIn0.eyJhdWQiOiJsb29wb24tZGVtbyIsImp0aSI6ImEzMGQ0ZGM4OGY4MDIxY2Q5YWQ1OWE2MTVjZTk5MzM4MWViYmJmMWI3YjUzMjhiMjdhN2E1MTUzM2Y0NTQwOThkOWVkOGNhNjQzYjBkMzQzIiwiaWF0IjoxNTExMDEzODg2LCJuYmYiOjE1MTEwMTM4ODYsImV4cCI6MTUxMTAxNzQ4Niwic3ViIjoiIiwic2NvcGVzIjpbImJhc2ljIl19.kE9brbD3CQFYBzgGzicMNm3W0O5B61Ku7o1P35_LjyCdM_etGlkBdrXwsbqO7qYAeh4fYXcwp1Am9aqxTCSvLV8HU597BtPYxLneYdK3j33s8HGQjpny66JbEcb9rN0evr9_tSR_T9gBPqfZ1Fmb4a3IleOPv1X2nI1btlwgQEU"}

In order to use this access token, include a HTTP Header in the format Authorization: Bearer ACCESS_TOKEN. For example:

curl -X GET -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImEzMGQ0ZGM4OGY4MDIxY2Q5YWQ1OWE2MTVjZTk5MzM4MWViYmJmMWI3YjUzMjhiMjdhN2E1MTUzM2Y0NTQwOThkOWVkOGNhNjQzYjBkMzQzIn0.eyJhdWQiOiJsb29wb24tZGVtbyIsImp0aSI6ImEzMGQ0ZGM4OGY4MDIxY2Q5YWQ1OWE2MTVjZTk5MzM4MWViYmJmMWI3YjUzMjhiMjdhN2E1MTUzM2Y0NTQwOThkOWVkOGNhNjQzYjBkMzQzIiwiaWF0IjoxNTExMDEzODg2LCJuYmYiOjE1MTEwMTM4ODYsImV4cCI6MTUxMTAxNzQ4Niwic3ViIjoiIiwic2NvcGVzIjpbImJhc2ljIl19.kE9brbD3CQFYBzgGzicMNm3W0O5B61Ku7o1P35_LjyCdM_etGlkBdrXwsbqO7qYAeh4fYXcwp1Am9aqxTCSvLV8HU597BtPYxLneYdK3j33s8HGQjpny66JbEcb9rN0evr9_tSR_T9gBPqfZ1Fmb4a3IleOPv1X2nI1btlwgQEU" "https://api.loopon.com/public/units" 

Which would return all units you are authorized to access:

[{"unitId":1203,"propertyCode":"","name":"Sea Hotels"},{"unitId":1282,"propertyCode":null,"name":"Sea Hotel Gulf of Bothnia"},{"unitId":1204,"propertyCode":"","name":"Sea Hotel Kattegat"},{"unitId":1601,"propertyCode":"","name":"Kattegat Gourmet Restaurant"},{"unitId":1281,"propertyCode":null,"name":"Sea Hotel Skagerrak"}]

Please contact us at support@loopon.com to receive your client id & client secret.

cURL

Obtain access token using client credential grant

$ curl -X POST \
  -d "grant_type=client_credentials" \
  -d "client_id=<CLIENT_ID>" \
  --data-urlencode "client_secret=<SHARED_SECRET>" \
  -d "scope=basic" \
  "https://api.loopon.com/oauth2/token"
  
{
    "token_type":"Bearer",
    "expires_in":3600,
    "access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImEzMGQ0ZGM4OGY4MDIxY2Q5YWQ1OWE2MTVjZTk5MzM4MWViYmJmMWI3YjUzMjhiMjdhN2E1MTUzM2Y0NTQwOThkOWVkOGNhNjQzYjBkMzQzIn0.eyJhdWQiOiJsb29wb24tZGVtbyIsImp0aSI6ImEzMGQ0ZGM4OGY4MDIxY2Q5YWQ1OWE2MTVjZTk5MzM4MWViYmJmMWI3YjUzMjhiMjdhN2E1MTUzM2Y0NTQwOThkOWVkOGNhNjQzYjBkMzQzIiwiaWF0IjoxNTExMDEzODg2LCJuYmYiOjE1MTEwMTM4ODYsImV4cCI6MTUxMTAxNzQ4Niwic3ViIjoiIiwic2NvcGVzIjpbImJhc2ljIl19.kE9brbD3CQFYBzgGzicMNm3W0O5B61Ku7o1P35_LjyCdM_etGlkBdrXwsbqO7qYAeh4fYXcwp1Am9aqxTCSvLV8HU597BtPYxLneYdK3j33s8HGQjpny66JbEcb9rN0evr9_tSR_T9gBPqfZ1Fmb4a3IleOPv1X2nI1btlwgQEU"
}
Common HTTP Headers

The following HTTP headers are required by or available for all requests:

VERSION
integer optional
Applied to all operations

Specifies which version of the API your application expects to talk to. If the header is not provided at all, it will be assumed that you are talking to the latest stable version of the API. Versions are provided as integers. While we strive to maintain backwards compatibility, we recommend that you always specify an explicit version number that your application talks to.

Min: 1
Max: 1
Authorization
string required
Applied to all operations

Access Token as provided by the call to https://api.loopon.com/oauth2/token

Pattern: Bearer ACCESS_TOKEN
ErrorMessage

Generic object returned whenever there is an error (non-2XX http status code)

Object
error
integer

Copy of the HTTP status code

Example:
message
string

Human readable explanation of the error

Units

Within Loopon we call a hotel, restaurant or cruise ship a Unit. A single Unit might contain multiple Evaluations but usually there is a single Evaluation which describes the questions asked to the guest at different stages of the guest journey.

GET /units
GET /units/{unitId}
List Units
GET /units

Authentication

API Authorization
basic

List all available units that your user has access to.

Request parameters

propertyCode
string optional

Search for unit with this specific property code, if specified.

Responses

200 OK
Body
Array of Unit
List Units
Search for Unit

List all units

$ curl -X GET -H "Authorization: Bearer <token>" "https://api.loopon.com/public/units"

[
    {
        "unitId":1203,
        "propertyCode":"",
        "name":"Sea Hotels"
    },
    {
        "unitId":1282,
        "propertyCode":"X01",
        "name":"Sea Hotel Gulf of Bothnia"
    },
    {
        "unitId":1204,
        "propertyCode":"X02",
        "name":"Sea Hotel Kattegat"
    },
    {
        "unitId":1601,
        "propertyCode":"",
        "name":"Kattegat Gourmet Restaurant"
    },
    {
        "unitId":1281,
        "propertyCode":"X03",
        "name":"Sea Hotel Skagerrak"
    }
]

Search for a unit based on property code

$ curl -X GET -H "Authorization: Bearer <token>" "https://api.loopon.com/public/units?propertyCode=X02"

[
    {
        "unitId":1204,
        "propertyCode":"X02",
        "name":"Sea Hotel Kattegat"
    }
]
Get Unit
GET /units/{unitId}

Authentication

API Authorization
basic

Retrieve an explicitly identified unit.

Path variables

unitId
integer required

Unique id of the unit you want to retrieve

Responses

200 OK
Body
403 Forbidden

You are not allowed to access the requested unit

Unit

Description of a single hotel/restaurant/cruise ship.

Object
unitId
integer

Unique identifier for this unit.

propertyCode
string nullable

Property code of this unit, as identified by the chain of which it is a member. Requires basic scope for unit in order to be included (i.e. null for Unit objects provided in competitive sets)

name
string

Human readable name of this unit.

evaluationId
integer nullable

Unique identifier for the default evaluation active on this unit.

Survey

The API endpoints relating to Survey refer to all data and anwers collected by Loopon directly from the guest. This is in contrast to the Online Reputation endpoints that relate to information about the hotel collected online from public third party source.

GET /units/{unitId}/evaluations
Evaluation

Evaluation of a specified unit.

Object
id
number

Unique identifier of the evaluation.

description
string

Name/description of the evaluation.

Get Unit Evaluations
GET /units/{unitId}/evaluations

Authentication

API Authorization
basic

Retrieve all evaluations of the specified unit.

Path variables

unitId
string required

Unique id of the unit for which you want to retrieve its evaluations.

Responses

200 OK
Body
Array of Evaluation
403 Forbidden

You are not allowed to access the requested unit

Simple Survey Operations

The simple survey operations consist of a few simple API calls that will most often be enough if your intention is to just collect data to a simple dashboard visualising your Loopon Results.

If you have more complex needs, and want to integrate Loopon with your CRM or retrieve complete data to your data warehouse including detailed information per guest, you should look at the Complete Survey Operations section.

GET /units/{unitId}/evaluation/scores/{semanticId}
GET /units/{unitId}/evaluation/scores/nps
GET /units/{unitId}/evaluations/{evaluationId}/scores/{semanticId}
ScoreResult

Result of retrieving the score of a specific unit.

Object
title
string

Title of the question.

score
number

Score ready for presentation, in the same scale as normal reports in Loopon.

normalizedScore
number

Score on scale from 0 to 1.

answerCount
integer

How many answers from guests were used to calculate the score.

promoterCount
integer nullable

Number of promoters. This property is only returned when retrieving the NPS score.

passiveCount
integer nullable

Number of passives. This property is only returned when retrieving the NPS score.

detractorCount
integer nullable

Number of detractors. This property is only returned when retrieving the NPS score.

Get Unit Score
GET /units/{unitId}/evaluation/scores/{semanticId}

Authentication

API Authorization
read_scores

Retrieve the score of the specified unit corresponding to the question with the specified semantic id within an optional date range.

If the unit id corresponds to a chain, the returned score is the aggregated score of all the units in the chain.

If no date range is specified, the score within the latest 30 days is returned. Dates refer to the checkout date of the guest.

The score is calculated using only results from guests who have answered the survey sent by e-mail. Specifically, answers provided through iPad-terminals, public web links, or online review sites are ignored and not included in the result.

Path variables

unitId
integer required

Unique id of the unit for which you want to retrieve the score.

semanticId
integer required

Semantic id of the question for which you want to retrieve the score.

Request parameters

startDate
string date optional

Date from which to calculate the score. Defaults to the current date minus 30 days if the parameter is not specified

endDate
string date optional

Date until which to calculate the score. Defaults to the current date if the parameter is not specified.

source
string optional

Comma-separated list of all sources you want to retrieve data from.

Enumeration:
email

Include data from email (or sms, or other source where Loopon delivered the survey)

web

Include data provided through public web links or QR codes

paper

Include data manually registered inside Loopon

reputation

Include data provided on public review sites

all

Include all data from above

Default:
email
reputationSource
string optional

Comma-separated list of reputation sources to include. If a reputation source is provided the source parameter will be set to source=reputation. By default all reputation sources will be selected if the source parameter includes reputation.

Enumeration:
agoda
airbnb
booking_com
camping2be
cheaptickets
couverts
ctrip
ebookers
eet_nu
expedia
facebook_pages
getyourguide
goibibo
google
holiday_check
holiday_iq
hostelworld
hoteliers_com
hotels_com
hotels_de
hotels_nl
hotel_specials
hrs
iens_nl
lastminute
makemytrip
meetingroom_review
orbitz
priceline
rooms_for_africa
takeaway_com
thefork
travelocity
traveloka
trip_advisor
vakantiereiswijzer
weekendjeweg_nl
weekend_desk
wotif
yelp
zomato
zoover

Responses

200 OK
403 Forbidden

You are not allowed to access the requested unit

400 Bad Request

The specified date range is invalid.

400 Bad Request

The specified semantic id is invalid.

Example 1
Example 2

Retrieve the NPS of the latest 30 days from all hotels in the ‘Sea Hotels’ chain

$ curl -X GET -H "Authorization: Bearer <token>" "https://api.loopon.com/public/units/1203/evaluation/scores/0"

{
    "title": "How likely is it that you would recommend our hotel?",
    "score": 65,
    "normalizedScore": 0.8,
    "answerCount": 100,
    "promoterCount": 70,
    "passiveCount": 25,
    "detractorCount": 5
}

Retrieve the NPS of Sea Hotel Kattegat for 2017

$ curl -X GET -H "Authorization: Bearer <token>" "https://api.loopon.com/public/units/1204/evaluation/scores/0?startDate=2017-01-01&endDate=2017-12-31"

{
    "title": "How likely is it that you would recommend our hotel?",
    "score": 65,
    "normalizedScore": 0.8,
    "answerCount": 1000,
    "promoterCount": 700,
    "passiveCount": 205,
    "detractorCount": 50
}
Get Unit NPS score
GET /units/{unitId}/evaluation/scores/nps

Authentication

API Authorization
read_scores

Retrieve the NPS score of the specified unit within an optional date range.

If the unit id corresponds to a chain, the returned score is the aggregated score of all the units in the chain.

If no date range is specified, the score within the latest 30 days is returned. Dates refer to the checkout date of the guest.

The score is calculated using only results from guests who have answered the survey sent by e-mail. Specifically, answers provided through iPad-terminals, public web links, or online review sites are ignored and not included in the result.

Path variables

unitId
integer required

Unique id of the unit for which you want to retrieve the NPS score

Request parameters

startDate
string date optional

Date from which to calculate the NPS score. Defaults to the current date minus 30 days if the parameter is not specified

endDate
string date optional

Date until which to calculate the NPS score. Defaults to the current date if the parameter is not specified.

source
string optional

Comma-separated list of all sources you want to retrieve data from.

Enumeration:
email

Include data from email (or sms, or other source where Loopon delivered the survey)

web

Include data provided through public web links or QR codes

paper

Include data manually registered inside Loopon

reputation

Include data provided on public review sites

all

Include all data from above

Default:
email
reputationSource
string optional

Comma-separated list of reputation sources to include. If a reputation source is provided the source parameter will be set to source=reputation. By default all reputation sources will be selected if the source parameter includes reputation.

Enumeration:
agoda
airbnb
booking_com
camping2be
cheaptickets
couverts
ctrip
ebookers
eet_nu
expedia
facebook_pages
getyourguide
goibibo
google
holiday_check
holiday_iq
hostelworld
hoteliers_com
hotels_com
hotels_de
hotels_nl
hotel_specials
hrs
iens_nl
lastminute
makemytrip
meetingroom_review
orbitz
priceline
rooms_for_africa
takeaway_com
thefork
travelocity
traveloka
trip_advisor
vakantiereiswijzer
weekendjeweg_nl
weekend_desk
wotif
yelp
zomato
zoover

Responses

200 OK
403 Forbidden

You are not allowed to access the requested unit

400 Bad Request

The specified date range is invalid.

Example 1
Example 2

Retrieve the NPS of the latest 30 days from all hotels in the ‘Sea Hotels’ chain

$ curl -X GET -H "Authorization: Bearer <token>" "https://api.loopon.com/public/units/1203/evaluation/scores/nps"

{
    "title": "How likely is it that you would recommend our hotel?",
    "score": 65,
    "normalizedScore": 0.8,
    "answerCount": 100,
    "promoterCount": 70,
    "passiveCount": 25,
    "detractorCount": 5
}

Retrieve the NPS of Sea Hotel Kattegat for 2017

$ curl -X GET -H "Authorization: Bearer <token>" "https://api.loopon.com/public/units/1204/evaluation/scores/nps?startDate=2017-01-01&endDate=2017-12-31"

{
    "title": "How likely is it that you would recommend our hotel?",
    "score": 65,
    "normalizedScore": 0.8,
    "answerCount": 1000,
    "promoterCount": 700,
    "passiveCount": 205,
    "detractorCount": 50
}
Get Score for Specific Evaluation
GET /units/{unitId}/evaluations/{evaluationId}/scores/{semanticId}

Authentication

API Authorization
read_scores

Retrieve the score of the specified unit corresponding to the question with the specified semantic id in the specified evaluation within an optional date range.

If the unit id corresponds to a chain, the returned score is the aggregated score of all the units with compatible evaluations in the chain.

If no date range is specified, the score within the latest 30 days is returned. Dates refer to the checkout date of the guest.

The score is calculated using only results from guests who have answered the survey sent by e-mail. Specifically, answers provided through iPad-terminals, public web links, or online review sites are ignored and not included in the result.

Path variables

unitId
integer required

Unique id of the unit for which you want to retrieve the score.

evaluationId
integer required

Unique id of the evaluation for which you want to retrieve the score.

semanticId
integer required

Semantic id of the question for which you want to retrieve the score.

Request parameters

startDate
string date optional

Date from which to calculate the score. Defaults to the current date minus 30 days if the parameter is not specified

endDate
string date optional

Date until which to calculate the score. Defaults to the current date if the parameter is not specified.

source
string optional

Comma-separated list of all sources you want to retrieve data from.

Enumeration:
email

Include data from email (or sms, or other source where Loopon delivered the survey)

web

Include data provided through public web links or QR codes

paper

Include data manually registered inside Loopon

reputation

Include data provided on public review sites

all

Include all data from above

Default:
email
reputationSource
string optional

Comma-separated list of reputation sources to include. If a reputation source is provided the source parameter will be set to source=reputation. By default all reputation sources will be selected if the source parameter includes reputation.

Enumeration:
agoda
airbnb
booking_com
camping2be
cheaptickets
couverts
ctrip
ebookers
eet_nu
expedia
facebook_pages
getyourguide
goibibo
google
holiday_check
holiday_iq
hostelworld
hoteliers_com
hotels_com
hotels_de
hotels_nl
hotel_specials
hrs
iens_nl
lastminute
makemytrip
meetingroom_review
orbitz
priceline
rooms_for_africa
takeaway_com
thefork
travelocity
traveloka
trip_advisor
vakantiereiswijzer
weekendjeweg_nl
weekend_desk
wotif
yelp
zomato
zoover
Complete Feedback Operations

If you are trying to retrieve some basic data (such as NPS score for your property) you most likely want to look at the simplified Simple Survey Operations.

What you find here instead is complete access to all guest data collected by Loopon, including old versions of your survey(s) - at the cost of quite some complexity.

GET /units/{unitId}/evaluations/{evaluationId}/answerDocuments
GET /units/{unitId}/evaluations/{evaluationId}/answerDocuments/{answerDocumentId}
GET /units/{unitId}/evaluations/{evaluationId}/questionSet/{questionSetId}
GET /units/{unitId}/evaluations/{evaluationId}/question/{questionId}
Feedback Introduction

At its core, Loopon considers all types of feedback - irregardless of source (e-mail survey, QR-code feedback, 3rd party review site, …) as the same type of data; and this API refers to all these types of guest feedback.

When a guest provides feedback, the entire set of answers are saved in something called an AnswerDocument. Each individual answer to a specific question is exposed through the API as an Answer object.

In order to know what question an answer relates to, there’s the Question object. If the question is of a multiple choice type (radio or checkbox), it will also contain a list of QuestionOption.

So far everything is hopefully completely clear. One detail that complicates the above situation a little however, is that surveys are no static objects - you as a customer might often be asking us to do a change, or introduce changes yourself. You might add questions, remove questions, reformulate questions, etc.

In relation to the above an additional complication is that the AnswerDocument will also contain meta-data provided by your PMS; such as room number, rate plan, checkout date and other details. What this means in practice is that answers to a single AnswerDocument might be provided at different times - meta-data will be provided when we receive data from your PMS, the guest’s actual answers will be provided when the guest answers the survey. Finally, in certain circumstances, a guest’s answers might be modified afterwards if there has been some misunderstanding or the guest changes their mind after you have sorted out an issue the guest might have complained about.

In order to cope with all the above requirements, Loopon keeps track of something called a QuestionSet. This is a container that keeps track of which Questions were included in the survey at a given point in time.

Simply speaking, every time you make a modification to your survey - even if you just change a single question, a completely new QuestionSet is created which defines the complete contents of the survey at that point in time. When you are retreiving Answer objects they will specify which Question they relate to, which in turn is contained by a given QuestionSet. However, since (as explained above) a single AnswerDocument might contain answers provided at different points in time - also a single AnswerDocument can refer to multiple QuestionSets. While this is uncommon, it’s something your implementation must take into consideration.

Finally, how you retrieve your feedback. Within Loopon a single property (a hotel, cruise ship, restaurant, …) is called a Unit. Each Unit might have one or more Evaluations which is the container of the QuestionSets and AnswerDocuments.

There is a single straight-forward way to receive new answers from Loopon, which is to call the Get Answer Objects endpoint. This will automatically expand all relevant information you need (all included QuestionSets, Questions, QuestionOptions, AnswerDocument and Answers).

Note that for all API endpoints documented below as /units/{unitId}/evaluations/{evaluationId}/ you can also use the short-hand version /units/{unitId}/evaluation/ if you only want to operate on the default evaluation rather than explicitly stating which one you want to access. For the majority of Loopon API use cases, this is probably the version you want to use to avoid having to care about the evaluation ids.

Get Answer Documents
GET /units/{unitId}/evaluations/{evaluationId}/answerDocuments

Authentication

API Authorization
read_answers
basic

This method retrieves all the answerDocuments that match the given parameters. By default if no parameters are provided we will return all new answers we have received in the last 24 hours.

Note that we will apply an AND rule between all the provided parameters, so for example:

GET /units/1/evaluation/1/answerDocuments?updatedMin=2019-01-01T00:00:00Z&checkoutMin=2019-05-01&checkoutMax=2019-05-02

would return all answers that we have received since 2019-01-01, but only if the checkout date is in the interval 2019-05-01 - 2019-05-02.

Use List Units to find the units you can access as well as their default evaluation id.

If the unitId and evaluationId refer to a chain, you will receive answer documents for all the compatible evaluations of the chain.

Note that there is no paging implemented for this call. If you are seeing “timeout” results, rather perform paging on your side by providing a narrower restriction of updatedMin and updatedMax.

Path variables

unitId
integer required

Identification of the property for which you want to retrieve answers

evaluationId
integer required

Identification of the evalution for which you want to retrieve answers

Request parameters

checkoutMin
string optional

Earliest date when guest is allowed to have checked out to have their feedback included in the results.

Example:
2019-05-01
checkoutMax
string optional

Latest date when guest is allowed to have checked out to have their feedback included in the results

updatedMin
string optional

Only include new answers received since the given timestamp

Default:
NOW() - 24 hours
Example:
2019-05-08T12:00:00Z
updatedMax
string optional

Only include new answers received before the given timestamp

Example:
2019-05-09T12:00:00Z
source
string optional

Comma-separated list of all sources you want to retrieve data from.

Enumeration:
email

Include data from email (or sms, or other source where Loopon delivered the survey)

web

Include data provided through public web links or QR codes

paper

Include data manually registered inside Loopon

reputation

Include data provided on public review sites

all

Include all data from above

Default:
email
reputationSource
string optional

Comma-separated list of reputation sources to include. If a reputation source is provided the source parameter will be set to source=reputation. By default all reputation sources will be selected if the source parameter includes reputation.

Enumeration:
agoda
airbnb
booking_com
camping2be
cheaptickets
couverts
ctrip
ebookers
eet_nu
expedia
facebook_pages
getyourguide
goibibo
google
holiday_check
holiday_iq
hostelworld
hoteliers_com
hotels_com
hotels_de
hotels_nl
hotel_specials
hrs
iens_nl
lastminute
makemytrip
meetingroom_review
orbitz
priceline
rooms_for_africa
takeaway_com
thefork
travelocity
traveloka
trip_advisor
vakantiereiswijzer
weekendjeweg_nl
weekend_desk
wotif
yelp
zomato
zoover

Responses

200 OK
Body
Object
questionSets
Array of QuestionSet

All question sets referred to by answers included in the results

answerDocuments
Array of AnswerDocument
Get Answer Document
GET /units/{unitId}/evaluations/{evaluationId}/answerDocuments/{answerDocumentId}

Authentication

API Authorization

Retrieve a specific answer document as identified by the given id

Path variables

unitId
integer required

Identification of the property for which you want to retrieve answers

evaluationId
integer required

Identification of the evalution for which you want to retrieve answers

answerDocumentId
integer required

Unique id of the specific answer document you want to retrieve

Responses

200 OK
Get Question Set
GET /units/{unitId}/evaluations/{evaluationId}/questionSet/{questionSetId}

Authentication

API Authorization

Retrieve question set identifier by the unique id

Path variables

unitId
integer required
evaluationId
integer required
questionSetId
integer required
Get Question
GET /units/{unitId}/evaluations/{evaluationId}/question/{questionId}

Authentication

API Authorization
basic

Retrieve the definition of a question identified by a unique id

Path variables

unitId
string required

The unique id of the unit from which you want to retrieve a question

evaluationId
string required

The unique id of the evaluation from which you want to retrieve a question

questionId
string required

The unique id of the question you want to retrieve

Responses

200 OK
Body
QuestionSet

A QuestionSet describes all the questions that were included in your survey at a specific point in time.

Object
questionSetId
integer

Unique id for this particular set of questions

questionSetNumber
integer

Serial number for this question set for the evaluation that owns this question set

createdTimestamp
string

Timestamp when this particular question set was created

deprecatedTimestamp
string nullable

Timestamp when this particular question set was superseded by another question set

sections
Array of QuestionSection

Array of sections of questions contained by this question set

QuestionSection

Questions in QuestionSets are grouped within multiple “sections”. For example a typical case could be:

Section: To what extent do you agree to the following statements? Question 1: The reception staff did a good job Question 2: The breakfast gave me a good start of the day

Note however that it’s also possible to have sections without a title, so do not depend on it in your implementation.

Object
questionSectionId
integer

Unique identifier of this section

questionSectionNumber
integer

Serial number of this section, within the question set

questionSetId
integer

Unique id of the QuestionSet which contains this section

title
string nullable

Title of the section

questions
Array of Question

Array of questions contained within this section

Question

Description of a specific question within a question set. Please note as per the explanation in Feedback Introduction that every change to a survey will result in a completely new QuestionSet.

This implies that when retreiving answers through Get Answer Documents you might get multiple guests who have answered for example the question “The breakfast gave me a good start of the day” but their answers refer to different questionIds even though conceptually it’s the same question.

One way to deal with this on your side, is to look at the semanticId field in the Question object. This is an id that will remain stable between different instances of the same question, as it refers to “the meaning” of the question.

Object
questionId
integer

Unique identifier of this specific question

questionSectionId
integer

Unique id of the QuestionSection which contains this question

questionSetId
integer

Unique id of the QuestionSet that contains this question

questionNumber
integer

Local id/serial number of the question within the QuestionSet

title
string

Title of the question as shown to the guest in the base language of the survey

semanticId
integer nullable

Id that defines the “meaning” of the question, can be used to map results between different question sets.

For example:

0 = “How likely is it that you would recommend … to your friends or colleagues?”

1004 = “I am satisfied with the restaurant”

departmentCode
string nullable

Code (provided by you) which associates this question to a specific department

resourceCode
string nullable

Code (provided by you) which associates this question to a specific resource, such as a specific room type, upsell offer or activity/service

facilityCode
string nullable

Identifier which associates this question with a specific facility type

Enumeration:
restaurant
spa
bar
breakfast
gym
evening_meal
conference_department
reception
barception
wellness
selfservice_check_in_out
type
string

Defines the type of question

Enumeration:
text

Free text field

radio

Multiple choice (where only a single of the options can be picked)

checkbox

Multiple choice (where zero or more options can be picked)

real

Answer will be a decimal number

questionOptions
Array of QuestionOption nullable

Array of available options if this question is a multiple choice (radio or checkbox) question

QuestionOption

The QuestionOption object specifies a single answer option to either a multiple choice question (radio) or a checkbox selection.

Object
optionId
integer

Unique id of this answer option, as referred by Answer.answerOption

optionNumber
integer

Serial number of this option within the Question

title
string

Title of this option as shown to the guest in the base language of the survey

score
number nullable

Normalised score in range [0, 1] if this answer option should count as a rating

nps
string nullable

NPS segmentat if this answer option relates to “The Ultimate Question”

Enumeration:
promoter
passive
detractor
AnswerDocument

An AnswerDocument represents a single complete survey answer from a specific guest relating to a specific stay at a specific property.

Object
answerDocumentId
integer read-only

Unique id that identifies this specific answer document

unitId
integer read-only

Unique id of the unit this feedback has been provided for

evaluationId
integer read-only

Unique id of the evaluation this feedback has been provided for

propertyCode
string nullable read-only

Property code for the unit this feedback has been provided for. (If you have provided us with your own internal property code(s))

dataProtection
string

The guest’s choice on how long you are allowed to keep personally identifiable information attached to the survey answer

Enumeration:
gdpr_anonymous

The guest has chosen to respond anonymously

gdpr_30_days

The guest has granted permission to save personally identifiable information for 30 days

gdpr_forever

The guest has granted permission to save personally identifiable information until further notice

status
string
Enumeration:
active

Survey has been created but not answered yet

completed

Survey has been answered and submitted

bounced

Survey was delivered by email, but the email bounced so the recipient will not have a chance to respond to it

opened

Survey link has been clicked in mail/sms but no answers submitted

restricted

Survey has been created and a request to deliver it was made, but Loopon decided to not send it out due to internal anti-spam measures

name
string nullable

Name of the guest

email
string nullable

e-mail address of the guest

reservationNumber
string nullable

Reservation number for the stay this feedback relates to

loyaltyNumber
string nullable

Membership id in loyalty program of the guest

source
string

Source from where this feedback was obtained

Enumeration:
email

Feedback obtained from post-stay e-mail/sms survey

prestay

Feedback obtained from pre-stay e-mail/sms survey

instay

Feedback obtained from in-stay e-mail/sms survey

nextstay

Feedback obtained from next-stay e-mail/sms survey

web

Feedback obtained from public web or QR-code survey

paper

Feedback manually registered from paper survey

reputation

Online review retrieved from 3rd party source

reputationSource
string nullable read-only

If source=reputation this field will specify which 3rd party site the review was retrieved from. The examples show a few available options, but do note that the list of available sources keep expanding so you should not add a constraint on your side to what possible values are for this field.

Examples:
trip_advisorbooking_comgoogle
checkinDate
string date nullable

Date when the guest checked in to the property, in the local time zone of the property

Example:
2019-05-05
checkoutDate
string date

Date when the guest checked out from the property, in the local time zone of the property

Example:
2019-05-06
sentTimestamp
string date-time

Timestamp when the survey was delievered to the guest

Example:
2019-05-07T07:30:00Z
completionRate
number read-only

Defines the share of questions (in range [0.00, 1.00]) the guest has responded to, out of the questions that were visible to the guest.

Min: 0
Max: 1
answers
Array of Answer

Array of answers & meta data

updatedTimestamp
string date-time

Timestamp when an answer was last updated in this answer document.

Example:
2019-05-07T09:25:00Z
Answer

An Answer object specifies a single answer to a single question (or a meta data field).

Only one of answerOption, answerOptions, answerText will be non-null for a single Answer.

Object
answerId
integer read-only

Unique identifier of this particular answer

question

The question to which this is an answer

answerTimestamp
string read-only

Timestamp when this answer was received

Example:
2019-05-07T12:00:00Z
answerOption
QuestionOption nullable

If the answer relates to a multiple choice question, this field provides the selected QuestionOption

answerOptions
Array of QuestionOption nullable

If the answer related to a checkbox question, this field provides an array of all selected QuestionOptions (or an empty array if nothing was checked)

answerText
string nullable

If the answer relates to a free text field, this field provides the actual answer given

answerScore
number nullable

Score in range [0, 1] if this answer represents a score

Min: 0
Max: 1
Online Reputation

The API endpoints relating to Online Reputation to information about the hotel collected online from public third party source, this is in contrast to the Survey endpoints that refer to all data and anwers collected by Loopon directly from the guest.

GET /units/{unitId}/review-questions
GET /units/{unitId}/reviews
GET /units/{unitId}/reputation
Get Review Questions
GET /units/{unitId}/review-questions

Authentication

API Authorization
basic

Retrieves the list of possible ReviewQuestions for which a Review can have ReviewRatings.

Path variables

unitId
integer required

Unique identifier of the unit for which to obtain review questions.

Responses

200 OK
Body
Array of ReviewQuestion
403 Forbidden

You are not allowed to access the review questions for the specified unit.

Get Unit Reviews
GET /units/{unitId}/reviews

Authentication

API Authorization
read_public_reviews

Retrieve all reviews for the given unit, in chronological reviewDate order (most recent review comes last), that have been updated since the given from date, up to the given to date. If the to date is not provided, it defaults to the current date. If the given unitId refers to a chain of properties, all reviews for all sub-units will be included as well.

Path variables

unitId
integer required

Unique identifier of the unit for which to obtain reviews.

Request parameters

from
string required

Include only reviews updated since given date, in format YYYY-MM-DD. A review is considered updated since given date if either the reviewDate or managementResponseDate is later than or equal to the provided date.

to
string optional

Include only reviews updated up to given date, in format YYYY-MM-DD. A review is considered updated up to given date if both the reviewDate and managementResponseDate are earlier or equal to the provided date. If this parameter is not provided it defaults to the current date.

pageId
integer optional

Which page to retrieve. Will default to 0 if none is given. Request will return empty array if page is out of bounds.

Default:
0
pageSize
integer optional

Number of reviews to include per page.

Min: 1
Max: 10,000
Default:
1000

Responses

200 OK
Body
Array of Review
403 Forbidden

You are not allowed to access reviews for the requested unit.

400 Bad Request

The since date has an invalid format.

Get Online Reputation
GET /units/{unitId}/reputation

Authentication

API Authorization
read_public_reviews

Retrieve the online reputation for a specific unit for a given date. If the given unitId represents a chain of properties, results for all the units within the chain will be returned.

Path variables

unitId
integer required

Unique identifier of the unit for which to retrieve online reputation.

Request parameters

date
string required

Date for which to retrieve online reputation, in format YYYY-MM-DD.

source
string optional

Name of the source from which to retrieve the online reputation. If this parameter is not provided, then the returned score is the average of all sources.

Examples:
trip_advisorbooking_com

Responses

200 OK
Body
Array
Object
unit
Unit read-only

Unit which this online reputation refers to.

reputation
OnlineReputation read-only

Score/result for this specific unit.

compset
Array read-only

Array of all competitive sets for this specific unit.

Object
compsetId
integer read-only

Unique identifier of this specific competitive set.

name
string read-only

Name of this competitive set.

units
Array read-only

Array of units (& their results) contained in this competitive set. Might be of length 0 if this unit has no competitive sets.

Object
unit
Unit read-only

Description of unit within competitive set.

reputation
OnlineReputation read-only

Online reputation of unit within competitive set.

Review

Representation of a single online review of a property.

Object
issueId
integer read-only

Unique identifier of the issue which was created for this review.

unit
Unit read-only

Description of the unit for which this review was provided.

reviewDate
string read-only

Date when review was provided in format YYYY-MM-DD.

stayDate
string read-only

Date when stay review refers to occured in format YYYY-MM-DD. Note that the resolution of this varies depending on review source, some review sites for example only provide the month in which case this date will be set to the 1st day of that month.

source
string read-only

Identifier of the review channel on which this review was provided.

Examples:
trip_advisorbooking_comyelp
language
string read-only

ISO 639-1 representation of language in which this review was provided.

rating
number nullable read-only

Raw overall rating number as provided on the channel on which this review was provided.

normalizedRating
number nullable read-only

Normalized overall rating on scale [0.0, 1.0] for this review.

canRespond
boolean read-only

True if this is a review it is possible to respond to.

managementResponseDate
string nullable read-only

Date in format YYYY-MM-DD when (latest) management response was provided, or null if no response has been provided.

travelComposition
string nullable

Description of the travel composition, if provided by the review channel.

Enumeration:
couples
solo
friend
business
families
seniors
group
other
reviewRatings
Array of ReviewRating

A list of ReviewRating associated to this review.

ReviewRating

Representation of the rating of a single aspect of a guest review.

Object
reviewQuestion

The review question to which this rating applies.

score
number nullable

The score using the original scale of the source. This value is not null if the reviewQuestion's answerType is number, null otherwise.

Example:
4.7
normalizedScore
number nullable

The score on a scale [0…1]. This value is not null if the reviewQuestion's answerType is number, null otherwise.

Example:
0.75
text
string nullable

The text answer given by the guest. This value is not null if the reviewQuestion's answerType is text, null otherwise.

ReviewQuestion

Representation of a reputation question for which there can be information in a Review.

Object
key
string

Unique key identifying this question.

Examples:
overall_generalbreakfastentertainmentgeneral
description
string

Description of this question.

Examples:
Overall RatingBreakfastEntertainment facilitiesGeneral Comments
answerType
string

The type of answer this question accepts.

Enumeration:
number

If the answer to the question is a numerical rating.

text

If the answer to the question is a text from the guest.

enum

If the answer to the question is a text from the list specified in answerValues.

answerValues
Array of string nullable

If the answerType property is enum, this property contains a list of valid text answers for this question. Otherwise this property is null.

OnlineReputation

Representation of a single unit’s online reputation score / result at (the end of) a specific day.

Object
date
string read-only

Date in format YYYY-MM-DD for which this reputation score was calculated.

rank
integer nullable read-only

The rank of this property in the specified review channel source, or the average rank of this property over all the review channels where it has reviews if no channel source is specified. Please note that if no channel source is specified, several properties might have the same rank as it’s an average over multiple review channels. This value can be null if there is no available data to calculate the rank.

rankSize
integer nullable

The total number of properties against which this property is being compared in order to calculate the rank for the specified review channel source, or all review channels if no channel source is specified. This value can be null if there is no available data to calculate the rank.

reputationScore
number nullable read-only

The calculated Reputation Score for this specific date on scale [0.0, 10.0]. This value can be null if there is no available data to calculate the score.

normalizedScore
string nullable

The normalized score for the specified date and source, or the average of all sources if no source is specified. This value can be null if there is no available data to calculate the score.

Stays

A Stay represents a single stay at a Unit for a specific Guest, throughout the entire guest journey.

POST /units/{unitid}/stays
GET /units/{unitId}/stays/{stayId}/events
Register Guest Stay
POST /units/{unitid}/stays

Authentication

API Authorization
manage_stays

This operation registers a guest stay at the given unit, and returns a unique identifier for the stay. There are a few things to consider:

  • Almost all parameters are optional, except the status parameter. However, if no uniquely identifying information is provided such as booking reference or email address, a new anonymous stay will always be returned.
  • Even though this is a POST request which usually implies creation of a new resource, if the provided data (booking reference, email + checkin & checkout date, mobile + checkin & checkout date) matches an existing guest stay, the existing one will be returned.
  • If the stay existed previously, this call will update relevant fields (room, status, stayCallback)

Also note that this request specifically requires the manage_stays scope. Additionally you also need the chat_sessions scope if you want to be allowed to register the callback. Make sure to request it when requesting the access token:

$ curl -X POST -d "grant_type=client_credentials" -d "client_id=<CLIENT_ID>" -d "client_secret=<SHARED_SECRET>" -d "scope=basic manage_stays chat_sessions" "https://api.loopon.com/oauth2/token"

Finally, note that if you do not provide a stayCallback, any previously registered stayCallback will be discarded. There can at one time be max one stayCallback registered per GuestStay & API Client.

Path variables

unitid
string required

Unique id of the hotel for which you want to register a stay

Request body

Object
name
string required

Full name of guest

email
string email required

E-mail address of the guest

language
string nullable

ISO 639-1 language representation of the language the guest prefers to speak. If not provided will be defaulted to default language of the hotel.

mobile
string nullable

Mobile phone number of guest in full international format.

bookingReference
string nullable

Booking reference as provided by the PMS (Possibly shared by multiple guests)

bookingSource
string nullable

Booking source/channel for this guest’s reservation

marketSegment
string nullable

Market segment for this guest’s reservation

ratePlan
string nullable

Rate plan for this guest’s reservation

loyaltyType
string nullable

Loyalty program type for this guest (if multiple loyalty programs available)

loyaltyNumber
string nullable

Loyalty number/identifier for this guest

loyaltyLevel
string nullable

Loyalty level for this guest

bookingDate
string date nullable

Date (locally at hotel) when stay was booked, expected in ISO 8601 date format: 2017-11-19

checkinDate
string date nullable

Checkin date (locally at hotel) for guest, expected in ISO 8601 date format: 2017-11-19

checkoutDate
string date nullable

Checkout date (locally at hotel) for guest, expected in ISO 8601 date format: 2017-11-19

room
string nullable

Room number guest is/will be/was staying in

roomCategory
string nullable

Room category (code) the guest is/will be/was staying in

roomCategoryName
string nullable

Human readable name of room category guest is/will be/was staying in

status
string required

Current status of this guest’s journey

Enumeration:
prestay

Guest has not yet checked in to the hotel

instay

Guest is currently at the hotel

poststay

Guest has checked out from hotel

nextstay

Guest is (hopefully) in the process of booking a stay at the hotel

stayCallback

Callback to which you want the Loopon API to POST updates regarding this stay. All calls will be done with a LooponEvent in JSON format in the body of the request.

Responses

201 Created

New guest stay was registered

Body
400 Bad Request

Returned if any required data is missing, or provided data is invalid

Register Stay

Register a stay with all information provided

$ curl -X POST -H "Authorization: Bearer <ACCESS_TOKEN>" --data-binary \
    "{ \
        \"name\":\"Simon Finne\", \
        \"bookingReference\":\"ExampleReference-001\", \
        \"email\":\"simon.finne@loopon.com\", \
        \"mobile\":\"+46730442480\", \
        \"bookingDate\":\"2017-11-01\", \
        \"checkinDate\":\"2017-11-18\", \
        \"checkoutDate\":\"2017-11-29\", \
        \"room\":\"123\", \
        \"status\":\"instay\", \
        \"stayCallback\": \
            { \
                \"url\":\"https:\/\/www.wowsify.com\/api\/stayUpdate\", \
                \"auth\":\"basic\", \
                \"authToken\":\"ExampleToken\" \
            } \
        }" \
        https://api.loopon.com/public/units/<unitId>/stays
List Events for Stay
GET /units/{unitId}/stays/{stayId}/events

Authentication

API Authorization
manage_stays

Retrieve all events, in chronological order (most recent event comes last), that have occurred for the given stay. Each event will be represented in the form of a LooponEvent.

Paging is implemented by adding the pageId and pageSize parameter to the request, where pageId starts from 0 and pageSize defines the number of events you want per page. If less than pageSize events are returned, it means the end of events was reached.

Path variables

unitId
string required

Unique id for the hotel which you want to query

stayId
string required

Unique id of the stay for which you want to retrieve events

Request parameters

pageId
integer optional

Which page to retrieve. Will default to 0 if none is given. Request will return empty array if page is out of bounds.

Default:
0
pageSize
integer optional

Number of events to include per page.

Min: 1
Max: 1,000
Default:
100

Responses

200 OK
Body
Array of LooponEvent
Guest

Representation of a single guest (person + unit). All contact details are nullable and will be null in the case of an anonymous guest. For anonymous guests a new guestId will always be generated, so you cannot use a non-anonymous guest’s guestId from a chat to identify answers to the post-stay survey.

Object
guestId
integer

Unique identifier of a specific guest. Important GDPR/Data Privacy note: At the moment Loopon maintains unique and static guest ids & stay ids also for a guest that chooses to respond anonymously. On our side we will delete all PII associated with the guest id/stay id so the ids themselves do not constitute PII.

If you associate ids to a specific guest on your side, it is your responsibility to comply with GDPR & similar privacy laws by wiping/deassociating ids for guests who want to be anonymous.

name
string nullable

Full name of guest

email
string nullable

E-mail address to guest

mobile
string nullable

Mobile phone number to guest in full international format

GuestStay

Representation of a guest’s specific stay at a specific hotel.

Object
stayId
integer

Unique id identifying this specific stay. Important GDPR/Data Privacy note: At the moment Loopon maintains unique and static guest ids & stay ids also for a guest that chooses to respond anonymously. On our side we will delete all PII associated with the guest id/stay id so the ids themselves do not constitute PII.

If you associate ids to a specific guest on your side, it is your responsibility to comply with GDPR & similar privacy laws by wiping/deassociating ids for guests who want to be anonymous.

unitId
integer

Unique identifier of the hotel for which this is a stay.

guest
Guest nullable

The guest associated with this stay. Can be null for anonymous/un-identified stays.

status
string
Enumeration:
prestay

Guest has not arrived yet

instay

Guest is currently at the hotel

poststay

Guest has checked out from hotel

nextstay

Guest is currently booking a new stay

bookingReference
string nullable

Booking reference as provided by the PMS

bookingDate
string nullable

Date when stay was booked given in ISO 8601 format (YYYY-MM-DD)

checkinDate
string nullable

Arrival date in ISO 8601 format (YYYY-MM-DD)

checkoutDate
string nullable

Departure date in ISO 8601 format (YYYY-MM-DD)

room
string nullable

Room number the guest is staying in

chatSession

Chat Session associated with this stay. Note that this will only be returned if your access token is valid for the chat_sessions scope.

language
string

ISO 639-1 representation of the language the guest prefers to speak

guestStayUrl
string

URL which can be passed on to guest to access the current stay at the current status. Note that a new URL will be created for each POST /units/:unitId/stays. The URL will be valid for 30 days before expiring.

StayCallback

Specification of a callback to which you want the Loopon API to push updates regarding a guest stay.

Object
url
string

URL to which LooponEvent’s should be POSTed.

auth
string
Enumeration:
none

No authentication/authorization required (IP whitelist of 79.99.7.10 or URL contains secret)

basic

Loopon will add a Authorization: Basic <token> header to every request

bearer

Loopon will add a Authorization: Bearer <token> header to every request

authToken
string nullable

Authorization token to use with either basic or bearer authentication

Chat

The Chat API provides the possibility to integrate Loopon’s realtime guest messaging features into your own guest application.

Introduction

In order to use the Loopon Chat API, we expect that you maintain your own backend for your own guest application and most likely your own frontend which is the guest application itself.

The picture below gives a quick overview of the different parts involved when using the Chat API:

A typical flow to setup a chat session, after which the guest writes a message to which the hotel responds, would look like this:

Note that for authorisation of the guest app itself, the unique identifier of the chat session is included in the WSS URL and is used as the authentication of the client. You do not need to pass any separate access token or other authentication info from the guest app.

Setup Chat Session (RESTful JSON API)

In contrast to some systems, Loopon maintains a single chat session per guest for the entire guest journey rather than task/issue/topic-based chats. The main idea behind this design is simplicity from the guest’s point of view - he or she maintains a single conversation with the hotel, and the responsibility of delegation between tasks and departments rest solely at the hotel.

In order for your guest app to obtain access to the chat session, your backend needs to provide the Loopon API with a number of details about the guest so we can identify the guest and provide you with the associated chat session.

The request needs to be done from your backend rather than from the guest app itself, in order to eliminate the need to maintain shared secrets on the client side.

After having obtained access to the chat session, you just need to pass on the WSS URL to your guest app which can then maintain realtime communication through the WebSocket API.

The steps to obtain access to the chat session are the following:

  1. Register the Guest Stay Register Guest Stay
  2. Send chat session from your backend to guest app
  3. Connect to and maintain the chat session from your guest app Manage Realtime Chat (WebSocket JSON API)
ChatSession

The ChatSession object describes all the information you need to pass on to your guest app in order to let it participate in a realtime conversation through the Loopon Chat Server WebSocket.

Object
sessionId
string read-only

Unique identifier of the chat session

wssUrl
string read-only

Fully qualified URL to the web socket your guest app needs to connect to. Note that this will always point to a secure WSS URL. Note that this URL will stay constant for the duration of the stay, so you can cache it in your own backend.

externalDataRef
string read-only

Identifier used to reference this chat session from 3rd party integrations such as Facebook Messenger.

Manage Realtime Chat (WebSocket JSON API)

From the guest app’s point of view, all communication with Loopon is done through a WebSocket. Messages sent both by the hotel and the guest will be received on the socket, and if the app wants to send messages to the hotel from the guest it is done by writing the message to the socket.

Note that when you register a GuestStay you will be given back a WSS URL in a format similar to:

wss://chat.loopon.com:2424/public/en/2f51f216ea9c411e87ce45059e2168de

While not required for the chat to work, it is highly recommended that you add a unique deviceId parameter when connecting, such as:

wss://chat.loopon.com:2424/public/en/2f51f216ea9c411e87ce45059e2168de?deviceId=ab637dfeca7abcd

If you are developing under iOS a suitable deviceId to use would be for example UIDevice.current.identifierForVendor!.uuidString in Swift or [UIDevice currentDevice].identifierForVendor.UUIDString for Objective C.

The purpose of the deviceId is to keep track of which events a specific device has seen, in order for the chat server to know which events to replay on connect event. The deviceId should not be an id that can be linked to any personally identifiable information.

Sending chat messages

When you want to deliver a chat message from the guest to the hotel, this is done by writing a LooponEvent in JSON format on the WebSocket to which your guest app is connected.

Note that if you provide any of the read only fields in your message, they will be ignored.

After you have sent a LooponEvent on the WebSocket, if it was correctly received and processed in the backend it will be sent back to you on the same WebSocket but this time with the appropriate read only fields filled in (such as created and id in case of for example a ChatMessage).

Example:

{
    "type":"chatMessage",
    "chatMessage":{
        "localId":"FB634A49-074E-4A8F-A840-EF66B1D38A3C",'
        "contentType":"text\/plain",
        "content":"Please be careful when parking my brand new Tesla Roadster!"
    }
}
LooponEvent

All messages passed by Loopon on both the WebSocket connection as well as to the registered callback URL for the guest application backend will be of type LooponEvent.

Object
sessionId
string read-only

Unique identifier of the chat session this event is associated with.

Example:
17e051949dfcd3fe7b4e9e93a9bcd7001c08e1dd5f2fc4365f9d5e22e0e46cd2
created
string read-only

Date & timestamp when the event was initially created, provided in ISO 8601 format including milliseconds.

Example:
2017-11-21T17:50:48.813225Z
type
string required

Identifier of the type of event, which defines the rest of the content of the LooponEvent.

Enumeration:
chatMessage

Either guest or hotel has written a message.

typingIndicator

Either guest or hotel is currently composing a message (only sent on WebSocket).

guestConnect

Guest connected to chat server (only sent to backend callback).

guestDisconnect

Guest disconnected from chat server (only sent to backend callback).

errorMessage

Error report for event previously sent by client; mostly for debugging purposes

chatMessage

The chat message, if the type is chatMessage

errorMessage
string

The error message, in case type was error

guestConnect

The connection message, if type is guestConnect

guestDisconnect

The disconnect message, if type is guestDisconnect

typingIndicator

The typing indicator message, if type is typingIndicator

ChatMessage

Describes a chat message written either by the guest or the hotel.

Object
id
integer read-only

Unique identifier of this specific message. If your application already received this event in the past, you might want to check the updated timestamp to verify if you need to update your local contents.

read
string nullable read-only

Timestamp when counterpart read the message (if written by guest, when did the hotel read it - if written by the hotel, when the guest read it). Provided in ISO 8601 format including milliseconds. If not read yet, it will be null.

Example:
2017-11-21T17:50:48.813225Z
localId
string nullable

Unique ID for this message specified by the interface where the message is generated. Can be used by guest app to keep track of correct delivery of the message.

author
string read-only

Which side of the conversation wrote this message?

Enumeration:
hotel

Message written by hotel staff

guest

Message written by guest

authorName
string read-only

Name of the author of this message

authorAvatarUrl
string nullable read-only

Fully qualified URL to image of the author

contentType
string required

Describes the type of content included in this chat message.

Enumeration:
text/plain

Plain text message with no styling.

text/html

Rich text formatted with very limited subset of HTML. Loopon ensures whitelist of allowed tags in backend, safe to display as-is.

image/png

Image in PNG format. URL will be provided to actual image data.

image/gif

Image in GIF format. URL will be provided to actual image data.

image/jpeg

Image in JPEG format. URL will be provided to actual image data.

url
string nullable

Fully qualified URL to content data (valid for image/png, image/gif and image/jpeg)

content
string nullable

Content of message (valid for text/plain and text/html)

media
string read-only
Enumeration:
sms

Message was sent using sms

facebook

Message was sent using facebook messenger

webchat

Message was sent using Loopon’s doorbell (web chat)

appchat

Message was sent from app using the public api

email

Message was sent through e-mail

GuestConnect
Object
deviceId
string

Unique id of the device, exactly as provided by the guest app when connecting to the chat server.

GuestDisconnect
Object
deviceId
string

Unique id of the device, exactly as provided by the guest app when connecting to the chat server.

TypingIndicator

The TypingIndicator message acts as a notification that someone is currently typing a message. When your guest app is sending a TypingIndicator, you don’t even need to include the typingIndicator field in the LooponEvent message. Just keep sending a LooponEvent of type typingIndicator at around 5 second intervals, as long as the guest is still typing a message.

When you receive a LooponEvent of type typingIndicator you should show a typing indicator, optionally together with the authorName field to signal who at the hotel is typing a message. You should make the indicator automatically disappear after timeout seconds, unless you receive a new typingIndicator LooponEvent before that in which case you should reset the timeout to the new value - don’t add it!

Object
timeout
integer read-only

Number of seconds this typing indicator should max be visible.

Example:
author
string read-only

Identifier of who is currently typing a message.

Enumeration:
guest
hotel
authorName
string read-only

Name of the author currently writing a message.

authorAvatarUrl
string read-only

URL to an avatar of the author currently writing a message.