Paying with customer cards

Overview

Duffel Cards provides a PCI-compliant way for your customers to pay airlines and accommodation providers directly for their bookings.
This guide will walk you through how to use Duffel Cards to capture your customers' cards, have the customers complete a 3DS challenge when required, and book flights or accommodation directly with these cards. Duffel Cards adds new steps to the normal search, select and create instant orders workflow:

Tip

The payment flow starts on your checkout page and includes the following steps:
. Capture your customers' card - Use Duffel's card component, DuffelCardForm, to capture all the required card details and store them securely on Duffel's servers. 2. Authenticating the payment - Start a Duffel 3DSecure Session using our createThreeDSecureSession function to authenticate the customer intent to purchase the travel service. As part of this step we contact the customer's card issuer to see if the cardholder is required to authenticate the transaction. This may trigger a challenge screen where your customer needs to enter a confirmation code to proceed with the booking. 3. Book a flight or accommodation - Taking the 3DSecure Session response and using that as part of booking a flight or accommodation with the customers card.

Requirements

Duffel Cards for non-PCI-compliant customers currently only supports integrations that operate a back-end server and run in a web browser with their front-end written in JavaScript, and mobile written in React Native. If these two requirements are not met you won't be able to use Duffel Cards for now.

Caution

This guide assumes that you already have a working integration with the Duffel API. Only the basics of searching and booking are required for this guide. If you could use a refresher, please head over to our Quick Start Guide.

Capture customer card

A Card is a resource that will be used to represent a card that does not expose PCI sensitive data and can be used to pay travel suppliers directly.
Once your customer has searched for and selected an offer to book, the first step to use Duffel Cards is to use the DuffelCardForm component on your checkout pages from the Duffel JavaScript library @duffel/components.

Install

Start by installing the library in your JavaScript project.
npm i @duffel/components
# -- or --
yarn add @duffel/components
You can find up to date documentation on how to use it on github:

Create client component key

To use the card component a client component key needs to be created on the server side and be made available to your checkout pages.
The client component key is a token that is safe to be used client side.

Render card form component

Next render the DuffelCardForm component in the payment section of your checkout page. This is usually the final step once the final price is known. Using the client component key, this will render a PCI-complaint form to capture the card and return a Card ID that will get used in the next step.
Actions are made available through an imperative interface. The component ref exposes two actions that will issue a request to Duffel to handle the user’s card data. You may choose to manage the ref yourself but we recommend using the useDuffelCardFormActions hook.

JavaScript

function YourComponent() {
const { ref, createCardForTemporaryUse } = useDuffelCardFormActions()
return (
<>
<DuffelCardForm ref={cardFormRef} {...props} />
<button onClick={createCardForTemporaryUse}>Pay</button>
</>
)
}
Once the form is submitted there are two different action handlers:
Validate This action gives you visibility into whether the form data is valid. This will happen automatically and does not require you to trigger a ref action. You should use the success handler to enable the following steps on your UI. To handle this action use:
  • onValidateSuccess: The card data input is valid.

  • onValidateFailure: The card data input is not valid. Note this will only be called when the form modified in a way that fails validation after validation had previously passed.

createCardForTemporaryUse When successful, this action will return a card ID that can be used for creating orders and bookings. To handle this action use:
  • onCreateCardForTemporaryUseSuccess: Returns the Card record.

  • onCreateCardForTemporaryUseFailure: Return information about the error.

Example of the card component

Example of the card component

Learn more

Initiate 3DS Session

Card payments must be authenticated before authorisation of a payment can be given. In this step, we will perform a 3DS authentication for a card payment with the cardholder's issuing bank and use the result to place an order using the Duffel API.
The flow starts by asking the cardholder's issuing bank to authenticate a payment amount to a specific merchant. The issuing bank might require fingerprinting of the cardholder's browser and requiring a verification challenge during checkout. The issuing bank determines the challenge flow, which usually involves the cardholder confirming the transaction using the method set up with their issuing bank (SMS, banking app, or email).
Example of a 3DSecure challenge

Example of a 3DSecure challenge

Usage

For 3DS authentication, use the createThreeDSecureSession function provided in @duffel/components. You will need a client key, resource information (i.e. its ID and any associated services), and Card ID created in the previous step.
If a 3DS challenge is required, the function will open a modal for the cardholder to action.
The createThreeDSecureSession functions returns a promise. If the transaction is authenticated successfully, this promise will resolve to a 3DS Session object with the status ready_for_payment. You must pass the ID of the 3DS Session when creating a payment for your resource as three_d_secure_session_id .
Otherwise the promise will reject with an error or a 3DS Session with a different status. Any other status means the session is not ready for payment - either the user failed the challenge, or there was an error during the challenge. The full list of possible statuses can be found in the interface below. When rejected the challenge should be retried by calling the function again.
In the below example, you can see how to use createThreeDSecureSession to get the three_d_secure_session_id required to create an order.

JavaScript

const offerId = 'off_0000AJyeTUCEoY5PhVPN8k_0'
const offerServices = [{ id: 'ase_00009UhD4ongolulWAAA1A', quantity: 1 }] // This can be bags or seats when booking flights
const clientKey = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiaWN1XzAwMDBBZ1ppdHBPblF0ZDNOUXhqd08iLCJvcmRlcl9pZCI6Im9yZF8wMDAwQUJkWm5nZ1NjdDdCb3JhVTFvIiwiaWF0IjoxNTE2MjM5MDIyfQ.GtJDKrfum7aLlNaXmUj-RtQIbx0-Opwjdid0fiJk6DE' // See the Client Key section above in the document
const cardId = 'tcd_00009hthhsUZ8W4LxQgkjb' // You can use the Duffel card component or API to get the card ID.
const threeDSecureSession = createThreeDSecureSession(
clientKey,
cardId, // This is the Card ID from the previous step
offerId,
offerServices,
true
)
.then(async (threeDSecureSession) => {
if (threeDSecureSession.status === 'ready_for_payment') {
createOrder({
... // plus passenger and other order creation information
selected_offers: [offerId],
services: offerServices,
payments: [
{
type: 'card',
currency: offerCurrency,
amount: offerAmount,
three_d_secure_session_id: threeDSecureSession.id,
},
],
})
} else {
console.warn(
'3DS session status is not ready_for_payment, please try again',
{
threeDSecureSession,
}
)
}
})
.catch((error) => {
console.error('Error creating 3DS session', error)
})

Testing your integration

Caution

Test Scenarios - 3DS Challenge

In test mode the following card details can be used to trigger different outcomes on the card acceptance of the 3DS flow.
Follow the below instructions to simulate the different 3DS authentication scenarios in test mode:
Card number:
Test scenarioVisaMastercardAmerican Express
3DS Challenge Required42424242424242425555555555554444378282246310005
No 3DS Challenge Required41111101166388705555550130659057378282246310005
Expiry date: Use any future date for expiry_month and expiry_year
Card Verification Code (CVC): Use any valid value for cvc. 3 digits for Visa and Mastercard, 4 digits for American Express.
Address details: Use any valid address.
3DS Challenge Verification code: When completing a 3DS challenge, entering 111-111 will result in a successful challenge. Any other value will result in a failure.

Learn more

Test Scenarios - Card Payment Declined

Suppliers can decline card payments for multiple reasons (perceived risk, insufficient funds, etc.).
Follow the below instructions to simulate payment declined scenarios in test mode:
  • To simulate a payment declined in Flights, use Declined as name when creating the card record.

  • To simulate a payment declined in Stays, select the Payment declined when Booking room on the Duffel Test Hotel.