Affiliate payments overview
Affiliates with Full + Booking API access can book through the Partner API and collect customer payment details using an API or an iframe solution.
Our payments solutions are only for affiliate partners with Full + Booking API access.
In this guide, we cover:
A comparison of our two payment solutions
How to implement the API solution
How to implement the iFrame solution
Testing
Additional resources
We offer two payment solutions, both of which follow a similar flow:
Check Availability and Pricing:
Determine that the desired experiences are available for the required date, time and passenger mix combination using the /availability/check endpoint and that the most accurate price is applied.
Request a Booking Hold:
If the experiences are available, request an availability/pricing hold using the /bookings/cart/hold endpoint.
Payment:
Provide customer payment details to obtain a payment token using one of the two available options:
- API: Collect customer payment details and pass them through to the /v1/checkoutsessions/{sessionToken}/paymentaccounts endpoint to obtain the payment token.
- iFrame: Include the Viator iframe in your checkout page to collect customer payment details to obtain the payment token.
Note: The customer won’t be charged until during the Confirm the Booking step.
Confirm the Booking:
Confirm the held booking using the /bookings/cart/book endpoint passing through the payment session token obtained using your chosen payment solution.
Choosing a payment solution
You can choose between two different payment solutions: our iFrame and a custom API integration. Both allow you to add customer payment to your checkout flow, but each come with their own benefits and features.
API | iFrame | |
Accepts debit & credit cards | ✓ | ✓ |
Accepts additional payment methods (e.g. Apple Pay or Google Pay) | X | Coming soon! |
Fraud detection | ✓ | ✓ |
3DS / PSD2 compliant | X | ✓ |
Supports multi-vendor carts | ✓ | X |
Supports multi-product carts* | ✓ | ✓ |
*applies only to Viator products
Implementing the API Solution
The API solution provides maximum flexibility to partners who are providing multi-vendor carts and are comfortable collecting customer payment details.
Prerequisites
Content Security Policy
Partners who implement a Content Security Policy on their sites must permit resources for frame-src, script-src and connect-src directives on the page where payment details are collected.
These directives allow the Viator Javascript library and our fraud prevention provider to integrate with your payment details page to facilitate fraud detection by collecting data points about the device, connection, and location. These data points are then analyzed to recognize trusted customers and reduce the likelihood of fraudulent bookings.
See the Content Security Policy section for details.
PCI Compliance
Partners wishing to use the API solution collect payment details from their customers and pass them through to the Viator payment gateway. As the partner is collecting credit card details, the partner is required to ensure that they are PCI compliant.
API Implementation
Check Availability and Pricing
Endpoint: /availability/check
Request a Booking Hold:
Endpoint: /bookings/cart/hold
Note: The payment session token returned from this call is valid for 1 hour, after which it will expire. This token is required to be valid for calling the Confirm the Booking endpoint.
API flow-specific request values:
Property | Value |
paymentDataSubmissionMode | PARTNER_FORM |
API flow-specific response values:
Property | Value |
paymentDataSubmissionUrl | The URL to use for sending the customer payment details. Already includes the session token. |
paymentSessionToken | The payment session token is used to initialize the library that captures device details for fraud prevention purposes. This token is quite long and can be JWT decoded. |
Payment
Note: Use the paymentDataSubmissionUrl value from the booking hold request instead of manually constructing the URL.
API flow specific response values:
Property | Value |
paymentAccounts.creditCards.accountMetaData.sessionAccountToken | The payment token for the payment details. Required in the confirm booking endpoint call. |
Confirm the Booking
Endpoint: /bookings/cart/book
API flow specific request values:
Property | Value |
paymentToken | The sessionAccountToken returned from the payment endpoint. This token is in the form STK-<string code> (e.g. STK-czhiz2jbqjdeff5gptqbhoscb4). |
Viator Javascript Library
The Viator Javascript library must be imported into your payment details page using the following URL:
https://checkout-assets.payments.tamg.cloud/stable/v2/payment.js
Step-by-Step Guide
These steps will guide you through implementing the fraud detection requirements within your checkout page. This guide covers the required aspects and should give you enough of an idea to adjust, as needed, to support your use case.
Step 1
Provide initialization logic, which will be called on page load with the paymentSessionToken returned from the /bookings/cart/hold API endpoint.
This relies on the Viator UI Javascript library, which is required to initialize the fraud detection logic.
The payment variable should be in a scope that can be called during form submission.
Note: It is now recommended that one uses window.Payment.init(…) rather than new Payment(…) as this will detach the event listeners from any previous instance of the payment class.
import { Payment } from ‘https://checkout-assets.payments.tamg.cloud/stable/v2/payment.js’
var payment;
function initPaymentElements(paymentSessionToken) {
payment = window.Payment.init(paymentSessionToken);
// The Payment method is imported by the Viator Javascript library
}
Step 2
On page load, call the method to initialize the fraud detection logic passing in the payment session token returned from the /bookings/cart/hold API endpoint.
<body onload=”initPaymentElements(‘$paymentSessionToken’)”>
Step 3
Provide the fraud detection submission logic for your payments page, which should be called to submit the fraud detection details before you handle the processing of the booking.
The onSubmit method should be called when the payment details form is submitted, and call the submitDeviceData method of the payment variable defined in Step 2 before continuing to call with the booking flow.
payment.submitDeviceData();
// continue with booking flow
}
Implementing the iFrame Solution
The iframe solution offers a simpler option to partners who only sell Viator experiences and don’t want the overhead of dealing with their customer payment details.
iFrame example
Here is an example of what the iFrame generally looks like.
The iFrame can be styled, as described in our styling guide.
Prerequisites
Content Security Policy
Partners who implement a Content Security Policy on their sites must permit resources for frame-src, script-src and connect-src directives on the page where the iframe will be included.
These directives allow the Viator Javascript library and our fraud prevention provider to integrate with your payment details page to display and interact with the iframe and facilitate fraud detection by collecting data points about the device, connection, and location. These data points are then analyzed to recognize trusted customers and reduce the likelihood of fraudulent bookings.
See the Content Security Policy section for details.
Browser Support
The iframe solution supports the latest versions of Edge, Firefox, Chrome and Safari.
iFrame Implementation
Check Availability and Pricing
Endpoint: /availability/check
Request a Booking Hold:
Endpoint: /bookings/cart/hold
Note: The payment session token returned from this call is valid for 1 hour, after which it will expire. This token is required to be valid for calling the Confirm the Booking endpoint.
iFrame flow specific request values:
Property | Value |
paymentDataSubmissionMode | VIATOR_FORM |
hostingUrl | Provide the URL to your checkout page where the iframe will be hosted. This should include the protocol, domain and any non-standard port, excluding the trailing ‘/’. E.g.: https://www.yourdomain.com |
iFrame flow specific response values:
Property | Value |
paymentSessionToken | The payment session token is used to initialize the iframe. This token is long and can be JWT decoded. |
Payment
See Step by Step Guide below.
iFrame flow success response values:
Property | Value |
paymentToken | The payment token for the payment details. Required in the confirm booking endpoint call. This token is in the form STK-<string code> (e.g. STK-czhiz2jbqjdeff5gptqbhoscb4). |
Confirm the Booking
Endpoint: /bookings/cart/book
iFrame flow specific request values:
Property | Value |
paymentToken | The paymentToken returned in the object passed to the success callback method from the payment submitForm call. |
Import
There are two possible ways to include the library:
- Javascript
- NPM module
Viator Javascript Library
The Viator Javascript library must be imported into your payment details page using the following URL:
https://checkout-assets.payments.tamg.cloud/stable/v2/payment.js
NPM module
If using a build tool, for example if you are using webpack to create your pages, and you can import NPM packages then you can use this option to load the library:
https://checkout-assets.payments.tamg.cloud/payment-module-v2.0.4.tgz
Step-by-Step Guide
Javascript library guide
These steps will guide you through implementing the Viator iframe payments solution within your checkout page. This guide covers the required aspects and should give you enough of an idea to adjust, as needed, to support your use case.
Step 1
Include an element where you want the payment details iframe to be injected. The element’s id will reference this element in the initialization Javascript.
<div id=“payment-iframe-holder”>
<!– Secure iframe is injected here –>
</div>
Step 2
Provide initialization logic, which will be called on page load with the paymentSessionToken returned from the /bookings/cart/hold API endpoint.
This relies on the Viator UI Javascript library, which is required to initialize the iframe and fraud detection logic.
The element id from Step 1 should be used as the value for the cardElementContainer.
The payment variable should be in a scope that can be called during form submission.
See the Styling section for full styling options.
import { Payment } from ‘https://checkout-assets.payments.tamg.cloud/stable/v2/payment.js’
var payment;
function initPaymentIframe(paymentSessionToken) {
payment = window.Payment.init(paymentSessionToken);
// The Payment method is imported by the Viator Javascript library
payment.renderCard({
cardElementContainer: ‘payment-iframe-holder’,
onFormUpdate: onFormUpdate,
styling: {
variables: {
colorBackground: ‘#FFF’,
colorPrimaryText: ‘#000’
}
}
});
}
Step 3
On page load, call the method to initialize the iframe passing in the payment session token returned from the /bookings/cart/hold API endpoint.
<body onload=“initPaymentIframe(‘$paymentSessionToken’)”>
Step 4
Provide the form submission logic for your payments page, which should be called to process the payment details before you handle the processing of the form.
The onSubmit method should be called when the form is submitted, and call the submitForm method of the payment variable defined in Step 2. The argument to submitForm is an object with an address field containing fields for the payer’s country code and postcode/zip code.
The onSubmitSuccess and onSubmitError methods will be called on success and error, respectively, from submitting the payment details to the payment gateway. These methods must be implemented appropriately for dealing with successful or error responses.
The payer’s country code and postcode are not included in the iframe collection form and must be collected by the partner to submit the payment details.
Note: The country code is the ISO 3166-1 alpha-2 code for the customer country.
The onSubmitSuccess callback method will be passed an object in the following format:
{
result: “SUCCESS”,
paymentToken: <Token>,
cardData: {
cardType: “Visa”
}
}
The paymentToken is required for the Confirm the Booking endpoint.
function onSubmit(e) {
// omitted … read country and zip fields on page
const bodyData = {
address: {
country: country,
postalCode: zip
}
email: email //or you can pass in phoneNumber: phoneNumber
};
payment.submitForm(bodyData)
.then((res) => onSubmitSuccess(res))
.catch((err) => onSubmitError(err));
}
function onSubmitSuccess(message) {
// Handle success here
}
function onSubmitError(error) {
// Handle errors here
}
Step 5
When the form that contains the payment details is submitted, ensure that the form submission logic is called to process the payment details.
<button id=“submitBtn” type=“button” onclick=“onSubmit()”>Book</button>
Complete Example
checkout.html
<html>
<head>
…
<!– checkout.js
<script src=“/checkout.js” type=“application/javascript”></script>
</head>
<body onload=”initPaymentIframe(‘$paymentSessionToken’)”>
…
<div>
<label for=“billing-country”>Billing Country</label>
<input type=”text” name=“billing-country” size=“2” width=“4” id=“billing-country” />
</div>
<div>
<label for=“zip”>Postal Code</label>
<input type=“text” name=“zip” value=“5000” size=“10” id=“zip” />
</div>
<div>Enter your payment details below</div>
<div id=“payment-iframe-holder”>
<!– Secure iframe is injected here –>
</div>
<button id=“submitBtn” type=“button” onclick=“onSubmit()”>Book</button>
…
</body>
</html>
checkout.js
import { Payment } from ‘https://checkout-assets.payments.tamg.cloud/stable/v2/payment.js’
var payment;
function initPaymentIframe(paymentSessionToken) {
payment = new Payment(paymentSessionToken);
payment.renderCard({
cardElementContainer: ‘payment-iframe-holder’,
onFormUpdate: onFormUpdate,
styling: {
variables: {
colorBackground: ‘#FFF’,
colorPrimaryText: ‘#000’
}
}
});
}
function onSubmit(e) {
// omitted … read country and zip fields on page
const bodyData = {
address: {
country: country,
postalCode: zip
}
};
payment.submitForm(bodyData)
.then((res) => onSubmitSuccess(res))
.catch((err) => onSubmitError(err));
}
function onSubmitSuccess(message) {
// Handle success here
}
function onSubmitError(error) {
// Handle errors here
}
NPM module guide
This guide shows you an example to implement the NPM module for payments solution within your checkout page. This guide combines all the required aspects and should give you enough of an idea to adjust, as needed, to support your use case.
Step 1
Add a dependency on your package.json to the payment module.
“dependencies”: {
…
“payment”: “https://checkout-assets.payments.tamg.cloud/payment-module-v2.0.4.tgz”,
…
}
Step 2
Use the module in your code.
import ‘./App.css’;
import { useEffect } from ‘react’;
import loadPayment from ‘payment’;
function updateFunction(event) {
console.log(event)
}
function submitSucceeded(msg) {
// Format of msg:
// {result: “SUCCESS”, paymentToken: <Token>, cardData: {cardType:”Visa”}}}
}
function submitFailed(message) {
// report errors here
}
var paymentPromise;
var payment;
/**
* The function called when the submit button is pressed.
*/
function submit(e) {
// omitted … read country and zip fields from page
const cardMetadata = {
address: {
country: country,
postalCode: zip
}
};
// Call the payment library to submit the card details to the TripAdvisor vault.
payment.submitForm(cardMetadata)
.then((resp) => submitSucceeded(resp))
.catch((err) => submitFailed(err));
}
function App() {
useEffect(() => {
// Make this block of code idempotent:
if (paymentPromise) {
return;
}
const renderOptions = {
cardElementContainer: ‘card-frame-holder-module’,
cardholderName: ‘Jane Doe’,
onFormUpdate: updateFunction,
styling: {
variables: {
colorBackground: ‘#F5F5F5’,
colorPrimaryText: ‘#00008B’
}
}
};
// This is the entry point to the module which will load the library code dynamically
// The return is a promise that will resolve to the Payment object.
paymentPromise = loadPayment(‘ey…TOKEN…8Q’);
// When the promise resolves we can render the form:
paymentPromise.then(payment => {
// Store a reference to payment to call in the submit function:
this.payment = payment;
// Render the form:
payment.renderCard(renderOptions);
console.log(“Form should now be rendered”)
});
}, []);
return (
<div className=“App”>
<p>Checkout lib loaded by Module.</p>
<div id=“card-frame-holder-module” className=“masked”></div>
<button onClick={submit()}>Submit</button>
</div>
);
}
export default App;
Styling the iFrame
The styling of some elements within the iframe is supported. The full styling options available are listed below:
styling: {
colorTheme: ‘LIGHT|DARK’, // Defaults to LIGHT
variables: {
fontSize: ‘0.9rem’,
colorInputBackground: ‘#eee’,
colorBackground: ‘#eee’,
colorPrimaryText: ‘#212121’
}}
All styling settings are optional, with any combination of them supported. Colors can be a standard CCS name or HEX value. Font sizes must be in rem.
Addendum
Content Security Policy
If your site implements a Content Security Policy (CSP), to use either of the Viator payment solutions, you will be required to adjust your CSP with these values.
See here for more details about CSPs.
Directive | Sandbox Host | Production Host |
frame-src | ||
script-src | ||
connect-src |
Example Content Security Policy for Production:
<meta http-equiv=”Content-Security-Policy” content=”frame-src ‘self’ https://api.tapayments.com https://prod.accdab.net https://www.cdn-net.com; script-src ‘self’ https://checkout-assets.payments.tamg.cloud https://prod.accdab.net https://www.cdn-net.com https://six.cdn-net.com; connect-src ‘self’ https://checkout-api.payments.tamg.cloud https://prod.accdab.net;”>
Secure voucher redemption
Secure voucher redemption must be implemented in case of transactions that meet at least one fraud suspicious criteria. Such transactions can be identified by the isVoucherRestrictionRequired field in the /bookings/cart/book response returned for every cart item. This field has value true when the transaction is identified as potentially fraudulent and false when the transaction is deemed legitimate.
Secure voucher redemption requires indirect access via email with either a link or a pdf version of the voucher that can be accessed only by an authorized person (instead of displaying the voucher on the booking confirmation page)
Testing
Test Credit Cards
In the sandbox environment, please use one of the test cards listed on: https://developer.paypal.com/braintree/docs/guides/credit-cards/testing-go-live/java
3DS Support
For versions of the Viator UI Javascript library that support 3DS, a 3DS flow is likely to be triggered when the payment currency is EUR or GBP. The sandbox version of the library includes the ability to simulate the completion of a successful 3DS challenge. Actual MFA support is only available in a production environment with real cards.