Integrating the Duffel Assistant

About

Offering a high quality post-booking experience is an essential part of selling travel. However, servicing flights is complex, management integrations are hard to build, there will likely always be support cases that can't be solved programmatically, and having a team of knowledgeable travel consultants to manage support queries is expensive.
We created the Duffel Assistant to take on the burden of servicing flights orders and stays bookings. With this product you are able to integrate a visual component into your website that will display your customers trips and give them the ability to manage their flights and stays. Where an automation is not available they can connect via chat to our team of travel support specialists to resolve issues.
This guide walks through how to integrate Duffel Assistant into your website.

Assistant overview

The Assistant offers two main functionalities:
  • A trip management interface

  • A chat connected to Duffel's travel support team

Screenshots of the pages of the Duffel Assistant

Screenshots of the pages of the Duffel Assistant

Quick start

Load script

Include the following script tag on your site

HTML

<script
type="text/javascript"
src="http://assets.duffel.com/assistant/custom-element.js"
></script>

Render custom element

Include the custom element anywhere on your markup.

HTML

<duffel-assistant></duffel-assistant>

Open assistant

To open the assistant you need to call openDuffelAssistant and give it a client key to authenticate the component usage. You can learn about how to retrieve the client key below.
If you don't have a client key yet, you can also use the client key below which will load a fixture used to demonstrate the component.

React

openDuffelAssistant({
clientKey:
'fixture_eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiaWN1XzEyMyJ9.AEC4nHMvFuOrCljQ1guQz-Sw53GsP4JPiY1N2OLtnpI',
})

Pre-requisites

Customer users

To work with assistant we need to know which orders and bookings are associated to which users. For every user of your platform that will be booking travel on Duffel you need to create a Customer User. And when an order or booking is created, the IDs of that customer user must be present in the request payload. Learn more on our API reference:

Client key

Client keys are ephemeral and unique per user, so they must be generated on demand — when the assistant is going to be used. The mode of the access token you use to create the client key will dictate its scope of access. To create a client key for a specific user you must include the user ID in the data attribute of the request payload:

JSON

{ "data": { "user_id": "icu_..." } }
Creating client keys

Showing user trips

  • Generate a client key for your user

  • Share the client key with your front-end

  • Load assistant script

  • Render the custom element

  • Call function to open the assistant

Find a Javascript example below, with annotations of the steps above in comments:

React

// server.ts
import express from 'express'
import { readFile } from 'fs/promises'
import { dirname, resolve } from 'path'
const app = express()
const port = 3000
const DUFFEL_API_TOKEN = '' // TODO: Add your API token here
const USER_ID = '' // TODO: Add your user ID here
const HTML_FILE_PATH = resolve(__dirname, './index.html')
async function getHTML() {
return await readFile(HTML_FILE_PATH, {
encoding: 'utf-8',
})
}
async function getComponentClientKey(user_id: string) {
const response = await fetch(
`https://api.duffel.com/identity/component_client_keys`,
{
method: 'POST',
headers: {
'Duffel-Version': 'v1',
'Accept-Encoding': 'gzip',
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${DUFFEL_API_TOKEN}`,
},
body: JSON.stringify({ data: { user_id } }),
}
)
const { data } = await response.json()
return data.component_client_key
}
app.get('/', async (_req, res) => {
try {
// STEP 1: Generate a client key for your user
const componentClientKey = await getComponentClientKey(USER_ID)
const template = await getHTML()
res.writeHead(200)
// STEP 2: Share the client key with your front-end
res.end(template.replace('__COMPONENT_CLIENT_KEY__', componentClientKey))
} catch (error) {
console.error(error)
res.writeHead(500)
res.end((error as Error).message)
}
})
app.listen(port, () => {
console.log(`Listening on port ${port}`)
})

HTML

// index.html
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Traveller support integration example</title>
</head>
<body style="height: 100vh">
<h1>Traveller support integration example</h1>
<button id="open-support" onclick="openSupport()">Open support</button>
<!-- STEP 4: Render the custom element -->
<duffel-assistant></duffel-assistant>
</body>
<!-- STEP 3: Load assistant script -->
<script
type="text/javascript"
src="https://assets.duffel.com/assistant/custom-element.js"
></script>
<script type="text/javascript">
window.addEventListener('load', () => {
window.openSupport = () => {
// SETP 4: Call function to open the assistant
openDuffelAssistant({
clientKey: '__COMPONENT_CLIENT_KEY__',
})
}
})
</script>
</html>

Assistant for single resource

You may want to take more control over the display experience of flights order and stays booking, or integrate our flight and booking management APIs. In that case, you’ll only need the assistant when human intervention is needed. To support that you’ll need the following:

Client key for resource

A resource, aka a flights order or stays booking, needs to be identified in the client key creation. So when creating the client key you must include both the user id and resource id for which your user needs support. For orders:

JSON

{ "data": { "user_id": "icu_...", "order_id": "ord_..." } }
And for bookings:

JSON

{ "data": { "user_id": "icu_...", "booking_id": "bok_..." } }

Opening the assistant

When opening the assistant, you just need to call the openDuffelAssistant function with the client key generated for the user and resource pair.

React

openDuffelAssistant({ clientKey: '...' })
If the issue type for which your user is seeking help is already known, You may specify it with the issueType parameter. Allowed values are *cancellation*, *change* or *other*.

React

openDuffelAssistant({ clientKey: '...', issueType: 'other' })
When no issue type is specified the UI will prompt the user for one. When the assistant is open with an issue type, a travel consultant will be immediately notified and a support case will be opened.

Content Security Policy

By explicitly specifying trusted sources (script-src, style-src, img-src, frame-src, connect-src), the CSP ensures only required resources are loaded from trusted domains, including Duffel's assets, chat provider(Stream)'s chat APIs, and WebSocket endpoints. It restricts unnecessary connections and prevents unauthorized scripts or assets from running, thereby safeguarding the website and its users.
DirectiveURLReason
script-srchttps://assets.duffel.comLoad Duffel Assistant's custom JavaScript file.
style-srchttps://assets.duffel.comLoad Duffel Assistant's custom CSS for the Assistant component.
style-srchttps://cdn.jsdelivr.netLoad CSS styles for the chat provider (Stream)'s React components.
frame-srchttps://assets.duffel.comEmbed the Duffel Assistant iframe in the page.
connect-srchttps://api.duffel.comEnable HTTP requests made by the Duffel Assistant iframe.
connect-srchttps://chat.stream-io-api.comAllow HTTP requests for chat functionalities via chat provider's API.
connect-srcwss://chat.stream-io-api.com/connectAllow WebSocket connections for real-time chat updates.
img-srchttps://dublin.stream-io-cdn.comLoad image and file assets for the chat service.
default-src'self'Restrict loading of all other resources to the same origin by default.