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
Quick start
Load script
Include the following script tag on your site
HTML
<scripttype="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.tsimport express from 'express'import { readFile } from 'fs/promises'import { dirname, resolve } from 'path'const app = express()const port = 3000const DUFFEL_API_TOKEN = '' // TODO: Add your API token hereconst USER_ID = '' // TODO: Add your user ID hereconst 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 userconst componentClientKey = await getComponentClientKey(USER_ID)const template = await getHTML()res.writeHead(200)// STEP 2: Share the client key with your front-endres.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 --><scripttype="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 assistantopenDuffelAssistant({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.
Directive | URL | Reason |
---|---|---|
script-src | https://assets.duffel.com | Load Duffel Assistant's custom JavaScript file. |
style-src | https://assets.duffel.com | Load Duffel Assistant's custom CSS for the Assistant component. |
style-src | https://cdn.jsdelivr.net | Load CSS styles for the chat provider (Stream)'s React components. |
frame-src | https://assets.duffel.com | Embed the Duffel Assistant iframe in the page. |
connect-src | https://api.duffel.com | Enable HTTP requests made by the Duffel Assistant iframe. |
connect-src | https://chat.stream-io-api.com | Allow HTTP requests for chat functionalities via chat provider's API. |
connect-src | wss://chat.stream-io-api.com/connect | Allow WebSocket connections for real-time chat updates. |
img-src | https://dublin.stream-io-cdn.com | Load image and file assets for the chat service. |
default-src | 'self' | Restrict loading of all other resources to the same origin by default. |