<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Making Chatbots]]></title><description><![CDATA[Sharing solutions for improving contact centers]]></description><link>https://makingchatbots.com</link><image><url>https://substackcdn.com/image/fetch/$s_!j11O!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d5e836a-dcf7-45fb-801d-d2360daa87a8_512x512.png</url><title>Making Chatbots</title><link>https://makingchatbots.com</link></image><generator>Substack</generator><lastBuildDate>Sun, 19 Apr 2026 08:26:38 GMT</lastBuildDate><atom:link href="https://makingchatbots.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Lucas Woodward]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[makingchatbots@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[makingchatbots@substack.com]]></itunes:email><itunes:name><![CDATA[Lucas Woodward]]></itunes:name></itunes:owner><itunes:author><![CDATA[Lucas Woodward]]></itunes:author><googleplay:owner><![CDATA[makingchatbots@substack.com]]></googleplay:owner><googleplay:email><![CDATA[makingchatbots@substack.com]]></googleplay:email><googleplay:author><![CDATA[Lucas Woodward]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Experimental Genesys Cloud & Gemini Live customer journey]]></title><description><![CDATA[I&#8217;ve been playing around with building a realtime video AI agent with Google&#8217;s Gemini Live API, and integrating it into a Genesys Cloud chatbot journey.]]></description><link>https://makingchatbots.com/p/experimental-genesys-cloud-and-gemini</link><guid isPermaLink="false">https://makingchatbots.com/p/experimental-genesys-cloud-and-gemini</guid><dc:creator><![CDATA[Lucas Woodward]]></dc:creator><pubDate>Thu, 12 Mar 2026 00:03:38 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/af05ad10-63ba-4cdf-9b39-30e693a801bb_1014x718.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I&#8217;ve been playing around with building a realtime video AI agent with Google&#8217;s Gemini Live API, and integrating it into a Genesys Cloud chatbot journey. In this article I want to share how it works, and the considerations for implementing something similar yourself.</p><p>Let&#8217;s start with the concept and then look at how it turned out. Afterwards, I&#8217;ll take you through the nitty-gritty of how it all works, and the various trade-offs.</p><h2>The concept</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!PazD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04499632-3bb2-4973-99a4-d8fcf2412876_1080x759.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!PazD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04499632-3bb2-4973-99a4-d8fcf2412876_1080x759.png 424w, https://substackcdn.com/image/fetch/$s_!PazD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04499632-3bb2-4973-99a4-d8fcf2412876_1080x759.png 848w, https://substackcdn.com/image/fetch/$s_!PazD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04499632-3bb2-4973-99a4-d8fcf2412876_1080x759.png 1272w, https://substackcdn.com/image/fetch/$s_!PazD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04499632-3bb2-4973-99a4-d8fcf2412876_1080x759.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!PazD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04499632-3bb2-4973-99a4-d8fcf2412876_1080x759.png" width="1080" height="759" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/04499632-3bb2-4973-99a4-d8fcf2412876_1080x759.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:759,&quot;width&quot;:1080,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:390468,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/177387759?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04499632-3bb2-4973-99a4-d8fcf2412876_1080x759.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!PazD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04499632-3bb2-4973-99a4-d8fcf2412876_1080x759.png 424w, https://substackcdn.com/image/fetch/$s_!PazD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04499632-3bb2-4973-99a4-d8fcf2412876_1080x759.png 848w, https://substackcdn.com/image/fetch/$s_!PazD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04499632-3bb2-4973-99a4-d8fcf2412876_1080x759.png 1272w, https://substackcdn.com/image/fetch/$s_!PazD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04499632-3bb2-4973-99a4-d8fcf2412876_1080x759.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The journey is for my fictional Bookshop. When a customer wants to sell their books they&#8217;re offered the ability to talk to a realtime audio/video AI Assistant that will:</p><ol><li><p>Scan their books</p></li><li><p>Quote the amount my library is willing to pay for them</p></li><li><p>Create a list of the books</p></li></ol><p>Afterwards they can then continue their chat-based journey with the chosen books.</p><h2>The Result</h2><p>After many evenings of playing around with Genesys Cloud, Gemini Live API and Agent Development Kit the result was the following:</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;1581383e-e07f-4567-ae9f-4677f534b61b&quot;,&quot;duration&quot;:null}"></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://makingchatbots.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Intrigued by what I create next? Subscribe :D</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>How it works</h2><p>What you observed in the video can be broken into 2 concepts:</p><ol><li><p>AI Video Assistant</p></li><li><p>Integrating it with a Genesys Cloud Digital Chatbot journey</p></li></ol><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ybpO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ee8b836-9aa4-4cfe-a994-361daecbdb9e_1039x765.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ybpO!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ee8b836-9aa4-4cfe-a994-361daecbdb9e_1039x765.png 424w, https://substackcdn.com/image/fetch/$s_!ybpO!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ee8b836-9aa4-4cfe-a994-361daecbdb9e_1039x765.png 848w, https://substackcdn.com/image/fetch/$s_!ybpO!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ee8b836-9aa4-4cfe-a994-361daecbdb9e_1039x765.png 1272w, https://substackcdn.com/image/fetch/$s_!ybpO!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ee8b836-9aa4-4cfe-a994-361daecbdb9e_1039x765.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ybpO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ee8b836-9aa4-4cfe-a994-361daecbdb9e_1039x765.png" width="1039" height="765" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6ee8b836-9aa4-4cfe-a994-361daecbdb9e_1039x765.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:765,&quot;width&quot;:1039,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:455361,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/177387759?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ee8b836-9aa4-4cfe-a994-361daecbdb9e_1039x765.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ybpO!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ee8b836-9aa4-4cfe-a994-361daecbdb9e_1039x765.png 424w, https://substackcdn.com/image/fetch/$s_!ybpO!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ee8b836-9aa4-4cfe-a994-361daecbdb9e_1039x765.png 848w, https://substackcdn.com/image/fetch/$s_!ybpO!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ee8b836-9aa4-4cfe-a994-361daecbdb9e_1039x765.png 1272w, https://substackcdn.com/image/fetch/$s_!ybpO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ee8b836-9aa4-4cfe-a994-361daecbdb9e_1039x765.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>I will start with AI at the core of this journey, then cover how it integrates into the Genesys Cloud flow. </p><h2>Creating the Live Agent with Google ADK</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!prve!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2e2d6ee-6390-46a7-840b-4dc83f04e632_1039x765.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!prve!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2e2d6ee-6390-46a7-840b-4dc83f04e632_1039x765.png 424w, https://substackcdn.com/image/fetch/$s_!prve!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2e2d6ee-6390-46a7-840b-4dc83f04e632_1039x765.png 848w, https://substackcdn.com/image/fetch/$s_!prve!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2e2d6ee-6390-46a7-840b-4dc83f04e632_1039x765.png 1272w, https://substackcdn.com/image/fetch/$s_!prve!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2e2d6ee-6390-46a7-840b-4dc83f04e632_1039x765.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!prve!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2e2d6ee-6390-46a7-840b-4dc83f04e632_1039x765.png" width="1039" height="765" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d2e2d6ee-6390-46a7-840b-4dc83f04e632_1039x765.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:765,&quot;width&quot;:1039,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:398563,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/177387759?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2e2d6ee-6390-46a7-840b-4dc83f04e632_1039x765.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!prve!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2e2d6ee-6390-46a7-840b-4dc83f04e632_1039x765.png 424w, https://substackcdn.com/image/fetch/$s_!prve!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2e2d6ee-6390-46a7-840b-4dc83f04e632_1039x765.png 848w, https://substackcdn.com/image/fetch/$s_!prve!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2e2d6ee-6390-46a7-840b-4dc83f04e632_1039x765.png 1272w, https://substackcdn.com/image/fetch/$s_!prve!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2e2d6ee-6390-46a7-840b-4dc83f04e632_1039x765.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The crux of this CX journey is leveraging two of Google&#8217;s technologies:</p><ul><li><p><a href="https://docs.cloud.google.com/vertex-ai/generative-ai/docs/live-api">Gemini Live API</a> which allows low-latency, real-time voice and video interactions with Gemini Live</p></li><li><p><a href="https://google.github.io/adk-docs/">Google Agent Development Kit</a> which is a modular framework for the development, evaluation and deployment of AI agents</p></li></ul><p>This solution was built around a single AI Agent, which we&#8217;ll look at more closely.</p><h3>Book Pricing Agent</h3><p>The Book Pricing Agent is designed to:</p><ul><li><p>Identify customer books by scanning their barcode</p></li><li><p>Fetch a price we&#8217;d offer for the book</p></li><li><p>Maintain a list of books the customer confirmed they&#8217;d sell</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tVcp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae5ee3a-2b78-4425-a3a3-356ab217b859_1177x228.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tVcp!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae5ee3a-2b78-4425-a3a3-356ab217b859_1177x228.png 424w, https://substackcdn.com/image/fetch/$s_!tVcp!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae5ee3a-2b78-4425-a3a3-356ab217b859_1177x228.png 848w, https://substackcdn.com/image/fetch/$s_!tVcp!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae5ee3a-2b78-4425-a3a3-356ab217b859_1177x228.png 1272w, https://substackcdn.com/image/fetch/$s_!tVcp!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae5ee3a-2b78-4425-a3a3-356ab217b859_1177x228.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tVcp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae5ee3a-2b78-4425-a3a3-356ab217b859_1177x228.png" width="1177" height="228" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3ae5ee3a-2b78-4425-a3a3-356ab217b859_1177x228.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:228,&quot;width&quot;:1177,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:71029,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/177387759?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae5ee3a-2b78-4425-a3a3-356ab217b859_1177x228.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!tVcp!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae5ee3a-2b78-4425-a3a3-356ab217b859_1177x228.png 424w, https://substackcdn.com/image/fetch/$s_!tVcp!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae5ee3a-2b78-4425-a3a3-356ab217b859_1177x228.png 848w, https://substackcdn.com/image/fetch/$s_!tVcp!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae5ee3a-2b78-4425-a3a3-356ab217b859_1177x228.png 1272w, https://substackcdn.com/image/fetch/$s_!tVcp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae5ee3a-2b78-4425-a3a3-356ab217b859_1177x228.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>The definition of the Agent shows its instruction and tooling:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">root_agent = Agent(
        name="coordinator_agent",
        model="gemini-live-2.5-flash-preview-native-audio-09-2025",
        instruction="""
You are an AI assistant for a library. Your purpose is to help customers who want to sell their books.

Your primary tasks are:
1.  Identify books by having the customer show you the barcode to scan
2.  Once a book is identified, tell the customer the book&#8217;s title and what the shop will offer for it.
3.  Keep a list of the books the customer wants to sell. You can add or remove books from this list based on the customer&#8217;s request.
4.  When the customer is ready, you will hand them back to a text-based chatbot to finalise the sale.

Important rules for your behaviour:
-   Always be helpful and professional.
-   When a book is scanned, refer to it by its title. Do not read out the ISBN or barcode number, and do not ask the customer to confirm it.
-   Use your tools to remember which books the customer wants to sell.
-   When the conversation is over, use the &#8216;transfer_conversation&#8217; tool.
    """,
    tools=[
        # Scans the barcodes from video frames and returns book details
        scan_barcode,

        # Tools for remembering books
        remember_book_customer_is_selling,
        forget_book_customer_is_selling,
        retrieve_books_customer_is_selling,

        # End the conversation and transfer to Genesys Cloud
        transfer_conversation,
    ],
)</code></pre></div><p>The tooling at the bottom of the definition is what the agent can use during a conversation to achieve its goal. They are&#8230;</p><h4>Barcode scanning tool</h4><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8jfF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45b81941-ae56-4f70-874a-b8a1fbf78247_1177x228.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8jfF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45b81941-ae56-4f70-874a-b8a1fbf78247_1177x228.png 424w, https://substackcdn.com/image/fetch/$s_!8jfF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45b81941-ae56-4f70-874a-b8a1fbf78247_1177x228.png 848w, https://substackcdn.com/image/fetch/$s_!8jfF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45b81941-ae56-4f70-874a-b8a1fbf78247_1177x228.png 1272w, https://substackcdn.com/image/fetch/$s_!8jfF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45b81941-ae56-4f70-874a-b8a1fbf78247_1177x228.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8jfF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45b81941-ae56-4f70-874a-b8a1fbf78247_1177x228.png" width="1177" height="228" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/45b81941-ae56-4f70-874a-b8a1fbf78247_1177x228.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:228,&quot;width&quot;:1177,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:71776,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/177387759?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45b81941-ae56-4f70-874a-b8a1fbf78247_1177x228.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!8jfF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45b81941-ae56-4f70-874a-b8a1fbf78247_1177x228.png 424w, https://substackcdn.com/image/fetch/$s_!8jfF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45b81941-ae56-4f70-874a-b8a1fbf78247_1177x228.png 848w, https://substackcdn.com/image/fetch/$s_!8jfF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45b81941-ae56-4f70-874a-b8a1fbf78247_1177x228.png 1272w, https://substackcdn.com/image/fetch/$s_!8jfF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45b81941-ae56-4f70-874a-b8a1fbf78247_1177x228.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>The Gemini Live Flash model that the Agent is using is multimodal, so can understand what it is seeing as well as hearing. But it cannot read barcodes. So I had to create a tool for it detect and read the barcodes in the video frames it was receiving.</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;a34d4766-c10d-4ed2-b59a-77ebaffe4c8d&quot;,&quot;duration&quot;:null}"></div><p>The video above shows a simplified view of the solution I created, which is to give the Agent a tool that when called will process the past 3 seconds worth of video frames to extract the ISBN from a barcode. It then searches for the relevant book&#8217;s details.</p><p>It works like this:</p><ol><li><p>Agent&#8217;s multimodal model determines it is being shown a book</p></li><li><p>Agent calls the Scan Barcode tool</p></li><li><p>Scan Barcode tool with its access to last 3 seconds worth of video frames will:</p><ol><li><p>Send frames to my Barcode Scanner Service, which returns the ISBN encoded in the barcode</p></li><li><p>Queries ISBN against <a href="https://developers.google.com/books">Google&#8217;s Books API</a> to get details about the book</p></li><li><p>Calls the Book API to get a price my fictional library would pay for it</p></li></ol></li><li><p>Scan Barcode tool returns to the Agent the ISBN, book&#8217;s details and an offer price</p></li></ol><p>Excerpt of the Scan Barcode tool&#8217;s code:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">async def scan_barcode() -&gt; dict:
    """Returns information about a book based on its barcode.

       This tool reads from a buffer of recent video frames
       to find a barcode.
    """
    if not frame_buffer:
        return {"status": "Cannot read barcode."}

    frames = list(frame_buffer)
    tasks = [
        # Function below:
        # 1. Sends frame to Barcode Scanner API
        # 2. Searches for book details for ISBN in barcode
        _scan_frame_and_search_by_isbn(frame,
                                       video_frame_barcode_scanner,
                                       isbn_book_searcher)
        for frame in frames
    ]
    results = await asyncio.gather(*tasks)
    
    # ...
    
    matching_books = [
        {
            "isbn": b.isbn,
            "title": b.title,
            "authors": b.authors,
            "offerPrice": book_pricer.formatted_offer_price(b.isbn),
        }
        for b in deduped_books.values()
    ]

    return {"matching_books": matching_books} </code></pre></div><p>Originally, I&#8217;d relied on the browser&#8217;s native <a href="https://developer.mozilla.org/en-US/docs/Web/API/Barcode_Detection_API">Barcode Detection API</a> - as I&#8217;d <a href="https://www.linkedin.com/posts/lucas-woodward-the-dev_googlegemini-gemini-ai-activity-7383263424652259328-tddu?utm_source=share&amp;utm_medium=member_desktop&amp;rcm=ACoAABsbo2wBcmnNqxYJ5UO9BrsfURZcVEtgLOU">shared on LinkedIn</a>. However, it was only when I got an iPhone that I realised this API isn&#8217;t widely supported (<a href="https://bugs.webkit.org/show_bug.cgi?id=281848">nor working</a>).</p><h4>Memory tool</h4><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!J9Ze!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8703c992-aec7-4698-acc1-a45a92a8bc96_1177x228.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!J9Ze!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8703c992-aec7-4698-acc1-a45a92a8bc96_1177x228.png 424w, https://substackcdn.com/image/fetch/$s_!J9Ze!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8703c992-aec7-4698-acc1-a45a92a8bc96_1177x228.png 848w, https://substackcdn.com/image/fetch/$s_!J9Ze!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8703c992-aec7-4698-acc1-a45a92a8bc96_1177x228.png 1272w, https://substackcdn.com/image/fetch/$s_!J9Ze!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8703c992-aec7-4698-acc1-a45a92a8bc96_1177x228.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!J9Ze!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8703c992-aec7-4698-acc1-a45a92a8bc96_1177x228.png" width="728" height="141.02293967714527" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8703c992-aec7-4698-acc1-a45a92a8bc96_1177x228.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:228,&quot;width&quot;:1177,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:68064,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/177387759?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8703c992-aec7-4698-acc1-a45a92a8bc96_1177x228.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!J9Ze!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8703c992-aec7-4698-acc1-a45a92a8bc96_1177x228.png 424w, https://substackcdn.com/image/fetch/$s_!J9Ze!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8703c992-aec7-4698-acc1-a45a92a8bc96_1177x228.png 848w, https://substackcdn.com/image/fetch/$s_!J9Ze!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8703c992-aec7-4698-acc1-a45a92a8bc96_1177x228.png 1272w, https://substackcdn.com/image/fetch/$s_!J9Ze!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8703c992-aec7-4698-acc1-a45a92a8bc96_1177x228.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>ADK does have a mechanism for memory, but I wanted the memory to be specific to the books being sold, and to have it drive the UI. What I came up with was a memory that consists of three tools:</p><ul><li><p><code>remember_book_customer_is_selling(isbn: str)</code></p><ul><li><p>Saves book information and offer price by ISBN</p></li><li><p>Sends event to UI to add book to &#8216;Books to sell&#8216; section</p></li></ul></li><li><p><code>forget_book_customer_is_selling(isbn: str)</code></p><ul><li><p>Removes book from memory by ISBN</p></li><li><p>Sends event to UI to remove book from &#8216;Books to sell&#8216; section</p></li></ul></li><li><p> <code>retrieve_books_customer_is_selling()-&gt; List[Book]</code></p><ul><li><p>Retrieves all books customer is selling, with offer price totalled</p></li></ul></li></ul><p>This is what the UI looks like when the customer agrees on a book to sell:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!fjEj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F585d7fc5-91b0-4b49-b023-9235e94c803a_460x417.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!fjEj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F585d7fc5-91b0-4b49-b023-9235e94c803a_460x417.gif 424w, https://substackcdn.com/image/fetch/$s_!fjEj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F585d7fc5-91b0-4b49-b023-9235e94c803a_460x417.gif 848w, https://substackcdn.com/image/fetch/$s_!fjEj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F585d7fc5-91b0-4b49-b023-9235e94c803a_460x417.gif 1272w, https://substackcdn.com/image/fetch/$s_!fjEj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F585d7fc5-91b0-4b49-b023-9235e94c803a_460x417.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!fjEj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F585d7fc5-91b0-4b49-b023-9235e94c803a_460x417.gif" width="460" height="417" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/585d7fc5-91b0-4b49-b023-9235e94c803a_460x417.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:417,&quot;width&quot;:460,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:950897,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/177387759?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F585d7fc5-91b0-4b49-b023-9235e94c803a_460x417.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!fjEj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F585d7fc5-91b0-4b49-b023-9235e94c803a_460x417.gif 424w, https://substackcdn.com/image/fetch/$s_!fjEj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F585d7fc5-91b0-4b49-b023-9235e94c803a_460x417.gif 848w, https://substackcdn.com/image/fetch/$s_!fjEj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F585d7fc5-91b0-4b49-b023-9235e94c803a_460x417.gif 1272w, https://substackcdn.com/image/fetch/$s_!fjEj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F585d7fc5-91b0-4b49-b023-9235e94c803a_460x417.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">UI is updated based on Agent&#8217;s memory of books customer wants to sell</figcaption></figure></div><h4>Transfer to Chatbot tool</h4><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GF3Z!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbeb10106-ac18-4016-a3c7-f1c6601cf1d2_1177x228.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GF3Z!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbeb10106-ac18-4016-a3c7-f1c6601cf1d2_1177x228.png 424w, https://substackcdn.com/image/fetch/$s_!GF3Z!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbeb10106-ac18-4016-a3c7-f1c6601cf1d2_1177x228.png 848w, https://substackcdn.com/image/fetch/$s_!GF3Z!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbeb10106-ac18-4016-a3c7-f1c6601cf1d2_1177x228.png 1272w, https://substackcdn.com/image/fetch/$s_!GF3Z!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbeb10106-ac18-4016-a3c7-f1c6601cf1d2_1177x228.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GF3Z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbeb10106-ac18-4016-a3c7-f1c6601cf1d2_1177x228.png" width="728" height="141.02293967714527" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/beb10106-ac18-4016-a3c7-f1c6601cf1d2_1177x228.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:228,&quot;width&quot;:1177,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:68186,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/177387759?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbeb10106-ac18-4016-a3c7-f1c6601cf1d2_1177x228.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!GF3Z!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbeb10106-ac18-4016-a3c7-f1c6601cf1d2_1177x228.png 424w, https://substackcdn.com/image/fetch/$s_!GF3Z!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbeb10106-ac18-4016-a3c7-f1c6601cf1d2_1177x228.png 848w, https://substackcdn.com/image/fetch/$s_!GF3Z!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbeb10106-ac18-4016-a3c7-f1c6601cf1d2_1177x228.png 1272w, https://substackcdn.com/image/fetch/$s_!GF3Z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbeb10106-ac18-4016-a3c7-f1c6601cf1d2_1177x228.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>The last tool to be called is <code>transfer_conversation</code>. This tool allows the Agent to  transfer control back to Genesys Cloud.</p><p>When this tool is called it causes the My API to instruct the front-end to replace the AI Assistant UI with the Web Messenger chat UI - covered more in the next section.</p><h2>Integrating with Genesys Cloud</h2><p>Now that we have covered the AI Video Assistant let&#8217;s look at how we integrate it into a Digital Chatbot in Genesys Cloud&#8217;s Web Messenger.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tTnZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58be6026-a02e-42a8-8fa3-6662e9ff2e77_1039x765.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tTnZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58be6026-a02e-42a8-8fa3-6662e9ff2e77_1039x765.png 424w, https://substackcdn.com/image/fetch/$s_!tTnZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58be6026-a02e-42a8-8fa3-6662e9ff2e77_1039x765.png 848w, https://substackcdn.com/image/fetch/$s_!tTnZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58be6026-a02e-42a8-8fa3-6662e9ff2e77_1039x765.png 1272w, https://substackcdn.com/image/fetch/$s_!tTnZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58be6026-a02e-42a8-8fa3-6662e9ff2e77_1039x765.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tTnZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58be6026-a02e-42a8-8fa3-6662e9ff2e77_1039x765.png" width="1039" height="765" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/58be6026-a02e-42a8-8fa3-6662e9ff2e77_1039x765.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:765,&quot;width&quot;:1039,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:349194,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/177387759?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58be6026-a02e-42a8-8fa3-6662e9ff2e77_1039x765.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!tTnZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58be6026-a02e-42a8-8fa3-6662e9ff2e77_1039x765.png 424w, https://substackcdn.com/image/fetch/$s_!tTnZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58be6026-a02e-42a8-8fa3-6662e9ff2e77_1039x765.png 848w, https://substackcdn.com/image/fetch/$s_!tTnZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58be6026-a02e-42a8-8fa3-6662e9ff2e77_1039x765.png 1272w, https://substackcdn.com/image/fetch/$s_!tTnZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58be6026-a02e-42a8-8fa3-6662e9ff2e77_1039x765.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>There are two sides to this interaction:</p><ol><li><p>The customer is transferred from a Digital Chatbot Flow to the AI Assistant</p></li><li><p>The AI Assistant transfers the customer back to the Digital Chatbot Flow</p></li></ol><p>Both sides are built to be resilient to failures.</p><h3>Transferring to the AI Assistant</h3><p>The customer starts their journey in Genesys Cloud&#8217;s <a href="https://developer.genesys.cloud/commdigital/digital/webmessaging/#messenger">Web Messenger UI</a>, but even before they send their first message something important has happened...</p><p>The customer&#8217;s browser establishes a Websocket connection with My API, and associates that connection to a Customer&#8217;s Journey Session ID. This means two things:</p><ol><li><p>The browser and My API have a bidirectional connection outside of the chat</p></li><li><p>My API has associated the customer&#8217;s browser with an ID that an Architect Flow also knows, allowing a flow to send messages to My API via a Data Action and have them forwarded to the customer&#8217;s browser </p></li></ol><p>This is how it works:</p><ol><li><p>The Customer Journey Session ID for the conversation is retrieved using the <a href="https://developer.genesys.cloud/commdigital/digital/webmessaging/messengersdk/">Messenger JavaScript SDK</a>:</p></li></ol><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;javascript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-javascript">const channel = new BroadcastChannel("genesys-cloud-agent");

Genesys('subscribe', 'MessagingService.ready', () =&gt; {
    Genesys('subscribe', 'Conversations.started', function (event) {
        const journeySessionId = event?.data?.journeyContext?.customerSession?.id;
        
        channel.postMessage({
            type: "conversation_started",
            customerSessionId
        });
    });
});</code></pre></div><ol start="2"><li><p>This ID is then used in the URL when establishing the WebSocket connection:</p></li></ol><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;javascript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-javascript">const channel = new BroadcastChannel("genesys-cloud-agent");

channel.addEventListener("message", async (event) =&gt; {
    const messageType = event.data.type;
    switch (messageType) {
        case "conversation_started":
            //...
            connectToServer(event.data.customerSessionId);
            break;
        //...
    }
})

function connectToServer(customerJourneyId) {
    const websocket = new WebSocket(`wss://${serverUrl}/ws/${customerJourneyId}`);
    //...
}</code></pre></div><p>When the Digital Chatbot flow wants to switch the customer&#8217;s UI to the AI Assistant it simply calls the relevant Data Action with the Customer Journey Session ID that the upstream Inbound Message flow passed to it.</p><p>Why a Customer Journey Session ID instead of the Conversation ID? Well, I was unable get the Conversation ID from the Messenger SDK. Do let me know if you know of a way&#8230;</p><h3>Transferring back to the Digital Chatbot flow</h3><p>I chose a different approach when transferring from the AI Assistant back to the chat:</p><ol><li><p>Just after transferring the customer to the AI Assistant the Digital Chatbot sends a Quick Response message to the minimised chat window, asking if the customer has finished with the AI Assistant</p></li><li><p>When the AI Assistant has finished it calls the Transfer tool. This results in a command being sent to the customer&#8217;s browser.</p></li><li><p>The client-side code then:</p><ol><li><p>Closes the AI Assistant UI</p></li><li><p>Maximises the Web Messenger UI</p></li><li><p>Resumes the conversation by using the <a href="https://developer.genesys.cloud/commdigital/digital/webmessaging/messengersdk/SDKCommandsEvents/messagingServicePlugin#messagingservice-sendmessage">SendMessage command</a> to response to the Quick Reply in step 1</p></li></ol></li></ol><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;javascript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-javascript">function continueConversation(){
    Genesys('command',
        'MessagingService.sendMessage',
        {message: 'Finished'},
        (data) =&gt; { /* ... */ },
        (error) =&gt; { /* ... */ }
    );
}</code></pre></div><p>This approach allows the customer to continue the conversation should the AI Assistant fail unexpectedly, and avoids any awkward polling of My API in the Architect flow.</p><h2>Considerations</h2><p>As with any solution, there are considerations you have to take into account. Here are 3 of the biggest with this solution.</p><h3>Data split between multiple systems</h3><p>Joining different systems may allow you to leverage the latest and greatest functionality, but unless these systems are closely integrated you&#8217;ll end up with data pertaining to a customer&#8217;s journey existing across them.</p><p>In this case the AI Assistant is completely separate to Genesys Cloud, so the conversation is not included in the Genesys Cloud&#8217;s transcript, nor included in any <a href="https://help.genesys.cloud/articles/speech-and-text-analytics-overview/">Speech and Text Analytics</a>.</p><h3>A2A will be a better way to integrate</h3><p>With <a href="https://www.genesys.com/en-gb/company/newsroom/announcements/genesys-launches-ai-agents-with-greater-autonomy-to-drive-enterprise-wide-customer-experience-orchestration">Genesys Cloud investing in Agentic CX</a>, and Google investing heavily in their Agent Development Kit (ADK), one hopes it is only a matter of time until both platforms can be integrated over the <a href="https://a2a-protocol.org/">Agent2Agent protocol</a>.</p><p>However, at the time of creating this experiment A2A could not be used to integrate the two. Which explains the complexity needed in transferring between the systems.</p><p>When A2A is widely available I foresee marketplaces of specialised agents that can be leveraged for specific parts of a customer&#8217;s journey.</p><p>The result would be highly specialised agents all working together to deliver for a customer.</p><h3>Safety</h3><p>We&#8217;ve all heard the horror stories of freshly implemented AI chatbots running amok with a company&#8217;s reputation. So ensuring any AI Assistant is bounded to a particular task, grounded, extensively evaluated and restricted by sufficient guardrails is a must.</p><p>The Gemini Live API, which was freshly out of GA at the time of implementing this solution cannot be used with <a href="https://cloud.google.com/security/products/model-armor">Google&#8217;s Model Armor</a>, and I was unable to find any mature third-party guardrail solutions compatible with the Live API&#8217;s streaming architecture.</p><p>There is also little in way of evaluations that simulate audio/video to test an agent&#8217;s performance using the Gemini Live model. You can get part the way there though by switching to a text-based model to evaluate the reasoning part of the agent. </p><p>Anecdotally, the model did a great job of refusing to diverge from its task.</p><h2>Conclusion</h2><p>This project has provided a glimpse into what capabilities may be easily integrated into customer journeys of the future. However, for the time being with these two platforms workarounds are required to create a coherent flow.</p><p>Naturally there are also questions around whether this makes for a good CX journey anyway&#8230; I created the journey out of curiosity of the technologies and how they fit together, not based on CX research. But it sure was fun!</p><p>If you have any questions, or have  suggestions on how I can improve the flow please do get in contact.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://makingchatbots.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://makingchatbots.com/subscribe?"><span>Subscribe now</span></a></p>]]></content:encoded></item><item><title><![CDATA[Automating Genesys Cloud with n8n]]></title><description><![CDATA[I have created an open-source n8n Genesys Cloud community node, which allows you to leverage n8n, one of the world&#8217;s leading workflow automation platforms.]]></description><link>https://makingchatbots.com/p/automating-genesys-cloud-with-n8n</link><guid isPermaLink="false">https://makingchatbots.com/p/automating-genesys-cloud-with-n8n</guid><dc:creator><![CDATA[Lucas Woodward]]></dc:creator><pubDate>Tue, 27 Jan 2026 23:50:56 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/0ae5eb83-1a8c-41c6-84eb-9af41fb08fed_854x605.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Genesys Cloud&#8217;s user interface allows you to do an awful lot, and for what it can&#8217;t yet do you have their Platform API. However, leveraging the Platform API requires writing code to handle retry mechanisms, rate-limits, pagination etc. All of which can be quite daunting. But not anymore!</p><p>I have created an <a href="https://github.com/MakingChatbots/n8n-nodes-genesys-cloud">open-source n8n Genesys Cloud community node</a>. It allows you to leverage n8n, one of the world&#8217;s leading workflow automation platforms to easily create workflows that interact with Genesys Cloud to do tasks such as:</p><ul><li><p>Generating custom reports</p></li><li><p>Automating user provisioning / syncing between environments</p></li><li><p>Auditing user permissions</p></li><li><p>Triggering alerting</p></li><li><p>and much more&#8230;</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!WSfV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fecc719e8-d6d8-4abb-9c42-88628c647741_2178x956.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!WSfV!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fecc719e8-d6d8-4abb-9c42-88628c647741_2178x956.png 424w, https://substackcdn.com/image/fetch/$s_!WSfV!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fecc719e8-d6d8-4abb-9c42-88628c647741_2178x956.png 848w, https://substackcdn.com/image/fetch/$s_!WSfV!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fecc719e8-d6d8-4abb-9c42-88628c647741_2178x956.png 1272w, https://substackcdn.com/image/fetch/$s_!WSfV!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fecc719e8-d6d8-4abb-9c42-88628c647741_2178x956.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!WSfV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fecc719e8-d6d8-4abb-9c42-88628c647741_2178x956.png" width="1456" height="639" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ecc719e8-d6d8-4abb-9c42-88628c647741_2178x956.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:639,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:196136,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/184357306?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fecc719e8-d6d8-4abb-9c42-88628c647741_2178x956.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!WSfV!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fecc719e8-d6d8-4abb-9c42-88628c647741_2178x956.png 424w, https://substackcdn.com/image/fetch/$s_!WSfV!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fecc719e8-d6d8-4abb-9c42-88628c647741_2178x956.png 848w, https://substackcdn.com/image/fetch/$s_!WSfV!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fecc719e8-d6d8-4abb-9c42-88628c647741_2178x956.png 1272w, https://substackcdn.com/image/fetch/$s_!WSfV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fecc719e8-d6d8-4abb-9c42-88628c647741_2178x956.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">n8n workflow using Genesys Cloud actions</figcaption></figure></div><h2>What is n8n</h2><p>For those who haven&#8217;t heard of <a href="https://n8n.io/">n8n</a>, it is one of the world&#8217;s leading workflow automation platforms. It offers, amongst other things:</p><ul><li><p>An exceedingly simple interface - where you visually connect actions to make a workflow</p></li><li><p>Support for over 1k integrations, and an extensive range of community integrations.</p></li><li><p>An incredibly supportive community</p></li><li><p>The ability to create, maintain, share and execute workflows</p></li></ul><p>Accessing n8n is possible by:</p><ul><li><p><a href="https://docs.n8n.io/hosting/">Hosting n8n yourself</a></p></li><li><p><a href="https://n8n.io/pricing/">Choosing a hosted plan</a></p></li></ul><h2>Creating a demonstration workflow</h2><p>As always, let&#8217;s learn by doing&#8230;</p><p>We&#8217;ll use <a href="https://www.npmjs.com/package/@makingchatbots/n8n-nodes-genesys-cloud">the Genesys Cloud community node</a> to create a workflow that reports on User&#8217;s roles, Skills, Groups &amp; Queues in your organisation. At the end we&#8217;ll then touch on how it could be extended to include data from the likes of Salesforce, MS Dynamics CRM 365, Zendesk etc</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Z1Jf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36275909-557c-40df-a750-b59cce2c87d2_5141x778.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Z1Jf!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36275909-557c-40df-a750-b59cce2c87d2_5141x778.png 424w, https://substackcdn.com/image/fetch/$s_!Z1Jf!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36275909-557c-40df-a750-b59cce2c87d2_5141x778.png 848w, https://substackcdn.com/image/fetch/$s_!Z1Jf!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36275909-557c-40df-a750-b59cce2c87d2_5141x778.png 1272w, https://substackcdn.com/image/fetch/$s_!Z1Jf!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36275909-557c-40df-a750-b59cce2c87d2_5141x778.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Z1Jf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36275909-557c-40df-a750-b59cce2c87d2_5141x778.png" width="1456" height="220" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/36275909-557c-40df-a750-b59cce2c87d2_5141x778.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:220,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:380665,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/184357306?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36275909-557c-40df-a750-b59cce2c87d2_5141x778.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!Z1Jf!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36275909-557c-40df-a750-b59cce2c87d2_5141x778.png 424w, https://substackcdn.com/image/fetch/$s_!Z1Jf!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36275909-557c-40df-a750-b59cce2c87d2_5141x778.png 848w, https://substackcdn.com/image/fetch/$s_!Z1Jf!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36275909-557c-40df-a750-b59cce2c87d2_5141x778.png 1272w, https://substackcdn.com/image/fetch/$s_!Z1Jf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36275909-557c-40df-a750-b59cce2c87d2_5141x778.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>The workflow we&#8217;ll create will:</p><ol><li><p>Get all the users in the organisation</p></li><li><p>Get the queues for each of the users</p></li><li><p>Format the data</p></li><li><p>Convert to a CSV</p></li></ol><p>The resulting CSV will contain the User ID, Name, Email, State, Roles, Skills, Groups and Queues of all users.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Y2ij!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba629f9b-d032-4dc1-bede-d1efea1b16aa_2476x248.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Y2ij!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba629f9b-d032-4dc1-bede-d1efea1b16aa_2476x248.png 424w, https://substackcdn.com/image/fetch/$s_!Y2ij!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba629f9b-d032-4dc1-bede-d1efea1b16aa_2476x248.png 848w, https://substackcdn.com/image/fetch/$s_!Y2ij!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba629f9b-d032-4dc1-bede-d1efea1b16aa_2476x248.png 1272w, https://substackcdn.com/image/fetch/$s_!Y2ij!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba629f9b-d032-4dc1-bede-d1efea1b16aa_2476x248.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Y2ij!,w_2400,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba629f9b-d032-4dc1-bede-d1efea1b16aa_2476x248.png" width="1200" height="120.32967032967034" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ba629f9b-d032-4dc1-bede-d1efea1b16aa_2476x248.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;large&quot;,&quot;height&quot;:146,&quot;width&quot;:1456,&quot;resizeWidth&quot;:1200,&quot;bytes&quot;:144856,&quot;alt&quot;:&quot;CSV containing the columns, User ID, Name, Email, State, Roles, Skills, Groups and Queues&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/184357306?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba629f9b-d032-4dc1-bede-d1efea1b16aa_2476x248.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-large" alt="CSV containing the columns, User ID, Name, Email, State, Roles, Skills, Groups and Queues" title="CSV containing the columns, User ID, Name, Email, State, Roles, Skills, Groups and Queues" srcset="https://substackcdn.com/image/fetch/$s_!Y2ij!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba629f9b-d032-4dc1-bede-d1efea1b16aa_2476x248.png 424w, https://substackcdn.com/image/fetch/$s_!Y2ij!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba629f9b-d032-4dc1-bede-d1efea1b16aa_2476x248.png 848w, https://substackcdn.com/image/fetch/$s_!Y2ij!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba629f9b-d032-4dc1-bede-d1efea1b16aa_2476x248.png 1272w, https://substackcdn.com/image/fetch/$s_!Y2ij!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba629f9b-d032-4dc1-bede-d1efea1b16aa_2476x248.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">CSV our workflow will produce</figcaption></figure></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://makingchatbots.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Enjoying the article?</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h3>Installing Genesys Cloud community n8n node</h3><p>Assuming you now have access to n8n, you need to install the Genesys Cloud community node to n8n by:</p><ol><li><p>Expanding the Settings</p></li><li><p>Clicking &#8216;Community nodes&#8217;</p></li><li><p>Clicking &#8216;Install a community node&#8217;</p></li><li><p>Under &#8216;npm Package name&#8216; put <code>@makingchatbots/n8n-nodes-genesys-cloud</code> </p></li><li><p>Check &#8216;I understand the risks&#8230;&#8216;</p></li><li><p>Finally, click Install</p></li></ol><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;0951cb5e-aaee-4075-98a2-8e0f05540612&quot;,&quot;duration&quot;:null}"></div><h3>Creating an OAuth Client</h3><p>I&#8217;ll pre-emptively mention setting up credentials, which you will have to do in the next step. When you add your first action in a minute you will be presented with the &#8216;Credential to connect with&#8217; box in red.  </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!aRww!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb38edc1a-46a1-4072-827c-2417aff6fc63_2308x418.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aRww!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb38edc1a-46a1-4072-827c-2417aff6fc63_2308x418.png 424w, https://substackcdn.com/image/fetch/$s_!aRww!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb38edc1a-46a1-4072-827c-2417aff6fc63_2308x418.png 848w, https://substackcdn.com/image/fetch/$s_!aRww!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb38edc1a-46a1-4072-827c-2417aff6fc63_2308x418.png 1272w, https://substackcdn.com/image/fetch/$s_!aRww!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb38edc1a-46a1-4072-827c-2417aff6fc63_2308x418.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aRww!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb38edc1a-46a1-4072-827c-2417aff6fc63_2308x418.png" width="1456" height="264" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b38edc1a-46a1-4072-827c-2417aff6fc63_2308x418.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:264,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:81292,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/184357306?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb38edc1a-46a1-4072-827c-2417aff6fc63_2308x418.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!aRww!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb38edc1a-46a1-4072-827c-2417aff6fc63_2308x418.png 424w, https://substackcdn.com/image/fetch/$s_!aRww!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb38edc1a-46a1-4072-827c-2417aff6fc63_2308x418.png 848w, https://substackcdn.com/image/fetch/$s_!aRww!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb38edc1a-46a1-4072-827c-2417aff6fc63_2308x418.png 1272w, https://substackcdn.com/image/fetch/$s_!aRww!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb38edc1a-46a1-4072-827c-2417aff6fc63_2308x418.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Add your Genesys Cloud org&#8217;s OAuth Client by:</p><ol><li><p>Clicking the box and selecting &#8216;Create new Credential&#8216;</p></li><li><p>Supplying your OAuth Client&#8217;s ID, Secret and Region </p></li><li><p>Clicking Save</p></li></ol><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!c6VU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F105b565a-92cc-4af1-8737-3ea4ae648e7a_1434x1034.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!c6VU!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F105b565a-92cc-4af1-8737-3ea4ae648e7a_1434x1034.png 424w, https://substackcdn.com/image/fetch/$s_!c6VU!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F105b565a-92cc-4af1-8737-3ea4ae648e7a_1434x1034.png 848w, https://substackcdn.com/image/fetch/$s_!c6VU!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F105b565a-92cc-4af1-8737-3ea4ae648e7a_1434x1034.png 1272w, https://substackcdn.com/image/fetch/$s_!c6VU!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F105b565a-92cc-4af1-8737-3ea4ae648e7a_1434x1034.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!c6VU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F105b565a-92cc-4af1-8737-3ea4ae648e7a_1434x1034.png" width="566" height="408.11994421199444" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/105b565a-92cc-4af1-8737-3ea4ae648e7a_1434x1034.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1034,&quot;width&quot;:1434,&quot;resizeWidth&quot;:566,&quot;bytes&quot;:115035,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/184357306?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F105b565a-92cc-4af1-8737-3ea4ae648e7a_1434x1034.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!c6VU!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F105b565a-92cc-4af1-8737-3ea4ae648e7a_1434x1034.png 424w, https://substackcdn.com/image/fetch/$s_!c6VU!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F105b565a-92cc-4af1-8737-3ea4ae648e7a_1434x1034.png 848w, https://substackcdn.com/image/fetch/$s_!c6VU!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F105b565a-92cc-4af1-8737-3ea4ae648e7a_1434x1034.png 1272w, https://substackcdn.com/image/fetch/$s_!c6VU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F105b565a-92cc-4af1-8737-3ea4ae648e7a_1434x1034.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>Retrieve users and their assigned queues</h3><p>We start the creation of the flow by attaching two Actions to a <a href="https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.scheduletrigger/">Schedule Trigger node</a>:</p><ol><li><p>Get many users - returns all users in the Genesys Cloud org</p></li><li><p>Get queues for a user - for each user return all their assigned queues</p></li></ol><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xjfz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2fd2755-d051-43c8-8da3-3d602b054bb0_5141x778.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xjfz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2fd2755-d051-43c8-8da3-3d602b054bb0_5141x778.png 424w, https://substackcdn.com/image/fetch/$s_!xjfz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2fd2755-d051-43c8-8da3-3d602b054bb0_5141x778.png 848w, https://substackcdn.com/image/fetch/$s_!xjfz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2fd2755-d051-43c8-8da3-3d602b054bb0_5141x778.png 1272w, https://substackcdn.com/image/fetch/$s_!xjfz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2fd2755-d051-43c8-8da3-3d602b054bb0_5141x778.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xjfz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2fd2755-d051-43c8-8da3-3d602b054bb0_5141x778.png" width="1456" height="220" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e2fd2755-d051-43c8-8da3-3d602b054bb0_5141x778.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:220,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:363529,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/184357306?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2fd2755-d051-43c8-8da3-3d602b054bb0_5141x778.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!xjfz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2fd2755-d051-43c8-8da3-3d602b054bb0_5141x778.png 424w, https://substackcdn.com/image/fetch/$s_!xjfz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2fd2755-d051-43c8-8da3-3d602b054bb0_5141x778.png 848w, https://substackcdn.com/image/fetch/$s_!xjfz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2fd2755-d051-43c8-8da3-3d602b054bb0_5141x778.png 1272w, https://substackcdn.com/image/fetch/$s_!xjfz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2fd2755-d051-43c8-8da3-3d602b054bb0_5141x778.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>The video below shows the process of adding these nodes:</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;022f87fc-3dd8-4d0b-b0ca-d0d3850ab98d&quot;,&quot;duration&quot;:null}"></div><h3>Transform data into a CSV report</h3><p>Now we have all the data for our report (users and their assigned queues) I&#8217;ll show how, even though n8n allows for code-less automation, you can always add code if you want to.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8-5N!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F134a7e1d-841f-431c-b4f5-d934ae4ea81f_5141x778.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8-5N!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F134a7e1d-841f-431c-b4f5-d934ae4ea81f_5141x778.png 424w, https://substackcdn.com/image/fetch/$s_!8-5N!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F134a7e1d-841f-431c-b4f5-d934ae4ea81f_5141x778.png 848w, https://substackcdn.com/image/fetch/$s_!8-5N!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F134a7e1d-841f-431c-b4f5-d934ae4ea81f_5141x778.png 1272w, https://substackcdn.com/image/fetch/$s_!8-5N!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F134a7e1d-841f-431c-b4f5-d934ae4ea81f_5141x778.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8-5N!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F134a7e1d-841f-431c-b4f5-d934ae4ea81f_5141x778.png" width="1456" height="220" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/134a7e1d-841f-431c-b4f5-d934ae4ea81f_5141x778.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:220,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:336695,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/184357306?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F134a7e1d-841f-431c-b4f5-d934ae4ea81f_5141x778.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!8-5N!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F134a7e1d-841f-431c-b4f5-d934ae4ea81f_5141x778.png 424w, https://substackcdn.com/image/fetch/$s_!8-5N!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F134a7e1d-841f-431c-b4f5-d934ae4ea81f_5141x778.png 848w, https://substackcdn.com/image/fetch/$s_!8-5N!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F134a7e1d-841f-431c-b4f5-d934ae4ea81f_5141x778.png 1272w, https://substackcdn.com/image/fetch/$s_!8-5N!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F134a7e1d-841f-431c-b4f5-d934ae4ea81f_5141x778.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>I take the data amassed from the previous actions and use the <a href="https://docs.n8n.io/code/code-node/">Code In JavaScript node</a> to collate it into a response that the next node will <a href="https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.converttofile/#convert-to-csv">Convert to a CSV file</a>:</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;dd1837ad-fcbe-4704-b10d-0447836ea180&quot;,&quot;duration&quot;:null}"></div><p>The code that is used to collate the user data and their assigned queues is below:</p><pre><code>const users = $items("Get many users");
const allQueues = $items("Get queues for a user");

// Helper to extract names from arrays like roles, skills, or groups
const formatNames = (arr) =&gt; (arr ? arr.map(i =&gt; i.name).join(', ') : '');

return users.map((userItem, index) =&gt; {
  const user = userItem.json;

  // Filter queues linked to this specific user index
  const queueNames = allQueues
    .filter(q =&gt; (Array.isArray(q.pairedItem) ? q.pairedItem[0].item : q.pairedItem?.item) === index)
    .map(q =&gt; q.json.name)
    .join(', ');

  return {
    json: {
      "User ID": user.id,
      "Name": user.name,
      "Email": user.email,
      "Title": user.title,
      "Department": user.department,
      "State": user.state,
      "Last Login": user.dateLastLogin,
      "Roles": formatNames(user.authorization?.roles),
      "Skills": formatNames(user.skills),
      "Groups": formatNames(user.groups),
      "Queues": queueNames
    }
  };
});</code></pre><h3>Running your workflow</h3><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Z1Jf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36275909-557c-40df-a750-b59cce2c87d2_5141x778.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Z1Jf!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36275909-557c-40df-a750-b59cce2c87d2_5141x778.png 424w, https://substackcdn.com/image/fetch/$s_!Z1Jf!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36275909-557c-40df-a750-b59cce2c87d2_5141x778.png 848w, https://substackcdn.com/image/fetch/$s_!Z1Jf!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36275909-557c-40df-a750-b59cce2c87d2_5141x778.png 1272w, https://substackcdn.com/image/fetch/$s_!Z1Jf!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36275909-557c-40df-a750-b59cce2c87d2_5141x778.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Z1Jf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36275909-557c-40df-a750-b59cce2c87d2_5141x778.png" width="1456" height="220" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/36275909-557c-40df-a750-b59cce2c87d2_5141x778.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:220,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:380665,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/184357306?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36275909-557c-40df-a750-b59cce2c87d2_5141x778.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!Z1Jf!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36275909-557c-40df-a750-b59cce2c87d2_5141x778.png 424w, https://substackcdn.com/image/fetch/$s_!Z1Jf!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36275909-557c-40df-a750-b59cce2c87d2_5141x778.png 848w, https://substackcdn.com/image/fetch/$s_!Z1Jf!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36275909-557c-40df-a750-b59cce2c87d2_5141x778.png 1272w, https://substackcdn.com/image/fetch/$s_!Z1Jf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36275909-557c-40df-a750-b59cce2c87d2_5141x778.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Now we have created the entire workflow you can run it by clicking &#8216;Execute workflow&#8217;, or by adjusting the Schedule Trigger.</p><p>The output will be a CSV file like below attached to your Convert to File node:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Y2ij!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba629f9b-d032-4dc1-bede-d1efea1b16aa_2476x248.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Y2ij!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba629f9b-d032-4dc1-bede-d1efea1b16aa_2476x248.png 424w, https://substackcdn.com/image/fetch/$s_!Y2ij!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba629f9b-d032-4dc1-bede-d1efea1b16aa_2476x248.png 848w, https://substackcdn.com/image/fetch/$s_!Y2ij!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba629f9b-d032-4dc1-bede-d1efea1b16aa_2476x248.png 1272w, https://substackcdn.com/image/fetch/$s_!Y2ij!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba629f9b-d032-4dc1-bede-d1efea1b16aa_2476x248.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Y2ij!,w_2400,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba629f9b-d032-4dc1-bede-d1efea1b16aa_2476x248.png" width="1200" height="120.32967032967034" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ba629f9b-d032-4dc1-bede-d1efea1b16aa_2476x248.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;large&quot;,&quot;height&quot;:146,&quot;width&quot;:1456,&quot;resizeWidth&quot;:1200,&quot;bytes&quot;:144856,&quot;alt&quot;:&quot;CSV containing the columns, User ID, Name, Email, State, Roles, Skills, Groups and Queues&quot;,&quot;title&quot;:&quot;CSV containing the columns, User ID, Name, Email, State, Roles, Skills, Groups and Queues&quot;,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/184357306?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba629f9b-d032-4dc1-bede-d1efea1b16aa_2476x248.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-large" alt="CSV containing the columns, User ID, Name, Email, State, Roles, Skills, Groups and Queues" title="CSV containing the columns, User ID, Name, Email, State, Roles, Skills, Groups and Queues" srcset="https://substackcdn.com/image/fetch/$s_!Y2ij!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba629f9b-d032-4dc1-bede-d1efea1b16aa_2476x248.png 424w, https://substackcdn.com/image/fetch/$s_!Y2ij!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba629f9b-d032-4dc1-bede-d1efea1b16aa_2476x248.png 848w, https://substackcdn.com/image/fetch/$s_!Y2ij!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba629f9b-d032-4dc1-bede-d1efea1b16aa_2476x248.png 1272w, https://substackcdn.com/image/fetch/$s_!Y2ij!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba629f9b-d032-4dc1-bede-d1efea1b16aa_2476x248.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>You could next have a go at extending this workflow to email the CSV to you.</p><h3>Integrating with other systems</h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2GcA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6ca17dc-654b-4bcb-8e05-66f24942f198_2864x1396.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2GcA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6ca17dc-654b-4bcb-8e05-66f24942f198_2864x1396.png 424w, https://substackcdn.com/image/fetch/$s_!2GcA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6ca17dc-654b-4bcb-8e05-66f24942f198_2864x1396.png 848w, https://substackcdn.com/image/fetch/$s_!2GcA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6ca17dc-654b-4bcb-8e05-66f24942f198_2864x1396.png 1272w, https://substackcdn.com/image/fetch/$s_!2GcA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6ca17dc-654b-4bcb-8e05-66f24942f198_2864x1396.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2GcA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6ca17dc-654b-4bcb-8e05-66f24942f198_2864x1396.png" width="1456" height="710" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c6ca17dc-654b-4bcb-8e05-66f24942f198_2864x1396.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:710,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:493249,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/184357306?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6ca17dc-654b-4bcb-8e05-66f24942f198_2864x1396.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!2GcA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6ca17dc-654b-4bcb-8e05-66f24942f198_2864x1396.png 424w, https://substackcdn.com/image/fetch/$s_!2GcA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6ca17dc-654b-4bcb-8e05-66f24942f198_2864x1396.png 848w, https://substackcdn.com/image/fetch/$s_!2GcA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6ca17dc-654b-4bcb-8e05-66f24942f198_2864x1396.png 1272w, https://substackcdn.com/image/fetch/$s_!2GcA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6ca17dc-654b-4bcb-8e05-66f24942f198_2864x1396.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>I have shown a workflow that only extracts data from Genesys Cloud. However, that&#8217;s only scratching the surface of what&#8217;s possible with this node and n8n. There are many other systems that n8n integrates with, making it possible to collate data from across your company&#8217;s estate. Systems such as <a href="https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.salesforce/">Salesforce</a>, <a href="https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.microsoftdynamicscrm/">MS Dynamics CRM 365</a> and <a href="https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.zendesk/">Zendesk</a> are all supported.</p><h2>Conclusion</h2><p>This article has provided a whistle-stop tour demonstrating just how easy it now is to create workflows for Genesys Cloud by using my <a href="https://github.com/MakingChatbots/n8n-nodes-genesys-cloud">Genesys Cloud n8n community node</a>.</p><p>I will be continually extending it to cater to as many use-cases as I can think of. If you have a use-case you would like it to support then I&#8217;d love to hear from you!</p><p>Also, please do share what you make with it. I love seeing the ingenuity of the Genesys community.</p>]]></content:encoded></item><item><title><![CDATA[CX as Code with Genesys Cloud]]></title><description><![CDATA[Learn how Genesys Cloud&#8217;s CX as Code can help you deploy changes reliably in your contact-centre]]></description><link>https://makingchatbots.com/p/cx-as-code-with-genesys-cloud</link><guid isPermaLink="false">https://makingchatbots.com/p/cx-as-code-with-genesys-cloud</guid><dc:creator><![CDATA[Lucas Woodward]]></dc:creator><pubDate>Tue, 30 Sep 2025 22:49:52 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/22faf8d0-01c5-44f7-9c95-99105e3fec74_968x685.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The time is almost 5 o&#8217;clock. You&#8217;ve just finished making the final changes to a call flow&#8217;s dependencies and you&#8217;re ready to shut down your computer for the day. Just as you reach for the power button, a message pops up from your boss:</p><p><em>&#8220;Agents are reporting that no calls are coming through. Did you break something?&#8221;</em></p><p>Your heart sinks. But then you remember: you&#8217;re using CX as Code. With a single command you revert your changes, confirm agents are receiving calls again, and head home with a jaunty step.</p><p>The happy ending to this story is thanks to CX as Code. Without it, you&#8217;d be stuck in the drudgery of manually undoing your changes. In this article, I&#8217;ll explain what it is, how it works, and why it matters for your contact centre.</p><p>If you&#8217;d rather see it in action straight away, here&#8217;s my open-source project:</p><p><a href="https://github.com/MakingChatbots/genesys-cloud-cx-as-code-demo">https://github.com/MakingChatbots/genesys-cloud-cx-as-code-demo</a></p><p>In future articles I&#8217;ll discuss creating an automated pipeline to test and deploy changes, so be sure to subscribe:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://makingchatbots.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://makingchatbots.com/subscribe?"><span>Subscribe now</span></a></p><h2>What is CX as Code</h2><p>CX as Code, also known as <a href="https://en.wikipedia.org/wiki/Infrastructure_as_code">Infrastructure as Code (IaC)</a> is the concept of representing parts (or even all) of your contact centre as code. Queues, flows, data tables, integrations, and more can all be defined this way.</p><p>This is what a queue looks like defined as code:</p><pre><code><code>resource "genesyscloud_routing_queue" "book_refund_queue" {
  name                 = "Book Refund"
  description          = "Processes refunds for books"

  enable_transcription = true
  acw_timeout_ms       = 300000
  auto_answer_only     = false
}</code></code></pre><p>CX as Code is made possible using a tool called <a href="https://developer.hashicorp.com/terraform/intro">Terraform</a>, which has been extended by Genesys with their own <a href="https://registry.terraform.io/providers/MyPureCloud/genesyscloud/latest/docs">Terraform provider</a>.</p><p>As you&#8217;ll see later, with resources like this queue defined as code you&#8217;ll be able to use a single command to create, update or delete them against any of your organisations.</p><h3>Why represent resources as code?</h3><p>Amazing things start to happen when you represent your organisation as code:</p><ul><li><p><strong>Disaster Recovery</strong> - You can redeploy your entire contact centre (or parts of it) at the tap of a button, should disaster befall you</p></li><li><p><strong>Tracking changes</strong> - If you store the code in source-control then you can audit every change</p></li><li><p><strong>Reliability</strong> - You can test changes to your contact centre&#8217;s development organisation then reliably deploy the same changes to your production organisation.</p></li></ul><p>You can even bake all this into an <a href="https://makingchatbots.com/p/automating-development-of-genesys-chatbotshtml">automated process to test, peer-review and deploy</a> changes between Genesys Cloud Organisations.</p><h2>Demonstrating CX as Code</h2><p>Now to the fun bit! Let&#8217;s create and deploy a simple journey using CX as Code.</p><p>The <a href="https://github.com/MakingChatbots/genesys-cloud-cx-as-code-demo">full solution for this journey is over on my GitHub</a>.</p><h3>What we will build</h3><p>We will build a simple digital chatbot journey comprising of:</p><ol><li><p>Messenger Deployment / Configuration</p></li><li><p>Inbound Message Flow</p></li><li><p>Digital Bot Flow</p></li><li><p>Transfer to existing queue</p></li></ol><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!YVDv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5766fb9-2226-49fc-a929-bb75b7779e3a_4909x814.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!YVDv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5766fb9-2226-49fc-a929-bb75b7779e3a_4909x814.png 424w, https://substackcdn.com/image/fetch/$s_!YVDv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5766fb9-2226-49fc-a929-bb75b7779e3a_4909x814.png 848w, https://substackcdn.com/image/fetch/$s_!YVDv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5766fb9-2226-49fc-a929-bb75b7779e3a_4909x814.png 1272w, https://substackcdn.com/image/fetch/$s_!YVDv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5766fb9-2226-49fc-a929-bb75b7779e3a_4909x814.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!YVDv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5766fb9-2226-49fc-a929-bb75b7779e3a_4909x814.png" width="1456" height="241" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b5766fb9-2226-49fc-a929-bb75b7779e3a_4909x814.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:241,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:980850,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/169542655?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5766fb9-2226-49fc-a929-bb75b7779e3a_4909x814.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!YVDv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5766fb9-2226-49fc-a929-bb75b7779e3a_4909x814.png 424w, https://substackcdn.com/image/fetch/$s_!YVDv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5766fb9-2226-49fc-a929-bb75b7779e3a_4909x814.png 848w, https://substackcdn.com/image/fetch/$s_!YVDv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5766fb9-2226-49fc-a929-bb75b7779e3a_4909x814.png 1272w, https://substackcdn.com/image/fetch/$s_!YVDv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5766fb9-2226-49fc-a929-bb75b7779e3a_4909x814.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Then deploy it against two organisations:</p><ol><li><p>Development - where we can test it</p></li><li><p>Production - where real users use it</p></li></ol><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!yg9v!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F318c14f7-c7a4-4098-9ef6-83df80a414f1_4602x869.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!yg9v!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F318c14f7-c7a4-4098-9ef6-83df80a414f1_4602x869.png 424w, https://substackcdn.com/image/fetch/$s_!yg9v!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F318c14f7-c7a4-4098-9ef6-83df80a414f1_4602x869.png 848w, https://substackcdn.com/image/fetch/$s_!yg9v!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F318c14f7-c7a4-4098-9ef6-83df80a414f1_4602x869.png 1272w, https://substackcdn.com/image/fetch/$s_!yg9v!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F318c14f7-c7a4-4098-9ef6-83df80a414f1_4602x869.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!yg9v!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F318c14f7-c7a4-4098-9ef6-83df80a414f1_4602x869.png" width="1456" height="275" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/318c14f7-c7a4-4098-9ef6-83df80a414f1_4602x869.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:275,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:594727,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/169542655?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F318c14f7-c7a4-4098-9ef6-83df80a414f1_4602x869.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!yg9v!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F318c14f7-c7a4-4098-9ef6-83df80a414f1_4602x869.png 424w, https://substackcdn.com/image/fetch/$s_!yg9v!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F318c14f7-c7a4-4098-9ef6-83df80a414f1_4602x869.png 848w, https://substackcdn.com/image/fetch/$s_!yg9v!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F318c14f7-c7a4-4098-9ef6-83df80a414f1_4602x869.png 1272w, https://substackcdn.com/image/fetch/$s_!yg9v!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F318c14f7-c7a4-4098-9ef6-83df80a414f1_4602x869.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h3>Defining your resources as Terraform</h3><p>As I mentioned previously, CX as Code is built upon a tool called Terraform, which Genesys have extended via their <a href="https://registry.terraform.io/providers/MyPureCloud/genesyscloud/latest/docs">Terraform provider</a> to be able to represent Genesys Cloud resources. Terraform can then deploy these against any of your organisations.</p><p>So if we take our simple chatbot journey and represent it as Terraform resources in files it will look like below:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0nLJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ab2d90d-ec92-4ef4-b655-e8c287430940_4205x951.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0nLJ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ab2d90d-ec92-4ef4-b655-e8c287430940_4205x951.png 424w, https://substackcdn.com/image/fetch/$s_!0nLJ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ab2d90d-ec92-4ef4-b655-e8c287430940_4205x951.png 848w, https://substackcdn.com/image/fetch/$s_!0nLJ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ab2d90d-ec92-4ef4-b655-e8c287430940_4205x951.png 1272w, https://substackcdn.com/image/fetch/$s_!0nLJ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ab2d90d-ec92-4ef4-b655-e8c287430940_4205x951.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0nLJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ab2d90d-ec92-4ef4-b655-e8c287430940_4205x951.png" width="1456" height="329" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9ab2d90d-ec92-4ef4-b655-e8c287430940_4205x951.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:329,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:896888,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/169542655?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ab2d90d-ec92-4ef4-b655-e8c287430940_4205x951.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!0nLJ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ab2d90d-ec92-4ef4-b655-e8c287430940_4205x951.png 424w, https://substackcdn.com/image/fetch/$s_!0nLJ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ab2d90d-ec92-4ef4-b655-e8c287430940_4205x951.png 848w, https://substackcdn.com/image/fetch/$s_!0nLJ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ab2d90d-ec92-4ef4-b655-e8c287430940_4205x951.png 1272w, https://substackcdn.com/image/fetch/$s_!0nLJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ab2d90d-ec92-4ef4-b655-e8c287430940_4205x951.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><ul><li><p><a href="https://github.com/MakingChatbots/genesys-cloud-cx-as-code-demo/blob/main/terraform/deployment.tf">deployment.tf</a> - Contains the Messenger Deployment and Configuration</p></li><li><p><a href="https://github.com/MakingChatbots/genesys-cloud-cx-as-code-demo/blob/main/terraform/flows.tf">flows.tf</a> - Contains both Incoming Message and Digital Bot flows</p></li></ul><p>Around the peripheries there are also other files that are necessary:</p><ul><li><p><a href="https://github.com/MakingChatbots/genesys-cloud-cx-as-code-demo/blob/main/terraform/provider.tf">provider.tf</a> - Defines the providers Terraform must use, and how they should be configured</p></li><li><p><a href="https://github.com/MakingChatbots/genesys-cloud-cx-as-code-demo/blob/main/terraform/variables.tf">variables.tf</a> - Defines the variables that can be configured per environment</p></li><li><p><a href="https://github.com/MakingChatbots/genesys-cloud-cx-as-code-demo/blob/main/terraform/envs/dev/terraform.tfvars">terraform.tfvars</a> - Defines the values for the variables in variables.tf. There is one of these for each org</p></li></ul><p>Let&#8217;s go over the most important files above in more detail.</p><h4>Provider configuration (provider.tf)</h4><p>When we tell Terraform to deploy our Genesys Cloud resources it needs some way of knowing what they are and how to deploy them.</p><p>The <a href="https://github.com/MakingChatbots/genesys-cloud-cx-as-code-demo/blob/main/terraform/provider.tf">provider.tf</a> file tells Terraform:</p><ul><li><p>Exactly which version of Terraform can be used on this project</p></li><li><p>That it should use the <a href="https://registry.terraform.io/providers/MyPureCloud/genesyscloud/latest/docs">Genesys Cloud provider</a>, and what version</p></li><li><p>Where it should save the <a href="https://developer.hashicorp.com/terraform/language/state">State</a> of the resources it manages - for simplicity&#8217;s sake this project stores the state locally.</p></li></ul><pre><code><code># provider.tf

terraform {
  required_version = "~&gt; 1.12.2"

  required_providers {
    genesyscloud = {
      source  = "mypurecloud/genesyscloud"
      version = "~&gt; 1.68.3"
    }
  }
  
  # Using local backend for 
  backend "local" {}
}

provider "genesyscloud" {
  # Credentials will be set via environment variables
}</code></code></pre><h4>Variable definitions (variables.tf)</h4><p>When we run Terraform we can provide variables that it will use to define resources differently for each organisation.</p><p>The <a href="https://github.com/MakingChatbots/genesys-cloud-cx-as-code-demo/blob/main/terraform/variables.tf">variables.tf</a> in this project allow a different queue name to be used for each organisation:</p><pre><code># variables.tf

# ... 

variable "book_purchase_queue_name" {
  type        = string
  description = "Name of queue for book purchases"
}
</code></pre><h4>Messenger Deployment (deployment.tf)</h4><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xS37!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d8acc74-44bd-43f2-af0b-6e51f7d8ebf3_4205x951.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xS37!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d8acc74-44bd-43f2-af0b-6e51f7d8ebf3_4205x951.png 424w, https://substackcdn.com/image/fetch/$s_!xS37!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d8acc74-44bd-43f2-af0b-6e51f7d8ebf3_4205x951.png 848w, https://substackcdn.com/image/fetch/$s_!xS37!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d8acc74-44bd-43f2-af0b-6e51f7d8ebf3_4205x951.png 1272w, https://substackcdn.com/image/fetch/$s_!xS37!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d8acc74-44bd-43f2-af0b-6e51f7d8ebf3_4205x951.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xS37!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d8acc74-44bd-43f2-af0b-6e51f7d8ebf3_4205x951.png" width="1456" height="329" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6d8acc74-44bd-43f2-af0b-6e51f7d8ebf3_4205x951.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:329,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:782188,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/169542655?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d8acc74-44bd-43f2-af0b-6e51f7d8ebf3_4205x951.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!xS37!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d8acc74-44bd-43f2-af0b-6e51f7d8ebf3_4205x951.png 424w, https://substackcdn.com/image/fetch/$s_!xS37!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d8acc74-44bd-43f2-af0b-6e51f7d8ebf3_4205x951.png 848w, https://substackcdn.com/image/fetch/$s_!xS37!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d8acc74-44bd-43f2-af0b-6e51f7d8ebf3_4205x951.png 1272w, https://substackcdn.com/image/fetch/$s_!xS37!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d8acc74-44bd-43f2-af0b-6e51f7d8ebf3_4205x951.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>The <a href="https://github.com/MakingChatbots/genesys-cloud-cx-as-code-demo/blob/main/terraform/deployment.tf">deployment.tf</a> file contains two resources:</p><ul><li><p><a href="https://registry.terraform.io/providers/MyPureCloud/genesyscloud/latest/docs/resources/webdeployments_configuration">genesyscloud_webdeployments_configuration</a></p></li><li><p><a href="https://registry.terraform.io/providers/MyPureCloud/genesyscloud/latest/docs/resources/webdeployments_deployment">genesyscloud_webdeployments_deployment</a></p></li></ul><p>Below is simplified version of the file in the repo that explains some important concepts:</p><pre><code># deployment.tf

resource "genesyscloud_webdeployments_deployment" "contact_us" {
  name    = "Bookshop Support"

  # References the flow resource the Messenger Deployment will use
  flow_id = genesyscloud_flow.inbound_message_flow.id

  configuration {
    # References the configuration resource above 
    id = genesyscloud_webdeployments_configuration.default.id
    #...
  }
}

resource "genesyscloud_webdeployments_configuration" "default" {
  name        = "Lucas' Bookshop Config"
  description = "Configuration for Contact Us page"
  #...
}</code></pre><p>There is an important concept at work in this file:</p><p>One resource can reference a value of another resource - as is being done with the <code>flow_id</code> above. Terraform is clever enough to realise these dependencies and adjust the order that resources are created</p><h4>Architect Flows (flows.tf)</h4><p>The <a href="https://github.com/MakingChatbots/genesys-cloud-cx-as-code-demo/blob/main/terraform/flows.tf">flows.tf</a> file is where we will create our Incoming Message Flow and Digital Bot Flow. This is also where we will transfer to a queue that already exists in our organisation.</p><p>The definition for the flows themselves are defined in YAML. These are the YAML files that are <a href="https://help.mypurecloud.com/articles/define-architect-flows-using-yaml/">exported from the Architect UI</a>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FH2B!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8489a2d0-703e-4574-b620-2a752b2db808_3590x1114.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FH2B!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8489a2d0-703e-4574-b620-2a752b2db808_3590x1114.png 424w, https://substackcdn.com/image/fetch/$s_!FH2B!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8489a2d0-703e-4574-b620-2a752b2db808_3590x1114.png 848w, https://substackcdn.com/image/fetch/$s_!FH2B!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8489a2d0-703e-4574-b620-2a752b2db808_3590x1114.png 1272w, https://substackcdn.com/image/fetch/$s_!FH2B!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8489a2d0-703e-4574-b620-2a752b2db808_3590x1114.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FH2B!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8489a2d0-703e-4574-b620-2a752b2db808_3590x1114.png" width="1456" height="452" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8489a2d0-703e-4574-b620-2a752b2db808_3590x1114.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:452,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:830871,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/169542655?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8489a2d0-703e-4574-b620-2a752b2db808_3590x1114.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!FH2B!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8489a2d0-703e-4574-b620-2a752b2db808_3590x1114.png 424w, https://substackcdn.com/image/fetch/$s_!FH2B!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8489a2d0-703e-4574-b620-2a752b2db808_3590x1114.png 848w, https://substackcdn.com/image/fetch/$s_!FH2B!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8489a2d0-703e-4574-b620-2a752b2db808_3590x1114.png 1272w, https://substackcdn.com/image/fetch/$s_!FH2B!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8489a2d0-703e-4574-b620-2a752b2db808_3590x1114.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The flows.tf file contains a resource that is used by each flow:</p><ul><li><p><a href="https://registry.terraform.io/providers/MyPureCloud/genesyscloud/latest/docs/resources/flow">genesyscloud_flow</a></p></li></ul><p>Each of these point to the flows&#8217; definitions:</p><ul><li><p><a href="https://github.com/MakingChatbots/genesys-cloud-cx-as-code-demo/blob/main/terraform/flows/inbound-msg.yaml">inbound-msg.yaml</a></p></li><li><p><a href="https://github.com/MakingChatbots/genesys-cloud-cx-as-code-demo/blob/main/terraform/flows/digital-bot.yaml">digital-bot.yaml</a></p></li></ul><pre><code># flows.tf

locals {
  # Locations of where the flows are defined
  inbound_msg_flow_filepath = "${path.module}/flows/inbound-msg.yaml"
  digital_bot_flow_filepath = "${path.module}/flows/digital-bot.yaml"
}

resource "genesyscloud_flow" "inbound_message_flow" {
  filepath = local.inbound_msg_flow_filepath

  # A unique has created to detect when the flow's YAML file changes
  file_content_hash = filesha256(local.inbound_msg_flow_filepath)

  # This is how you can configure your flow definition
  substitutions = {
    bot_flow_name = genesyscloud_flow.digital_bot_flow.name
  }
}

resource "genesyscloud_flow" "digital_bot_flow" {
  filepath = local.digital_bot_flow_filepath
  file_content_hash = filesha256(local.digital_bot_flow_filepath)
  
  substitutions = {
    book_purchase_queue = var.book_purchase_queue_name
  }
}</code></pre><p>There&#8217;s an important concept at work here, called substitutions:</p><p>Substitutions allow values to be passed into the flow&#8217;s YAML definition. In our journey we are using them to pass in the name of the queue the flow will transfer to - which differs per organisation.</p><p>The flow&#8217;s YAML below shows the substitution <code>{{book_purchase_queue}}</code> being used.</p><pre><code># flows/digital-bot.yaml

digitalBot:
  name: Transfer To Queue
  bots:
    # ...
    actions:
      - transferToAcd:
        name: Transfer to ACD
        targetQueue:
          lit:
            name: "{{book_purchase_queue}}"</code></pre><div><hr></div><h3>Deploying to an organisation</h3><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!RwTM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ba180da-9582-47cb-9db6-9768bc55bdee_1144x216.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!RwTM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ba180da-9582-47cb-9db6-9768bc55bdee_1144x216.png 424w, https://substackcdn.com/image/fetch/$s_!RwTM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ba180da-9582-47cb-9db6-9768bc55bdee_1144x216.png 848w, https://substackcdn.com/image/fetch/$s_!RwTM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ba180da-9582-47cb-9db6-9768bc55bdee_1144x216.png 1272w, https://substackcdn.com/image/fetch/$s_!RwTM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ba180da-9582-47cb-9db6-9768bc55bdee_1144x216.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!RwTM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ba180da-9582-47cb-9db6-9768bc55bdee_1144x216.png" width="1144" height="216" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3ba180da-9582-47cb-9db6-9768bc55bdee_1144x216.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:216,&quot;width&quot;:1144,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:53810,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/169542655?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ba180da-9582-47cb-9db6-9768bc55bdee_1144x216.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!RwTM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ba180da-9582-47cb-9db6-9768bc55bdee_1144x216.png 424w, https://substackcdn.com/image/fetch/$s_!RwTM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ba180da-9582-47cb-9db6-9768bc55bdee_1144x216.png 848w, https://substackcdn.com/image/fetch/$s_!RwTM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ba180da-9582-47cb-9db6-9768bc55bdee_1144x216.png 1272w, https://substackcdn.com/image/fetch/$s_!RwTM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ba180da-9582-47cb-9db6-9768bc55bdee_1144x216.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>We now have our journey defined as code. Let&#8217;s now move on to how we deploy it to our dev organisation.</p><ol><li><p>Initialising Terraform is the first thing we have to do. In this step we also tell it where we want it to save the state of what resources it manages, which is defined in the <a href="https://github.com/MakingChatbots/genesys-cloud-cx-as-code-demo/blob/main/terraform/envs/dev/backend.hcl">backend.hcl</a> file.</p><pre><code>terraform init -backend-config=envs/dev/backend.hcl</code></pre></li><li><p>Next we share the Client ID and Secret of the OAuth Client that Genesys&#8217; Terraform Provider will use to access our dev organisation.</p><pre><code>export GENESYSCLOUD_REGION=&lt;region&gt;
export GENESYSCLOUD_OAUTHCLIENT_ID=&lt;OAuth Client ID&gt;
export GENESYSCLOUD_OAUTHCLIENT_SECRET=&lt;OAuth Client Secret&gt;</code></pre></li><li><p>Finally we run Terraform&#8217;s <a href="https://developer.hashicorp.com/terraform/cli/commands/apply">apply command</a>, and pass in the <a href="https://github.com/MakingChatbots/genesys-cloud-cx-as-code-demo/blob/main/terraform/envs/dev/terraform.tfvars">variables we have defined for the dev organisation</a>.</p><pre><code><code>terraform apply -var-file=./envs/dev/terraform.tfvars</code></code></pre><p>When you run <code>apply</code> it will <a href="https://developer.hashicorp.com/terraform/cli/commands/apply#automatic-plan-mode">create a plan</a> of what resources it needs to create, delete or update. You get a chance to check this plan and approve it.</p></li></ol><p>Once we have tested and/or iterated on the deployment to the dev organisation, we can then deploy to our production org.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!l8hn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0dc603dc-bfaf-42c0-96a0-fb6337b3e22b_1144x216.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!l8hn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0dc603dc-bfaf-42c0-96a0-fb6337b3e22b_1144x216.png 424w, https://substackcdn.com/image/fetch/$s_!l8hn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0dc603dc-bfaf-42c0-96a0-fb6337b3e22b_1144x216.png 848w, https://substackcdn.com/image/fetch/$s_!l8hn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0dc603dc-bfaf-42c0-96a0-fb6337b3e22b_1144x216.png 1272w, https://substackcdn.com/image/fetch/$s_!l8hn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0dc603dc-bfaf-42c0-96a0-fb6337b3e22b_1144x216.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!l8hn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0dc603dc-bfaf-42c0-96a0-fb6337b3e22b_1144x216.png" width="1144" height="216" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0dc603dc-bfaf-42c0-96a0-fb6337b3e22b_1144x216.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:216,&quot;width&quot;:1144,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:59986,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/169542655?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0dc603dc-bfaf-42c0-96a0-fb6337b3e22b_1144x216.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!l8hn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0dc603dc-bfaf-42c0-96a0-fb6337b3e22b_1144x216.png 424w, https://substackcdn.com/image/fetch/$s_!l8hn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0dc603dc-bfaf-42c0-96a0-fb6337b3e22b_1144x216.png 848w, https://substackcdn.com/image/fetch/$s_!l8hn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0dc603dc-bfaf-42c0-96a0-fb6337b3e22b_1144x216.png 1272w, https://substackcdn.com/image/fetch/$s_!l8hn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0dc603dc-bfaf-42c0-96a0-fb6337b3e22b_1144x216.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>We follow the same steps, but this time with the OAuth Client for our production organisation and pointing to the production <a href="https://github.com/MakingChatbots/genesys-cloud-cx-as-code-demo/blob/main/terraform/envs/prod/backend.hcl">backend</a> and <a href="https://github.com/MakingChatbots/genesys-cloud-cx-as-code-demo/blob/main/terraform/envs/prod/terraform.tfvars">variable</a> files.</p><pre><code>terraform init -backend-config=envs/prod/backend.hcl

export GENESYSCLOUD_REGION=&lt;region&gt;
export GENESYSCLOUD_OAUTHCLIENT_ID=&lt;OAuth Client ID&gt;
export GENESYSCLOUD_OAUTHCLIENT_SECRET=&lt;OAuth Client Secret&gt;

terraform apply -var-file=./envs/prod/terraform.tfvars</code></pre><p>Once again you&#8217;ll be presented with the plan to confirm before any changes are made to your organisation.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xxNr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb94a595f-f61d-4474-ad46-9b7e70d9284a_1144x216.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xxNr!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb94a595f-f61d-4474-ad46-9b7e70d9284a_1144x216.png 424w, https://substackcdn.com/image/fetch/$s_!xxNr!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb94a595f-f61d-4474-ad46-9b7e70d9284a_1144x216.png 848w, https://substackcdn.com/image/fetch/$s_!xxNr!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb94a595f-f61d-4474-ad46-9b7e70d9284a_1144x216.png 1272w, https://substackcdn.com/image/fetch/$s_!xxNr!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb94a595f-f61d-4474-ad46-9b7e70d9284a_1144x216.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xxNr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb94a595f-f61d-4474-ad46-9b7e70d9284a_1144x216.png" width="1144" height="216" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b94a595f-f61d-4474-ad46-9b7e70d9284a_1144x216.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:216,&quot;width&quot;:1144,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:58617,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/169542655?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb94a595f-f61d-4474-ad46-9b7e70d9284a_1144x216.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!xxNr!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb94a595f-f61d-4474-ad46-9b7e70d9284a_1144x216.png 424w, https://substackcdn.com/image/fetch/$s_!xxNr!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb94a595f-f61d-4474-ad46-9b7e70d9284a_1144x216.png 848w, https://substackcdn.com/image/fetch/$s_!xxNr!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb94a595f-f61d-4474-ad46-9b7e70d9284a_1144x216.png 1272w, https://substackcdn.com/image/fetch/$s_!xxNr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb94a595f-f61d-4474-ad46-9b7e70d9284a_1144x216.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>That&#8217;s it! We&#8217;ve now used CX as Code to deploy a change reliably to our two organisations.</p><h2><strong>Taking control of existing resources</strong></h2><p>The journey we deployed across our organisations both referenced an existing Queue. But what if we also wanted to bring the Queue under the management of Terraform?</p><p>This is actually an easy task, and is made possible by either of the following options:</p><ol><li><p><a href="https://developer.hashicorp.com/terraform/cli/import">Terraform&#8217;s import block</a> - great for specific resources you want to import</p></li><li><p>Genesys&#8217;s <a href="https://registry.terraform.io/providers/MyPureCloud/genesyscloud/latest/docs/guides/export">tf_export resource</a> - great for a type of resource e.g. all queues, or all flows</p></li></ol><p>Since we have a single resource we want to bring under the control of Terraform I will use option 1, Terraform&#8217;s import block.</p><p>To use the import block we create the following file, which contains two parts:</p><ul><li><p>The resource we&#8217;ll import the resource under &#8216;genesyscloud_routing_queue.book_purchase&#8216;</p></li><li><p>An import block where we provide the ID of the queue to import (taken from the queue&#8217;s URL in the Genesys Cloud org)</p></li></ul><pre><code># queue.tf

import {
  # ID of the queue in Genesys Cloud, taken from the Queue's URL
  id = "5b1761c1-632a-402b-aa28-6e858ed520f9"
  
  # Resource to import the queue to (aka the resource below) 
  to = genesyscloud_routing_queue.book_purchase
}

resource "genesyscloud_routing_queue" "book_purchase" {
  name = "Book Purchase (${var.environment})"
}</code></pre><p>Once defined you can run the <code>import</code> command (after the setup commands) to import the resource into your Terraform&#8217;s state:</p><pre><code>terraform init -backend-config=envs/dev/backend.hcl

export GENESYSCLOUD_REGION=&lt;region&gt;
export GENESYSCLOUD_OAUTHCLIENT_ID=&lt;OAuth Client ID&gt;
export GENESYSCLOUD_OAUTHCLIENT_SECRET=&lt;OAuth Client Secret&gt;

terraform import</code></pre><p>Terraform&#8217;s import command will import the name, ID and configuration of the queue in the dev organisation.</p><p>You should then import the Queue in the Production organisation using the same approach, being sure to replace the Queue&#8217;s ID in the import block.</p><pre><code><code>import {
  id = "32bc2add-4e5e-4794-b281-8eb82780b552"
  ...
}
...</code></code></pre><p>Once you&#8217;ve completed the above steps then both queues will be controlled by Terraform.</p><h2>Conclusion</h2><p>In this article we covered:</p><ul><li><p>What CX as Code is</p></li><li><p>How you can use it to reliably deploy resources across your organisations</p></li><li><p>How to reference existing resources</p></li><li><p>Finally, how to import those resources into CX as Code</p></li></ul><p>My hope is that you will have come away from reading this article with a new found enthusiasm for what is possible with CX as Code, and how you might apply it to your organisation. As David Gwartney, an AI Solutions Architect at Genesys reminded me, you don&#8217;t necessary have to implement this wholesale. It can help even if wanting to iterate quickly on a small project.</p><p>Enjoyed this article? <a href="https://www.linkedin.com/comm/mynetwork/discovery-see-all?usecase=PEOPLE_FOLLOWS&amp;followMember=lucas-woodward-the-dev">Follow me on LinkedIn</a> and subscribe to this newsletter to keep up to date.</p>]]></content:encoded></item><item><title><![CDATA[Connecting Genesys Cloud to Claude for call-centre insights]]></title><description><![CDATA[Your contact centre contains a wealth of knowledge about your customers, so wouldn&#8217;t it be fascinating to ask questions of that data using AI?]]></description><link>https://makingchatbots.com/p/connecting-genesys-cloud-to-claude</link><guid isPermaLink="false">https://makingchatbots.com/p/connecting-genesys-cloud-to-claude</guid><dc:creator><![CDATA[Lucas Woodward]]></dc:creator><pubDate>Tue, 22 Jul 2025 23:09:59 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/1937c7cc-4514-4486-b71c-4de17d435a1d_1014x718.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Your contact centre contains a wealth of knowledge about your customers, so wouldn&#8217;t it be fascinating to ask questions of that data using AI? Well, that&#8217;s exactly what this article will show you how to do, by combining Claude Desktop and my <a href="https://github.com/MakingChatbots/genesys-cloud-mcp-server">Genesys Cloud MCP Server</a>.</p><p>Once we&#8217;ve finished you&#8217;ll be able to ask AI questions about your contact centre, and even have it produce ad-hoc reports like below:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!mquG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93d15c34-4cfa-4701-9e7c-58bdd503debf_1615x894.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!mquG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93d15c34-4cfa-4701-9e7c-58bdd503debf_1615x894.png 424w, https://substackcdn.com/image/fetch/$s_!mquG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93d15c34-4cfa-4701-9e7c-58bdd503debf_1615x894.png 848w, https://substackcdn.com/image/fetch/$s_!mquG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93d15c34-4cfa-4701-9e7c-58bdd503debf_1615x894.png 1272w, https://substackcdn.com/image/fetch/$s_!mquG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93d15c34-4cfa-4701-9e7c-58bdd503debf_1615x894.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!mquG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93d15c34-4cfa-4701-9e7c-58bdd503debf_1615x894.png" width="1615" height="894" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/93d15c34-4cfa-4701-9e7c-58bdd503debf_1615x894.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:894,&quot;width&quot;:1615,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:442353,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/167547353?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f642827-96f8-4e22-8298-4a794dd0d133_1615x1046.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!mquG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93d15c34-4cfa-4701-9e7c-58bdd503debf_1615x894.png 424w, https://substackcdn.com/image/fetch/$s_!mquG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93d15c34-4cfa-4701-9e7c-58bdd503debf_1615x894.png 848w, https://substackcdn.com/image/fetch/$s_!mquG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93d15c34-4cfa-4701-9e7c-58bdd503debf_1615x894.png 1272w, https://substackcdn.com/image/fetch/$s_!mquG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93d15c34-4cfa-4701-9e7c-58bdd503debf_1615x894.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Before we dive into the setup let&#8217;s discuss how it works.</p><h2>How it works</h2><p>Claude Desktop is <a href="https://claude.ai/">Claude</a>&#8217;s official desktop app that lets you interact with their latest and greatest generative models (colloquially called AI). The feature we&#8217;ll be leveraging is its ability to be extended using MCP Servers (like mine), which give it access to <a href="https://modelcontextprotocol.io/docs/concepts/tools">tools</a> that can interact with external systems, in our case a Genesys Cloud organisation.</p><p>The grossly oversimplified process is as follows:</p><ol><li><p>You ask a question, such as &#8220;Which queue has the most agents assigned to it?&#8220;</p></li><li><p>The AI understands that it needs a tool to answer the question, and retrieves a list of tools from the configured MCP Server.</p><ol><li><p>Each tool has a name, description and parameters.</p></li></ol></li><li><p>AI uses these to determine the best tool, and then calls that tool</p></li><li><p>The response from the tool is then used to derive an answer</p></li></ol><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!nPnE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83b93a34-97dc-4409-9665-f6add9dce8fa_1229x485.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!nPnE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83b93a34-97dc-4409-9665-f6add9dce8fa_1229x485.png 424w, https://substackcdn.com/image/fetch/$s_!nPnE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83b93a34-97dc-4409-9665-f6add9dce8fa_1229x485.png 848w, https://substackcdn.com/image/fetch/$s_!nPnE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83b93a34-97dc-4409-9665-f6add9dce8fa_1229x485.png 1272w, https://substackcdn.com/image/fetch/$s_!nPnE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83b93a34-97dc-4409-9665-f6add9dce8fa_1229x485.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!nPnE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83b93a34-97dc-4409-9665-f6add9dce8fa_1229x485.png" width="728" height="287.29048006509356" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/83b93a34-97dc-4409-9665-f6add9dce8fa_1229x485.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:485,&quot;width&quot;:1229,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:129796,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/167547353?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83b93a34-97dc-4409-9665-f6add9dce8fa_1229x485.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!nPnE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83b93a34-97dc-4409-9665-f6add9dce8fa_1229x485.png 424w, https://substackcdn.com/image/fetch/$s_!nPnE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83b93a34-97dc-4409-9665-f6add9dce8fa_1229x485.png 848w, https://substackcdn.com/image/fetch/$s_!nPnE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83b93a34-97dc-4409-9665-f6add9dce8fa_1229x485.png 1272w, https://substackcdn.com/image/fetch/$s_!nPnE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83b93a34-97dc-4409-9665-f6add9dce8fa_1229x485.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Like I say, that is an oversimplification, but it adequately explains the roles of the various parts that we&#8217;ll setup in the next section&#8230;</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://makingchatbots.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Subscribe to be informed of my next post on this topic.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Setup</h2><p>The setup consists of two parts:</p><ol><li><p>Creating an OAuth Client in your Genesys Cloud organisation</p></li><li><p>Installing Claude Desktop and configuring it to use the Genesys Cloud MCP Server, along with the OAuth Client configuration </p></li></ol><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!IDAE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ddea2bb-a3a0-4fe8-9f1b-307f4d435196_1097x153.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!IDAE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ddea2bb-a3a0-4fe8-9f1b-307f4d435196_1097x153.png 424w, https://substackcdn.com/image/fetch/$s_!IDAE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ddea2bb-a3a0-4fe8-9f1b-307f4d435196_1097x153.png 848w, https://substackcdn.com/image/fetch/$s_!IDAE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ddea2bb-a3a0-4fe8-9f1b-307f4d435196_1097x153.png 1272w, https://substackcdn.com/image/fetch/$s_!IDAE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ddea2bb-a3a0-4fe8-9f1b-307f4d435196_1097x153.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!IDAE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ddea2bb-a3a0-4fe8-9f1b-307f4d435196_1097x153.png" width="1097" height="153" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0ddea2bb-a3a0-4fe8-9f1b-307f4d435196_1097x153.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:153,&quot;width&quot;:1097,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:46277,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/167547353?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ddea2bb-a3a0-4fe8-9f1b-307f4d435196_1097x153.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!IDAE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ddea2bb-a3a0-4fe8-9f1b-307f4d435196_1097x153.png 424w, https://substackcdn.com/image/fetch/$s_!IDAE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ddea2bb-a3a0-4fe8-9f1b-307f4d435196_1097x153.png 848w, https://substackcdn.com/image/fetch/$s_!IDAE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ddea2bb-a3a0-4fe8-9f1b-307f4d435196_1097x153.png 1272w, https://substackcdn.com/image/fetch/$s_!IDAE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ddea2bb-a3a0-4fe8-9f1b-307f4d435196_1097x153.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h3>Step 1: Create an OAuth Client</h3><p>When configuring the Claude to use the Genesys Cloud MCP Server you need to provide OAuth Client Credentials so the MCP Server can access your organisation.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!dj2j!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33f195f4-0e7d-4983-aefb-6d62ba8deb22_1097x153.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dj2j!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33f195f4-0e7d-4983-aefb-6d62ba8deb22_1097x153.png 424w, https://substackcdn.com/image/fetch/$s_!dj2j!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33f195f4-0e7d-4983-aefb-6d62ba8deb22_1097x153.png 848w, https://substackcdn.com/image/fetch/$s_!dj2j!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33f195f4-0e7d-4983-aefb-6d62ba8deb22_1097x153.png 1272w, https://substackcdn.com/image/fetch/$s_!dj2j!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33f195f4-0e7d-4983-aefb-6d62ba8deb22_1097x153.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dj2j!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33f195f4-0e7d-4983-aefb-6d62ba8deb22_1097x153.png" width="1097" height="153" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/33f195f4-0e7d-4983-aefb-6d62ba8deb22_1097x153.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:153,&quot;width&quot;:1097,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:38401,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/167547353?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33f195f4-0e7d-4983-aefb-6d62ba8deb22_1097x153.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!dj2j!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33f195f4-0e7d-4983-aefb-6d62ba8deb22_1097x153.png 424w, https://substackcdn.com/image/fetch/$s_!dj2j!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33f195f4-0e7d-4983-aefb-6d62ba8deb22_1097x153.png 848w, https://substackcdn.com/image/fetch/$s_!dj2j!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33f195f4-0e7d-4983-aefb-6d62ba8deb22_1097x153.png 1272w, https://substackcdn.com/image/fetch/$s_!dj2j!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33f195f4-0e7d-4983-aefb-6d62ba8deb22_1097x153.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Follow <a href="https://help.mypurecloud.com/articles/create-an-oauth-client/">Genesys&#8217; guide for creating an OAuth Client with Client Credentials</a>.</p><p>Then assign a role with the following permissions:</p><ul><li><p><em>Routing &gt; Queue &gt; View</em></p></li><li><p><em>Analytics &gt; Conversation Detail &gt; View</em></p></li><li><p><em>Analytics &gt; Speech and Text Analytics Aggregates &gt; View</em></p></li><li><p><em>Speech and Text Analytics &gt; Data &gt; View</em></p></li><li><p><em>Recording &gt; Recording &gt; View</em></p></li></ul><p>Alternatively, if you only want to assign permissions for a subset of the tools then you can find <a href="https://github.com/MakingChatbots/genesys-cloud-mcp-server/blob/main/docs/tools.md#security">permissions per tool in the docs</a>.</p><h3>Step 2: Configure Claude Desktop to use MCP Server</h3><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!XKus!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcf765538-3701-4d1d-b908-c1e31ef58fb4_1097x153.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!XKus!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcf765538-3701-4d1d-b908-c1e31ef58fb4_1097x153.png 424w, https://substackcdn.com/image/fetch/$s_!XKus!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcf765538-3701-4d1d-b908-c1e31ef58fb4_1097x153.png 848w, https://substackcdn.com/image/fetch/$s_!XKus!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcf765538-3701-4d1d-b908-c1e31ef58fb4_1097x153.png 1272w, https://substackcdn.com/image/fetch/$s_!XKus!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcf765538-3701-4d1d-b908-c1e31ef58fb4_1097x153.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!XKus!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcf765538-3701-4d1d-b908-c1e31ef58fb4_1097x153.png" width="1097" height="153" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cf765538-3701-4d1d-b908-c1e31ef58fb4_1097x153.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:153,&quot;width&quot;:1097,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:43332,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/167547353?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcf765538-3701-4d1d-b908-c1e31ef58fb4_1097x153.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!XKus!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcf765538-3701-4d1d-b908-c1e31ef58fb4_1097x153.png 424w, https://substackcdn.com/image/fetch/$s_!XKus!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcf765538-3701-4d1d-b908-c1e31ef58fb4_1097x153.png 848w, https://substackcdn.com/image/fetch/$s_!XKus!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcf765538-3701-4d1d-b908-c1e31ef58fb4_1097x153.png 1272w, https://substackcdn.com/image/fetch/$s_!XKus!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcf765538-3701-4d1d-b908-c1e31ef58fb4_1097x153.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Now we&#8217;ll set up Claude Desktop to use the Genesys Cloud MCP Server, along with the previously created OAuth Client&#8217;s credentials.</p><ol><li><p><a href="https://claude.ai/download">Install Claude Desktop</a> (and create a free account if necessary)</p></li><li><p><a href="https://modelcontextprotocol.io/quickstart/user#2-add-the-filesystem-mcp-server">Follow the official guide for opening the config file</a> <code>claude_desktop_config.json</code></p></li><li><p>Insert the configuration below:</p></li></ol><pre><code>{
  "mcpServers": {
    "genesys-cloud": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@makingchatbots/genesys-cloud-mcp-server"],
      "env": {
        "GENESYSCLOUD_REGION": "&lt;PUT REGION HERE&gt;",
        "GENESYSCLOUD_OAUTHCLIENT_ID": "&lt;PUT OAUTHCLIENT ID HERE&gt;",
        "GENESYSCLOUD_OAUTHCLIENT_SECRET": "&lt;PUT OAUTHCLIENT SECRET HERE&gt;"
      }
    }
  }
}</code></pre><p><em>Make sure you replace the placeholders with your Client Credentials created in the previous section.</em></p><p>It&#8217;s now all done. You can now open a new chat within Claude Desktop and ask a question of your contact centre&#8217;s data. Like asking it to analyse a transcript for a disgruntled customer to understand where it all went wrong:</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;429f6443-e397-4fa1-beef-49a324c15d5d&quot;,&quot;duration&quot;:null}"></div><h2>Conclusion</h2><p>There are few areas more important in a business than the point at which a customer contacts you. So being able to leverage AI to better understand the customer in this space can only be a good thing, and hopefully this article has helped with that.</p><p>The <a href="https://github.com/MakingChatbots/genesys-cloud-mcp-server">Genesys Cloud MCP Server</a> I&#8217;ve created, and referenced throughout this article, has <a href="https://github.com/MakingChatbots/genesys-cloud-mcp-server/blob/main/docs/tools.md">a growing set of tools</a> that I&#8217;m building and refining based on feedback from the Genesys community.</p><p>If you have any thoughts or suggestions, I&#8217;d love to hear from you. Feel free to connect with me (and follow me) on <a href="https://www.linkedin.com/in/lucas-woodward-the-dev/">LinkedIn</a>.</p>]]></content:encoded></item><item><title><![CDATA[Slack Alerts for Genesys Cloud Flow Changes]]></title><description><![CDATA[A little while ago I wrote a tool to notify people over Slack when a Genesys Cloud flow was updated.]]></description><link>https://makingchatbots.com/p/slack-alerts-for-genesys-cloud-flow</link><guid isPermaLink="false">https://makingchatbots.com/p/slack-alerts-for-genesys-cloud-flow</guid><dc:creator><![CDATA[Lucas Woodward]]></dc:creator><pubDate>Tue, 10 Jun 2025 22:35:37 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/6870b510-1b9d-4fdb-9534-9959a3a9fd9b_1014x718.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A little while ago I wrote a tool to notify people over Slack when a Genesys Cloud flow was updated. It was a simple tool, but it became very useful for adding explanations to changes, understanding the frequency of updates, and correlating changes to downstream service alerts. Here&#8217;s a breakdown of how it works.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QLPE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2785c6e6-dbde-40e7-9e34-4f9154c888aa_1300x356.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QLPE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2785c6e6-dbde-40e7-9e34-4f9154c888aa_1300x356.png 424w, https://substackcdn.com/image/fetch/$s_!QLPE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2785c6e6-dbde-40e7-9e34-4f9154c888aa_1300x356.png 848w, https://substackcdn.com/image/fetch/$s_!QLPE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2785c6e6-dbde-40e7-9e34-4f9154c888aa_1300x356.png 1272w, https://substackcdn.com/image/fetch/$s_!QLPE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2785c6e6-dbde-40e7-9e34-4f9154c888aa_1300x356.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QLPE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2785c6e6-dbde-40e7-9e34-4f9154c888aa_1300x356.png" width="1300" height="356" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2785c6e6-dbde-40e7-9e34-4f9154c888aa_1300x356.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:356,&quot;width&quot;:1300,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:72516,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/163166115?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2785c6e6-dbde-40e7-9e34-4f9154c888aa_1300x356.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!QLPE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2785c6e6-dbde-40e7-9e34-4f9154c888aa_1300x356.png 424w, https://substackcdn.com/image/fetch/$s_!QLPE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2785c6e6-dbde-40e7-9e34-4f9154c888aa_1300x356.png 848w, https://substackcdn.com/image/fetch/$s_!QLPE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2785c6e6-dbde-40e7-9e34-4f9154c888aa_1300x356.png 1272w, https://substackcdn.com/image/fetch/$s_!QLPE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2785c6e6-dbde-40e7-9e34-4f9154c888aa_1300x356.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Slack message describing an updated flow</figcaption></figure></div><p>The Slack message above shows what is automatically sent when a new version of a flow in Genesys Cloud is published. I included all the details I thought would be useful:</p><ul><li><p>Name of the updated flow</p></li><li><p>Flow Description</p></li><li><p>New Version</p></li><li><p>Who made the change</p></li><li><p>Link to conversations using the flow</p></li></ul><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://makingchatbots.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Before we dive into the details, subscribe if you&#8217;d like more articles like this</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>How it works</h2><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kFQL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f9b3fb9-4d82-4a64-9f63-5a7a39c0cf0c_1316x203.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kFQL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f9b3fb9-4d82-4a64-9f63-5a7a39c0cf0c_1316x203.png 424w, https://substackcdn.com/image/fetch/$s_!kFQL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f9b3fb9-4d82-4a64-9f63-5a7a39c0cf0c_1316x203.png 848w, https://substackcdn.com/image/fetch/$s_!kFQL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f9b3fb9-4d82-4a64-9f63-5a7a39c0cf0c_1316x203.png 1272w, https://substackcdn.com/image/fetch/$s_!kFQL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f9b3fb9-4d82-4a64-9f63-5a7a39c0cf0c_1316x203.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kFQL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f9b3fb9-4d82-4a64-9f63-5a7a39c0cf0c_1316x203.png" width="728" height="112.29787234042553" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5f9b3fb9-4d82-4a64-9f63-5a7a39c0cf0c_1316x203.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:203,&quot;width&quot;:1316,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:72749,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/163166115?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f9b3fb9-4d82-4a64-9f63-5a7a39c0cf0c_1316x203.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!kFQL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f9b3fb9-4d82-4a64-9f63-5a7a39c0cf0c_1316x203.png 424w, https://substackcdn.com/image/fetch/$s_!kFQL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f9b3fb9-4d82-4a64-9f63-5a7a39c0cf0c_1316x203.png 848w, https://substackcdn.com/image/fetch/$s_!kFQL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f9b3fb9-4d82-4a64-9f63-5a7a39c0cf0c_1316x203.png 1272w, https://substackcdn.com/image/fetch/$s_!kFQL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f9b3fb9-4d82-4a64-9f63-5a7a39c0cf0c_1316x203.png 1456w" sizes="100vw"></picture><div></div></div></a></figure></div><p>The solution, diagrammed above is as simple as I could make it. It consists of 3 parts:</p><ol><li><p><a href="https://developer.genesys.cloud/notificationsalerts/notifications/event-bridge">Amazon EventBridge Integration</a> used to trigger a Lambda when flows in Genesys Cloud are updated</p></li><li><p>Triggered Lambda uses details in the event to create a Slack message</p></li><li><p>Lambda calls Slack Webhook URL to send the message</p></li></ol><p>Let&#8217;s go into each point in more detail.</p><h2><strong>1. Detecting when a flow is updated</strong></h2><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0etY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2a780a0-0c25-4ee4-994f-8149d30867f0_1316x203.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0etY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2a780a0-0c25-4ee4-994f-8149d30867f0_1316x203.png 424w, https://substackcdn.com/image/fetch/$s_!0etY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2a780a0-0c25-4ee4-994f-8149d30867f0_1316x203.png 848w, https://substackcdn.com/image/fetch/$s_!0etY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2a780a0-0c25-4ee4-994f-8149d30867f0_1316x203.png 1272w, https://substackcdn.com/image/fetch/$s_!0etY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2a780a0-0c25-4ee4-994f-8149d30867f0_1316x203.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0etY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2a780a0-0c25-4ee4-994f-8149d30867f0_1316x203.png" width="1316" height="203" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a2a780a0-0c25-4ee4-994f-8149d30867f0_1316x203.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:203,&quot;width&quot;:1316,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:71608,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/163166115?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2a780a0-0c25-4ee4-994f-8149d30867f0_1316x203.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!0etY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2a780a0-0c25-4ee4-994f-8149d30867f0_1316x203.png 424w, https://substackcdn.com/image/fetch/$s_!0etY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2a780a0-0c25-4ee4-994f-8149d30867f0_1316x203.png 848w, https://substackcdn.com/image/fetch/$s_!0etY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2a780a0-0c25-4ee4-994f-8149d30867f0_1316x203.png 1272w, https://substackcdn.com/image/fetch/$s_!0etY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2a780a0-0c25-4ee4-994f-8149d30867f0_1316x203.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Detecting when a flow has been updated is possible by configuring Genesys Cloud&#8217;s <a href="https://developer.genesys.cloud/notificationsalerts/notifications/event-bridge">Amazon EventBridge Integration</a> to publish notifications for the <a href="https://developer.genesys.cloud/notificationsalerts/notifications/available-topics#v2-flows--id-">v2.flows.{id} topic</a>.</p><p>These notifications are filtered by an <a href="https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-rules.html">EventBridge Rule</a> to only trigger the Lambda when a flow has been successfully published:</p><pre><code>{
  "detail-type": ["v2.flows.{id}"],
  "detail": {
    "eventBody": {
      "currentOperation": {
        "actionStatus": ["SUCCESS"],
        "actionName": ["PUBLISH"]
      }
    }
  }
}</code></pre><h2><strong>2. Create Slack message from event</strong></h2><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!IC91!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe78f6097-c83f-4ab5-b484-c77ca9c2abe3_1316x203.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!IC91!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe78f6097-c83f-4ab5-b484-c77ca9c2abe3_1316x203.png 424w, https://substackcdn.com/image/fetch/$s_!IC91!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe78f6097-c83f-4ab5-b484-c77ca9c2abe3_1316x203.png 848w, https://substackcdn.com/image/fetch/$s_!IC91!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe78f6097-c83f-4ab5-b484-c77ca9c2abe3_1316x203.png 1272w, https://substackcdn.com/image/fetch/$s_!IC91!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe78f6097-c83f-4ab5-b484-c77ca9c2abe3_1316x203.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!IC91!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe78f6097-c83f-4ab5-b484-c77ca9c2abe3_1316x203.png" width="1316" height="203" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e78f6097-c83f-4ab5-b484-c77ca9c2abe3_1316x203.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:203,&quot;width&quot;:1316,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:65196,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/163166115?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe78f6097-c83f-4ab5-b484-c77ca9c2abe3_1316x203.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!IC91!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe78f6097-c83f-4ab5-b484-c77ca9c2abe3_1316x203.png 424w, https://substackcdn.com/image/fetch/$s_!IC91!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe78f6097-c83f-4ab5-b484-c77ca9c2abe3_1316x203.png 848w, https://substackcdn.com/image/fetch/$s_!IC91!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe78f6097-c83f-4ab5-b484-c77ca9c2abe3_1316x203.png 1272w, https://substackcdn.com/image/fetch/$s_!IC91!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe78f6097-c83f-4ab5-b484-c77ca9c2abe3_1316x203.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>When I created the tool I made the conscious decision to keep it simple by using only the details in the <code>v2.flow.{id} </code>notification, and not going off to other Platform API endpoints.</p><p>Thankfully the notification contained all the information I needed. The code below is that of the Lambda&#8217;s handler, and shows it extracting all the relevant fields:</p><pre><code>/* handler.ts */

async function handler(
  event: EventBridgeEvent&lt;typeof v2FlowsEventDetailType, v2FlowsEvent&gt;
): Promise&lt;void&gt; {
  const flowPublished = transformEvent(event.detail);

  await slackClient.sendMessage(
    flowUpdatedMessage({
      flow: {
        name: event.detail.eventBody.name,
        description: event.detail.eventBody.description,
        version: event.detail.eventBody.publishedVersion.id,
      },
      editor: {
        name: flowPublished.editor.name,
        profile: flowPublished.editor.profileUrl,
      },
      flowInteractionsPage: performanceInteractionLinkBuilder(
        event.detail.eventBody.id
      ),
    })
  );
}

/* transformEvent.ts */

export function transformEvent(
  { eventBody }: v2FlowsEvent
): FlowUpdatedEvent {
  let editor: EditorDetails;

  if (eventBody.currentOperation.user) {
    const userDetails = eventBody.currentOperation.user;
    editor = {
      type: "user",
      id: userDetails.id,
      name: userDetails.name,
      profileUrl: profileLinkBuilder(userDetails.id),
    };
  } else if (eventBody.currentOperation.client) {
    const clientDetails = eventBody.currentOperation.client;
    editor = {
      type: "oauth",
      id: clientDetails.id,
      name: clientDetails.name,
      profileUrl: oauthClientLinkBuilder(clientDetails.id),
    };
  } else {
    editor = {
      type: "unknown",
    };
  }

  return {
    editor,
    flow: {
      name: eventBody.name,
      description: eventBody.description,
      version: eventBody.publishedVersion.id,
    },
  };
}</code></pre><h2>3. Sending the Slack message</h2><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!C2rm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8739484d-f749-42e5-89bd-df23deeebd03_1316x203.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!C2rm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8739484d-f749-42e5-89bd-df23deeebd03_1316x203.png 424w, https://substackcdn.com/image/fetch/$s_!C2rm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8739484d-f749-42e5-89bd-df23deeebd03_1316x203.png 848w, https://substackcdn.com/image/fetch/$s_!C2rm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8739484d-f749-42e5-89bd-df23deeebd03_1316x203.png 1272w, https://substackcdn.com/image/fetch/$s_!C2rm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8739484d-f749-42e5-89bd-df23deeebd03_1316x203.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!C2rm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8739484d-f749-42e5-89bd-df23deeebd03_1316x203.png" width="1316" height="203" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8739484d-f749-42e5-89bd-df23deeebd03_1316x203.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:203,&quot;width&quot;:1316,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:64304,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/163166115?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8739484d-f749-42e5-89bd-df23deeebd03_1316x203.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!C2rm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8739484d-f749-42e5-89bd-df23deeebd03_1316x203.png 424w, https://substackcdn.com/image/fetch/$s_!C2rm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8739484d-f749-42e5-89bd-df23deeebd03_1316x203.png 848w, https://substackcdn.com/image/fetch/$s_!C2rm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8739484d-f749-42e5-89bd-df23deeebd03_1316x203.png 1272w, https://substackcdn.com/image/fetch/$s_!C2rm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8739484d-f749-42e5-89bd-df23deeebd03_1316x203.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>After the details have been extracted we transform them into a message schema for Slack&#8217;s <a href="https://docs.slack.dev/block-kit">Block Kit UI schema</a>. This schema allows more complex messages than just a block of text.</p><p>Once the Block Kit UI&#8217;s JSON has been created then it&#8217;s simply a case of sending it in the body of a POST request to the preconfigured Webhook URL.</p><pre><code>/* flowUpdatedMessage.ts */

export function flowUpdatedMessage({
  flow,
  editor,
  flowInteractionsPage,
}: {
  flow: {
    name: string;
    description: string | undefined;
    version: string;
  };
  editor: { name: string; profile: URL };
  flowInteractionsPage: URL;
}): SlackMessage {
  return {
    build(): string {
      return JSON.stringify({
        text: `Flow updated: ${flow.name}`,
        blocks: [
          {
            type: "section",
            text: {
              type: "mrkdwn",
              text: "A *flow was updated!*",
            },
          },
          {
            type: "section",
            fields: [
              {
                type: "mrkdwn",
                text: `*Name:*\n${flow.name}`,
              },
              ...(!flow.description
                ? []
                : [
                    {
                      type: "mrkdwn",
                      text: `*Description:*\n${flow.description}`,
                    },
                  ]),
              {
                type: "mrkdwn",
                text: `*By:*\n&lt;${editor.profile.href}|${editor.name}&gt;`,
              },
              {
                type: "mrkdwn",
                text: `*Version:*\n${flow.version}`,
              },
            ],
          },
          {
            type: "context",
            elements: [
              {
                type: "mrkdwn",
                text: `&lt;${flowInteractionsPage.href}|Latest conversations using this flow&gt;`,
              },
            ],
          },
        ],
      });
    },
  };
}

/* AxiosSlackClient.ts */

export class AxiosSlackClient implements SlackClient {
  private readonly axiosInstance: AxiosInstance;

  public constructor(
    webhookUrl: string,
    axiosInstanceFactory: Pick&lt;typeof axios, "create"&gt; = axios
  ) {
    this.axiosInstance = axiosInstanceFactory.create({
      baseURL: webhookUrl,
      headers: {
        "Content-Type": "application/json",
      },
    });
  }

  public async sendMessage(message: SlackMessage): Promise&lt;void&gt; {
    await this.axiosInstance.post(undefined, message.build());
  }
}</code></pre><p>The result is the message below being published to the Slack Channel configured against the Webhook URL:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QLPE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2785c6e6-dbde-40e7-9e34-4f9154c888aa_1300x356.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QLPE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2785c6e6-dbde-40e7-9e34-4f9154c888aa_1300x356.png 424w, https://substackcdn.com/image/fetch/$s_!QLPE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2785c6e6-dbde-40e7-9e34-4f9154c888aa_1300x356.png 848w, https://substackcdn.com/image/fetch/$s_!QLPE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2785c6e6-dbde-40e7-9e34-4f9154c888aa_1300x356.png 1272w, https://substackcdn.com/image/fetch/$s_!QLPE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2785c6e6-dbde-40e7-9e34-4f9154c888aa_1300x356.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QLPE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2785c6e6-dbde-40e7-9e34-4f9154c888aa_1300x356.png" width="1300" height="356" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2785c6e6-dbde-40e7-9e34-4f9154c888aa_1300x356.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:356,&quot;width&quot;:1300,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!QLPE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2785c6e6-dbde-40e7-9e34-4f9154c888aa_1300x356.png 424w, https://substackcdn.com/image/fetch/$s_!QLPE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2785c6e6-dbde-40e7-9e34-4f9154c888aa_1300x356.png 848w, https://substackcdn.com/image/fetch/$s_!QLPE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2785c6e6-dbde-40e7-9e34-4f9154c888aa_1300x356.png 1272w, https://substackcdn.com/image/fetch/$s_!QLPE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2785c6e6-dbde-40e7-9e34-4f9154c888aa_1300x356.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>What&#8217;s next&#8230;</h2><p>I have always seen this tool, whilst useful, as a stepping stone to a much more audacious project: Tracking every flow change in GitHub!</p><p>Having changes committed to GitHub would open up the ability to do some pretty cool things:</p><ul><li><p>Lint flow evaluations</p></li><li><p>Publish notifications to Slack (with patch-sets, change descriptions)</p></li><li><p>Auto-generate diagrams for living documentation</p></li><li><p>Easily identify who changed a specific part of a flow (e.g. Git Blame)</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!TcZ_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13fb7cab-c399-4ded-b66f-c6a9a55bdfa6_2393x875.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!TcZ_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13fb7cab-c399-4ded-b66f-c6a9a55bdfa6_2393x875.png 424w, https://substackcdn.com/image/fetch/$s_!TcZ_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13fb7cab-c399-4ded-b66f-c6a9a55bdfa6_2393x875.png 848w, https://substackcdn.com/image/fetch/$s_!TcZ_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13fb7cab-c399-4ded-b66f-c6a9a55bdfa6_2393x875.png 1272w, https://substackcdn.com/image/fetch/$s_!TcZ_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13fb7cab-c399-4ded-b66f-c6a9a55bdfa6_2393x875.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!TcZ_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13fb7cab-c399-4ded-b66f-c6a9a55bdfa6_2393x875.png" width="728" height="266" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/13fb7cab-c399-4ded-b66f-c6a9a55bdfa6_2393x875.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:532,&quot;width&quot;:1456,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:419632,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/163166115?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13fb7cab-c399-4ded-b66f-c6a9a55bdfa6_2393x875.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!TcZ_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13fb7cab-c399-4ded-b66f-c6a9a55bdfa6_2393x875.png 424w, https://substackcdn.com/image/fetch/$s_!TcZ_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13fb7cab-c399-4ded-b66f-c6a9a55bdfa6_2393x875.png 848w, https://substackcdn.com/image/fetch/$s_!TcZ_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13fb7cab-c399-4ded-b66f-c6a9a55bdfa6_2393x875.png 1272w, https://substackcdn.com/image/fetch/$s_!TcZ_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13fb7cab-c399-4ded-b66f-c6a9a55bdfa6_2393x875.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><a href="https://www.linkedin.com/comm/mynetwork/discovery-see-all?usecase=PEOPLE_FOLLOWS&amp;followMember=lucas-woodward-the-dev">Follow me on LinkedIn</a> if you&#8217;d like to track my progress on this. </p><h2>Conclusion</h2><p>This was a straightforward tool to build but proved very useful. It is also a great project for someone to try out who may not have built anything using Genesys Cloud&#8217;s EventBridge Integration before.</p><p>If you do build it, or already have then I&#8217;d love to hear about your experiences. Just <a href="https://www.linkedin.com/in/lucas-woodward-the-dev/">ping me on LinkedIn</a>.</p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Lessons building on Genesys Cloud's live voice transcription]]></title><description><![CDATA[What I learned from building a live voice transcription feature on Genesys Cloud&#8217;s Notifications API.]]></description><link>https://makingchatbots.com/p/lessons-building-on-genesys-clouds-live-transcript</link><guid isPermaLink="false">https://makingchatbots.com/p/lessons-building-on-genesys-clouds-live-transcript</guid><dc:creator><![CDATA[Lucas Woodward]]></dc:creator><pubDate>Thu, 03 Apr 2025 21:30:52 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff4301dc-4d05-4ac4-9ce2-2302646f7462_992x574.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Genesys Cloud's Notifications API makes streaming a live transcript from an agent's UI very easy indeed. But the implementation you choose can vary significantly depending on your use-case. In this article, I thought it might be interesting to share such an implementation, and the decisions I made along the way&#8230;</p><p>I set out to add a real-time transcript (which was enriched in real-time too) into a UI that already had a Genesys Cloud softphone, backed by Genesys&#8217;s Embedded Framework.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://makingchatbots.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Before we dive into the details, subscribe if you&#8217;d like more articles like this</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!oknP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1a20ce6-5b17-4a1f-816f-dc020869bd9e_2295x1742.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!oknP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1a20ce6-5b17-4a1f-816f-dc020869bd9e_2295x1742.png 424w, https://substackcdn.com/image/fetch/$s_!oknP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1a20ce6-5b17-4a1f-816f-dc020869bd9e_2295x1742.png 848w, https://substackcdn.com/image/fetch/$s_!oknP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1a20ce6-5b17-4a1f-816f-dc020869bd9e_2295x1742.png 1272w, https://substackcdn.com/image/fetch/$s_!oknP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1a20ce6-5b17-4a1f-816f-dc020869bd9e_2295x1742.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!oknP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1a20ce6-5b17-4a1f-816f-dc020869bd9e_2295x1742.png" width="1456" height="1105" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f1a20ce6-5b17-4a1f-816f-dc020869bd9e_2295x1742.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1105,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:265750,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/158104361?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1a20ce6-5b17-4a1f-816f-dc020869bd9e_2295x1742.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!oknP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1a20ce6-5b17-4a1f-816f-dc020869bd9e_2295x1742.png 424w, https://substackcdn.com/image/fetch/$s_!oknP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1a20ce6-5b17-4a1f-816f-dc020869bd9e_2295x1742.png 848w, https://substackcdn.com/image/fetch/$s_!oknP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1a20ce6-5b17-4a1f-816f-dc020869bd9e_2295x1742.png 1272w, https://substackcdn.com/image/fetch/$s_!oknP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1a20ce6-5b17-4a1f-816f-dc020869bd9e_2295x1742.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The live transcript (minus enrichment) and softphone, in isolation</figcaption></figure></div><p>It's worth mentioning that although <a href="https://help.mypurecloud.com/articles/about-genesys-agent-assist/">Agent Assist</a> displays a live transcript, you cannot enrich it within the UI e.g. tracking real-time sentiment, personalised entity extraction, etc. This was one of the reasons I built a custom implementation.</p><p>So, the first question was how I was going to access the transcript...</p><h2>Approaches to accessing a real-time transcript</h2><p>Genesys Cloud has two methods for accessing a real-time transcript, both easy to integrate with, but each designed for different use-cases. In my case the Notifications API was an obvious fit, as I will explain below.</p><h3>AWS EventBridge Integration</h3><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jovk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27fdc944-5912-46e9-b705-23fb25408b46_986x203.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jovk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27fdc944-5912-46e9-b705-23fb25408b46_986x203.png 424w, https://substackcdn.com/image/fetch/$s_!jovk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27fdc944-5912-46e9-b705-23fb25408b46_986x203.png 848w, https://substackcdn.com/image/fetch/$s_!jovk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27fdc944-5912-46e9-b705-23fb25408b46_986x203.png 1272w, https://substackcdn.com/image/fetch/$s_!jovk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27fdc944-5912-46e9-b705-23fb25408b46_986x203.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jovk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27fdc944-5912-46e9-b705-23fb25408b46_986x203.png" width="590" height="121.47058823529412" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/27fdc944-5912-46e9-b705-23fb25408b46_986x203.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:203,&quot;width&quot;:986,&quot;resizeWidth&quot;:590,&quot;bytes&quot;:60847,&quot;alt&quot;:&quot;Diagram illustrating the integration between Genesys Cloud and AWS. Genesys Cloud sends utterances to AWS EventBridge, which applies a filtering rule before passing events to an AWS Lambda function for further processing.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/158104361?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27fdc944-5912-46e9-b705-23fb25408b46_986x203.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Diagram illustrating the integration between Genesys Cloud and AWS. Genesys Cloud sends utterances to AWS EventBridge, which applies a filtering rule before passing events to an AWS Lambda function for further processing." title="Diagram illustrating the integration between Genesys Cloud and AWS. Genesys Cloud sends utterances to AWS EventBridge, which applies a filtering rule before passing events to an AWS Lambda function for further processing." srcset="https://substackcdn.com/image/fetch/$s_!jovk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27fdc944-5912-46e9-b705-23fb25408b46_986x203.png 424w, https://substackcdn.com/image/fetch/$s_!jovk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27fdc944-5912-46e9-b705-23fb25408b46_986x203.png 848w, https://substackcdn.com/image/fetch/$s_!jovk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27fdc944-5912-46e9-b705-23fb25408b46_986x203.png 1272w, https://substackcdn.com/image/fetch/$s_!jovk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27fdc944-5912-46e9-b705-23fb25408b46_986x203.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Genesys Cloud&#8217;s <a href="https://developer.genesys.cloud/notificationsalerts/notifications/event-bridge">Amazon EventBridge integration</a> can deliver real-time data, from an <a href="https://developer.genesys.cloud/notificationsalerts/notifications/available-topics">ever growing list of topics</a>, to EventBridge in your AWS account. From there you can filter and route data wherever you like.</p><p>This approach is great if you want to process utterances in near real-time for analytical tasks (and <a href="https://www.linkedin.com/posts/lucas-woodward-the-dev_genesys-genesyscloud-github-activity-7256930747653984256--emR?utm_source=share&amp;utm_medium=member_desktop&amp;rcm=ACoAABsbo2wBcmnNqxYJ5UO9BrsfURZcVEtgLOU">other fun use-cases</a>) but wasn't the right fit for what I was doing.</p><h3>Notifications API</h3><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Tg61!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d3a946d-92d8-48f5-815e-3e383976e22f_987x161.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Tg61!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d3a946d-92d8-48f5-815e-3e383976e22f_987x161.png 424w, https://substackcdn.com/image/fetch/$s_!Tg61!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d3a946d-92d8-48f5-815e-3e383976e22f_987x161.png 848w, https://substackcdn.com/image/fetch/$s_!Tg61!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d3a946d-92d8-48f5-815e-3e383976e22f_987x161.png 1272w, https://substackcdn.com/image/fetch/$s_!Tg61!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d3a946d-92d8-48f5-815e-3e383976e22f_987x161.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Tg61!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d3a946d-92d8-48f5-815e-3e383976e22f_987x161.png" width="590" height="96.24113475177305" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6d3a946d-92d8-48f5-815e-3e383976e22f_987x161.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:161,&quot;width&quot;:987,&quot;resizeWidth&quot;:590,&quot;bytes&quot;:42191,&quot;alt&quot;:&quot;Diagram showing Genesys Cloud sending \&quot;Utterances\&quot; via the Notifications API to a browser-based Platform API Client SDK, which then forwards the data to custom user code.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/158104361?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d3a946d-92d8-48f5-815e-3e383976e22f_987x161.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Diagram showing Genesys Cloud sending &quot;Utterances&quot; via the Notifications API to a browser-based Platform API Client SDK, which then forwards the data to custom user code." title="Diagram showing Genesys Cloud sending &quot;Utterances&quot; via the Notifications API to a browser-based Platform API Client SDK, which then forwards the data to custom user code." srcset="https://substackcdn.com/image/fetch/$s_!Tg61!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d3a946d-92d8-48f5-815e-3e383976e22f_987x161.png 424w, https://substackcdn.com/image/fetch/$s_!Tg61!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d3a946d-92d8-48f5-815e-3e383976e22f_987x161.png 848w, https://substackcdn.com/image/fetch/$s_!Tg61!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d3a946d-92d8-48f5-815e-3e383976e22f_987x161.png 1272w, https://substackcdn.com/image/fetch/$s_!Tg61!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d3a946d-92d8-48f5-815e-3e383976e22f_987x161.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>The <a href="https://developer.genesys.cloud/notificationsalerts/notifications/">Notifications API</a>, with its support for delivering real-time events via WebSockets was perfect for my use-case, as it offers:</p><ul><li><p>Events scoped to the agent that is authenticated</p></li><li><p>Low-latency. In my experience, this latency seemed to improve to 2 to 4 seconds around the same time Agent Assist was introduced - though this may be coincidental.</p></li></ul><h2>Iteration 1. Utilising the Embeddable Framework</h2><p>After having made the decision to focus on the Notification API for streaming the real-time transcript of the agent/customer call, I prototyped the simplest solution based on the existing setup.</p><p>The simplest prototype I could come up with was:</p><ol><li><p>Agent navigates to the UI</p></li><li><p>Genesys Cloud's Embedded Framework authenticates the agent against an OAuth Client</p></li><li><p>The auth token from the Embedded Framework is shared with my UI</p></li><li><p>My UI uses this token to talk to Genesys Cloud's Notification API and establish a WebSocket connection</p></li><li><p>It then listens for Conversation Started events from the Embedded Framework to determine when an agent starts a call that needs to be transcribed</p></li><li><p>Upon a call starting, my code requests the channel subscribe to the call&#8217;s live transcript</p></li></ol><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!bQZR!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2be3d90-cd14-43e1-9cf8-189da55b9f2e_987x506.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!bQZR!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2be3d90-cd14-43e1-9cf8-189da55b9f2e_987x506.png 424w, https://substackcdn.com/image/fetch/$s_!bQZR!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2be3d90-cd14-43e1-9cf8-189da55b9f2e_987x506.png 848w, https://substackcdn.com/image/fetch/$s_!bQZR!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2be3d90-cd14-43e1-9cf8-189da55b9f2e_987x506.png 1272w, https://substackcdn.com/image/fetch/$s_!bQZR!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2be3d90-cd14-43e1-9cf8-189da55b9f2e_987x506.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!bQZR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2be3d90-cd14-43e1-9cf8-189da55b9f2e_987x506.png" width="987" height="506" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c2be3d90-cd14-43e1-9cf8-189da55b9f2e_987x506.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:506,&quot;width&quot;:987,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:106937,&quot;alt&quot;:&quot;The diagram shows the interaction between Genesys Cloud and a website. It begins with a login window and OAuth client in Genesys Cloud authenticating with the Genesys Embedded Framework on the website. Once authenticated, a Genesys softphone starts a conversation. A WebSocket connection is created from the website to the Genesys Notification API, and the website subscribes to a transcription topic (v2.conversation.[conversation-id].transcript). Live transcription data is sent to the website&#8217;s code and displayed in a transcription UI.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/158104361?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2be3d90-cd14-43e1-9cf8-189da55b9f2e_987x506.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The diagram shows the interaction between Genesys Cloud and a website. It begins with a login window and OAuth client in Genesys Cloud authenticating with the Genesys Embedded Framework on the website. Once authenticated, a Genesys softphone starts a conversation. A WebSocket connection is created from the website to the Genesys Notification API, and the website subscribes to a transcription topic (v2.conversation.[conversation-id].transcript). Live transcription data is sent to the website&#8217;s code and displayed in a transcription UI." title="The diagram shows the interaction between Genesys Cloud and a website. It begins with a login window and OAuth client in Genesys Cloud authenticating with the Genesys Embedded Framework on the website. Once authenticated, a Genesys softphone starts a conversation. A WebSocket connection is created from the website to the Genesys Notification API, and the website subscribes to a transcription topic (v2.conversation.[conversation-id].transcript). Live transcription data is sent to the website&#8217;s code and displayed in a transcription UI." srcset="https://substackcdn.com/image/fetch/$s_!bQZR!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2be3d90-cd14-43e1-9cf8-189da55b9f2e_987x506.png 424w, https://substackcdn.com/image/fetch/$s_!bQZR!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2be3d90-cd14-43e1-9cf8-189da55b9f2e_987x506.png 848w, https://substackcdn.com/image/fetch/$s_!bQZR!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2be3d90-cd14-43e1-9cf8-189da55b9f2e_987x506.png 1272w, https://substackcdn.com/image/fetch/$s_!bQZR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2be3d90-cd14-43e1-9cf8-189da55b9f2e_987x506.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Iteration 2. Decoupling authentication</h2><p>In the first iteration I chose to share the token for the Embedded Framework with my UI's code. But this is problematic...</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!bzGB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee63baa4-d6ff-42cd-8099-1ca8dc3f154d_987x506.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!bzGB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee63baa4-d6ff-42cd-8099-1ca8dc3f154d_987x506.png 424w, https://substackcdn.com/image/fetch/$s_!bzGB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee63baa4-d6ff-42cd-8099-1ca8dc3f154d_987x506.png 848w, https://substackcdn.com/image/fetch/$s_!bzGB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee63baa4-d6ff-42cd-8099-1ca8dc3f154d_987x506.png 1272w, https://substackcdn.com/image/fetch/$s_!bzGB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee63baa4-d6ff-42cd-8099-1ca8dc3f154d_987x506.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!bzGB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee63baa4-d6ff-42cd-8099-1ca8dc3f154d_987x506.png" width="987" height="506" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ee63baa4-d6ff-42cd-8099-1ca8dc3f154d_987x506.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:506,&quot;width&quot;:987,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:113256,&quot;alt&quot;:&quot;Diagram showing the authentication flow between Genesys Cloud and a website. Genesys Cloud includes a login window and an OAuth client. The user logs in through the Genesys Embedded Framework on the website, which communicates with the login window and OAuth client. Once authenticated, an auth token is passed from the Genesys Embedded Framework to custom code on the website. Other components such as the Notification API and transcription functionality are faded out, indicating they are not part of this step.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/158104361?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee63baa4-d6ff-42cd-8099-1ca8dc3f154d_987x506.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Diagram showing the authentication flow between Genesys Cloud and a website. Genesys Cloud includes a login window and an OAuth client. The user logs in through the Genesys Embedded Framework on the website, which communicates with the login window and OAuth client. Once authenticated, an auth token is passed from the Genesys Embedded Framework to custom code on the website. Other components such as the Notification API and transcription functionality are faded out, indicating they are not part of this step." title="Diagram showing the authentication flow between Genesys Cloud and a website. Genesys Cloud includes a login window and an OAuth client. The user logs in through the Genesys Embedded Framework on the website, which communicates with the login window and OAuth client. Once authenticated, an auth token is passed from the Genesys Embedded Framework to custom code on the website. Other components such as the Notification API and transcription functionality are faded out, indicating they are not part of this step." srcset="https://substackcdn.com/image/fetch/$s_!bzGB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee63baa4-d6ff-42cd-8099-1ca8dc3f154d_987x506.png 424w, https://substackcdn.com/image/fetch/$s_!bzGB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee63baa4-d6ff-42cd-8099-1ca8dc3f154d_987x506.png 848w, https://substackcdn.com/image/fetch/$s_!bzGB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee63baa4-d6ff-42cd-8099-1ca8dc3f154d_987x506.png 1272w, https://substackcdn.com/image/fetch/$s_!bzGB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee63baa4-d6ff-42cd-8099-1ca8dc3f154d_987x506.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>The problem</h3><p>In this initial prototype there were two problems, which had to be fixed before moving forward:</p><ul><li><p>I'd coupled my solution's authentication flow to Genesys Embedded Framework</p></li><li><p>I had to share the token from Genesys Embedded Framework to my code (cross-origin), which increased the risk of it being exposed</p></li></ul><p>At the code level this involved acquiring the token from <a href="https://developer.genesys.cloud/platform/embeddable-framework/actions/User/User.getAuthToken">getAuthToken</a> inside the <a href="https://developer.genesys.cloud/platform/embeddable-framework/purecloud-embeddable-framework-example#example-configuration-and-methods">framework.js</a>, then posting it to the <code>window</code>, which my UI could then receive:</p><pre><code><code>window.PureCloud.subscribe([{
  type: "UserAction",
  callback: function(category) {
    if (category === 'login') {
      window.PureCloud.User.getAuthToken(function(accessToken) {
        // Security risk
        window.parent.postMessage({accessToken}, targetOrigin);
      });
    }
  }
}]);</code></code></pre><p>Implementing this outside of the prototype could have exposed the access token to any JavaScript running in the parent window, along with <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage#security_concerns">other security concerns</a>.</p><h3>The solution</h3><p>Both decoupling the auth flow and sharing the token were solved by having my solution manage its own authentication.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9BEI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e30fafd-8236-4ef6-a4fe-706cd1b48fde_987x506.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9BEI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e30fafd-8236-4ef6-a4fe-706cd1b48fde_987x506.png 424w, https://substackcdn.com/image/fetch/$s_!9BEI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e30fafd-8236-4ef6-a4fe-706cd1b48fde_987x506.png 848w, https://substackcdn.com/image/fetch/$s_!9BEI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e30fafd-8236-4ef6-a4fe-706cd1b48fde_987x506.png 1272w, https://substackcdn.com/image/fetch/$s_!9BEI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e30fafd-8236-4ef6-a4fe-706cd1b48fde_987x506.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9BEI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e30fafd-8236-4ef6-a4fe-706cd1b48fde_987x506.png" width="987" height="506" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2e30fafd-8236-4ef6-a4fe-706cd1b48fde_987x506.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:506,&quot;width&quot;:987,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:120751,&quot;alt&quot;:&quot;Diagram showing a dual-login OAuth authentication flow. Both the Genesys Embedded Framework and the custom code on the website initiate their own login windows with Genesys Cloud. Each login window communicates with the OAuth Clients in Genesys Cloud. After authentication, each receives an auth token. The login windows, OAuth Clients, Embedded Framework, and My Code components are highlighted, while the rest of the diagram (such as Notification API and Transcription UI) is faded out.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/158104361?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e30fafd-8236-4ef6-a4fe-706cd1b48fde_987x506.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Diagram showing a dual-login OAuth authentication flow. Both the Genesys Embedded Framework and the custom code on the website initiate their own login windows with Genesys Cloud. Each login window communicates with the OAuth Clients in Genesys Cloud. After authentication, each receives an auth token. The login windows, OAuth Clients, Embedded Framework, and My Code components are highlighted, while the rest of the diagram (such as Notification API and Transcription UI) is faded out." title="Diagram showing a dual-login OAuth authentication flow. Both the Genesys Embedded Framework and the custom code on the website initiate their own login windows with Genesys Cloud. Each login window communicates with the OAuth Clients in Genesys Cloud. After authentication, each receives an auth token. The login windows, OAuth Clients, Embedded Framework, and My Code components are highlighted, while the rest of the diagram (such as Notification API and Transcription UI) is faded out." srcset="https://substackcdn.com/image/fetch/$s_!9BEI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e30fafd-8236-4ef6-a4fe-706cd1b48fde_987x506.png 424w, https://substackcdn.com/image/fetch/$s_!9BEI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e30fafd-8236-4ef6-a4fe-706cd1b48fde_987x506.png 848w, https://substackcdn.com/image/fetch/$s_!9BEI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e30fafd-8236-4ef6-a4fe-706cd1b48fde_987x506.png 1272w, https://substackcdn.com/image/fetch/$s_!9BEI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e30fafd-8236-4ef6-a4fe-706cd1b48fde_987x506.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Implementing your own login flow for Genesys Cloud is as easy as creating an OAuth Client and calling their <a href="https://www.npmjs.com/package/purecloud-platform-client-v2">Platform API Client SDK</a>:</p><pre><code>const apiClient = platformClient.ApiClient.instance;  
apiClient  
  .loginPKCEGrant(clientId, redirectUri)  
  .then((authData) =&gt; {
    // ...
  }).catch((error) =&gt; {
    // ...
  })</code></pre><h3>Iteration 3. Preventing refreshes from losing utterances</h3><p>One interesting problem I encountered was that transcription events were missed when agents refreshed their browser.</p><p>The reason was simple, during the page refresh the WebSocket connection to the Notification API was closed, then in spite of me promptly reestablishing it on the page loading there is a brief window where I am not subscribed to the topic. Any utterance sent during this period is lost, with no way of being replayed.</p><p>The solution happened to be a popup window&#8230;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kgVj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff4301dc-4d05-4ac4-9ce2-2302646f7462_992x574.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kgVj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff4301dc-4d05-4ac4-9ce2-2302646f7462_992x574.png 424w, https://substackcdn.com/image/fetch/$s_!kgVj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff4301dc-4d05-4ac4-9ce2-2302646f7462_992x574.png 848w, https://substackcdn.com/image/fetch/$s_!kgVj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff4301dc-4d05-4ac4-9ce2-2302646f7462_992x574.png 1272w, https://substackcdn.com/image/fetch/$s_!kgVj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff4301dc-4d05-4ac4-9ce2-2302646f7462_992x574.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kgVj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff4301dc-4d05-4ac4-9ce2-2302646f7462_992x574.png" width="992" height="574" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ff4301dc-4d05-4ac4-9ce2-2302646f7462_992x574.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:574,&quot;width&quot;:992,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:123026,&quot;alt&quot;:&quot;Diagram showing separate OAuth login flows initiated independently by the Genesys Embedded Framework and a popup window on the website. Both the framework and the popup open their own login windows, which authenticate through Genesys Cloud&#8217;s OAuth Clients. Once a conversation is started via the Genesys Softphone, a WebSocket connection is established with the Genesys Notification API. The popup window&#8217;s custom code subscribes to the transcription topic and receives live transcriptions, which are passed to the transcription UI. The popup window and its custom code are highlighted.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/158104361?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff4301dc-4d05-4ac4-9ce2-2302646f7462_992x574.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Diagram showing separate OAuth login flows initiated independently by the Genesys Embedded Framework and a popup window on the website. Both the framework and the popup open their own login windows, which authenticate through Genesys Cloud&#8217;s OAuth Clients. Once a conversation is started via the Genesys Softphone, a WebSocket connection is established with the Genesys Notification API. The popup window&#8217;s custom code subscribes to the transcription topic and receives live transcriptions, which are passed to the transcription UI. The popup window and its custom code are highlighted." title="Diagram showing separate OAuth login flows initiated independently by the Genesys Embedded Framework and a popup window on the website. Both the framework and the popup open their own login windows, which authenticate through Genesys Cloud&#8217;s OAuth Clients. Once a conversation is started via the Genesys Softphone, a WebSocket connection is established with the Genesys Notification API. The popup window&#8217;s custom code subscribes to the transcription topic and receives live transcriptions, which are passed to the transcription UI. The popup window and its custom code are highlighted." srcset="https://substackcdn.com/image/fetch/$s_!kgVj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff4301dc-4d05-4ac4-9ce2-2302646f7462_992x574.png 424w, https://substackcdn.com/image/fetch/$s_!kgVj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff4301dc-4d05-4ac4-9ce2-2302646f7462_992x574.png 848w, https://substackcdn.com/image/fetch/$s_!kgVj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff4301dc-4d05-4ac4-9ce2-2302646f7462_992x574.png 1272w, https://substackcdn.com/image/fetch/$s_!kgVj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff4301dc-4d05-4ac4-9ce2-2302646f7462_992x574.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Having wondered how the Genesys softphone maintained its audio connection I realised the obvious, it has a popup window, which survives any refresh of the page containing the softphone.</p><p>The code refactor for this change was big, and involved me shifting all the logic for authentication and Notification API subscription into the popup window.</p><p>The UI was now very thin, and was just receiving utterances emitted from the popup window via a <a href="https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API">Broadcast Channel</a> - possible since they're in the <a href="https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy">same origin</a>:</p><pre><code>/* Within popup */

// Create channel
const channel = new BroadcastChannel("transcription-events");

// ...

// Post events from Notification API to channel 
this.ws.onmessage = (event: any) =&gt; {
  // ... validate and transform payload ... 
  
  channel.postMessage({
    type: "transcription-updated",
    data: transcriptionUpdate
  });
};</code></pre><p>There was also logic written to monitor whether a popup window was already open, so I didn't open multiple of them.</p><h3>What if my UI and Popup were on different domains?</h3><p>The Broadcast Channel above only works because the UI and popup are on the same domain. If they weren't then they would be considered '<a href="https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#cross-origin_network_access">cross-origin</a>', resulting in a lot more restrictions by the browser in how they can communicate. In this case I would have relied on the much inferior <code>postMessage</code> call.</p><pre><code>/* Within UI */

// Open popup
const popupRef = window.open(
  popupUrl,
  popupName,
  'width=450px,height=450px,status,opener',
);

// Send message to popup
popupRef.postMessage(event, origin);

// Receive messages from popup
window.addEventListener('message', (event: MessageEvent) =&gt; {
  // ... Validate event.origin ...
  // ... Validate payload ...
  
  processMessageFromPopup(event);
});</code></pre><h2>Conclusion</h2><p>This was a fairly brief look into the iterations that went into building a resilient and secure real-time transcript feature based on Genesys Cloud's Notification API. </p><p>I hope that in spite of its brevity, it was of some interest. It was certainly cathartic to write!</p><p>If anything here sparked an idea or improvement then I'd love to know! I&#8217;m also very happy to answer any questions you may have, just <a href="https://www.linkedin.com/in/lucas-woodward-the-dev/">ping me on LinkedIn</a>.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://makingchatbots.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Automated tests using Genesys Cloud's WebRTC softphone]]></title><description><![CDATA[Manually testing a UI that relies on Genesys Cloud's Softphone and Notifications API can be a time-consuming and fragile process.]]></description><link>https://makingchatbots.com/p/automated-tests-using-genesys-clouds</link><guid isPermaLink="false">https://makingchatbots.com/p/automated-tests-using-genesys-clouds</guid><dc:creator><![CDATA[Lucas Woodward]]></dc:creator><pubDate>Tue, 22 Oct 2024 22:12:32 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!FIwu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11767d54-09e8-40c9-b8e3-a26c71b84ee9_1080x485.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Manually testing a UI that relies on Genesys Cloud's Softphone and Notifications API can be a time-consuming and fragile process. It requires playing both customer and agent roles to simulate specific conversations - at least that's what I found. To save time, and increase confidence in what I was building, I automated these tests. At the time I <a href="https://www.linkedin.com/posts/lucas-woodward-the-dev_genesys-genesyscloud-webrtc-activity-7180853577681117184-ae0R?utm_source=share&amp;utm_medium=member_desktop">posted about this on LinkedIn</a> and got so much interest that I thought I&#8217;d write a blog post about how the tests work.</p><p>My end-to-end tests have three stages:</p><ol><li><p>Automate a call to a phone number setup in a Genesys Cloud org and simulate a customer speaking</p></li><li><p>Answer the call in the softphone and simulate an agent speaking</p></li><li><p>Assert the feature I&#8217;ve developed behaves as expected</p></li></ol><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FIwu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11767d54-09e8-40c9-b8e3-a26c71b84ee9_1080x485.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FIwu!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11767d54-09e8-40c9-b8e3-a26c71b84ee9_1080x485.png 424w, https://substackcdn.com/image/fetch/$s_!FIwu!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11767d54-09e8-40c9-b8e3-a26c71b84ee9_1080x485.png 848w, https://substackcdn.com/image/fetch/$s_!FIwu!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11767d54-09e8-40c9-b8e3-a26c71b84ee9_1080x485.png 1272w, https://substackcdn.com/image/fetch/$s_!FIwu!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11767d54-09e8-40c9-b8e3-a26c71b84ee9_1080x485.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FIwu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11767d54-09e8-40c9-b8e3-a26c71b84ee9_1080x485.png" width="1080" height="485" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/11767d54-09e8-40c9-b8e3-a26c71b84ee9_1080x485.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:485,&quot;width&quot;:1080,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:128154,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!FIwu!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11767d54-09e8-40c9-b8e3-a26c71b84ee9_1080x485.png 424w, https://substackcdn.com/image/fetch/$s_!FIwu!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11767d54-09e8-40c9-b8e3-a26c71b84ee9_1080x485.png 848w, https://substackcdn.com/image/fetch/$s_!FIwu!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11767d54-09e8-40c9-b8e3-a26c71b84ee9_1080x485.png 1272w, https://substackcdn.com/image/fetch/$s_!FIwu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11767d54-09e8-40c9-b8e3-a26c71b84ee9_1080x485.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>If the assertions pass then I know my feature is correctly integrated and using Genesys Cloud&#8217;s Notification API, Embedded Framework and Softphone. This reduced feedback loop allows me to develop the UI feature much faster, and with greater confidence than if I relied solely on manual testing.</p><h1>Tools I use</h1><p>Below are the tools I use for my tests, and what they were used for:</p><ol><li><p><a href="https://pptr.dev/">Puppeteer</a> - Opening the website containing my feature and giving me control of the page to do step 2 and 3</p></li><li><p><a href="https://gist.github.com/SketchingDev/00128173c26dae841a5057803fa4503a">MediaStream API Mocker</a> - Overriding the MediaStream API so I could receive the audio the agent would hear and stream audio simulating the agent speaking </p></li><li><p><a href="https://gist.github.com/SketchingDev/4b0a632e457b724b4eee9d95c5596208">Softphone UI POM</a> - Simplifying the control of Genesys Cloud&#8217;s Softphone in the website, making it easy to answer a call the way an agent would and ensuring the same events are fired from the Embedded Framework as you&#8217;d expect in the real scenario</p></li><li><p><a href="https://github.com/MakingChatbots/ivr-tester">IVR Tester</a> - Phones the agent and pretends to be the customer</p></li></ol><h1>How the tests work</h1><h2>Opening the website under test</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GJ7J!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa662d88-656d-4105-bf71-6a045edfbfbb_1080x485.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GJ7J!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa662d88-656d-4105-bf71-6a045edfbfbb_1080x485.png 424w, https://substackcdn.com/image/fetch/$s_!GJ7J!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa662d88-656d-4105-bf71-6a045edfbfbb_1080x485.png 848w, https://substackcdn.com/image/fetch/$s_!GJ7J!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa662d88-656d-4105-bf71-6a045edfbfbb_1080x485.png 1272w, https://substackcdn.com/image/fetch/$s_!GJ7J!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa662d88-656d-4105-bf71-6a045edfbfbb_1080x485.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GJ7J!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa662d88-656d-4105-bf71-6a045edfbfbb_1080x485.png" width="1080" height="485" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/aa662d88-656d-4105-bf71-6a045edfbfbb_1080x485.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:485,&quot;width&quot;:1080,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:100594,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!GJ7J!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa662d88-656d-4105-bf71-6a045edfbfbb_1080x485.png 424w, https://substackcdn.com/image/fetch/$s_!GJ7J!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa662d88-656d-4105-bf71-6a045edfbfbb_1080x485.png 848w, https://substackcdn.com/image/fetch/$s_!GJ7J!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa662d88-656d-4105-bf71-6a045edfbfbb_1080x485.png 1272w, https://substackcdn.com/image/fetch/$s_!GJ7J!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa662d88-656d-4105-bf71-6a045edfbfbb_1080x485.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The website containing my feature, and the softphone are controlled via a <a href="https://pptr.dev/">Puppeteer test script</a>. The first step of this test script is to launch the browser and point it to my website:</p><pre><code>const browser = await <em>puppeteer</em>.launch({
  headless: false,
  userDataDir: "./user_data",
  defaultViewport: null,
  args: [
    "--use-fake-device-for-media-stream",
    "--disable-features=site-per-process",
    "--allow-file-access",
    "--no-sandbox",
    "--autoplay-policy=no-user-gesture-required"
  ],
});

const page = await browser.newPage();
await page.goto("http://localhost:8080");</code></pre><p>The following two parameters from above ensure I can manually perform the browser-based auth required by the softphone, and persist the token for future tests:</p><pre><code>headless: false,
userDataDir: "./user_data",</code></pre><p><em>Although I prefer to login manually for the first test, and have the token reused for future tests until it expires, you could just automate the login process too.</em></p><h2>Impersonating an agent over the softphone</h2><p>The confidence that my feature will work comes from the fact the tests are as realistic as possible, and one facet of this is simulating the agent speaking over the sofphone.</p><p>To achieve this I override the Browser&#8217;s MediaStream API which is the mechanism through which the softphone receives audio from the agent&#8217;s headset. This allows me to:</p><ul><li><p>Capture the audio coming from the softphone</p></li><li><p>Stream my own audio that goes to the softphone </p></li></ul><h3>Overriding the MediaStream API</h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pHjX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c82aae8-ef43-48ae-ae33-60f180b93de6_1080x485.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pHjX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c82aae8-ef43-48ae-ae33-60f180b93de6_1080x485.png 424w, https://substackcdn.com/image/fetch/$s_!pHjX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c82aae8-ef43-48ae-ae33-60f180b93de6_1080x485.png 848w, https://substackcdn.com/image/fetch/$s_!pHjX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c82aae8-ef43-48ae-ae33-60f180b93de6_1080x485.png 1272w, https://substackcdn.com/image/fetch/$s_!pHjX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c82aae8-ef43-48ae-ae33-60f180b93de6_1080x485.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pHjX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c82aae8-ef43-48ae-ae33-60f180b93de6_1080x485.png" width="1080" height="485" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5c82aae8-ef43-48ae-ae33-60f180b93de6_1080x485.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:485,&quot;width&quot;:1080,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:103801,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!pHjX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c82aae8-ef43-48ae-ae33-60f180b93de6_1080x485.png 424w, https://substackcdn.com/image/fetch/$s_!pHjX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c82aae8-ef43-48ae-ae33-60f180b93de6_1080x485.png 848w, https://substackcdn.com/image/fetch/$s_!pHjX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c82aae8-ef43-48ae-ae33-60f180b93de6_1080x485.png 1272w, https://substackcdn.com/image/fetch/$s_!pHjX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c82aae8-ef43-48ae-ae33-60f180b93de6_1080x485.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>Firstly, there is an option available when opening the browser to specify an audio file that it will play over a Media Device (below), however this is simply played on repeat. I want to control what is said and when.</p><pre><code><code>--use-file-for-fake-audio-capture=&lt;PATH-TO-FILE&gt;</code></code></pre><p>The solution I use is Puppeteer&#8217;s .<code>evaluate(...) </code>function. This function allows me to run code inside any browser window, which means I can run code inside the softphone&#8217;s iframe <a href="https://gist.github.com/SketchingDev/00128173c26dae841a5057803fa4503a">that replaces the MediaStreams API with a mock</a>. I can then control the audio coming in and out of this mock:</p><pre><code>// 1. Read in the JS code for mocking the MediaStreams API
const mockMediaDevicesScript = readFileSync(
"https://gist.githubusercontent.com/SketchingDev/00128173c26dae841a5057803fa4503a/raw/fea356b4117c6981693e8ac9eea2f3c52261ac45/mocked_media_stream.bundle.js",
"utf8");

// 2. Get IFrame for WebRTC phone
const webRtcFrame = await browser.waitForTarget((page) =&gt;
   page.url().includes("/crm/webrtc.html"),
);

// 3. Run the script within the WebRTC frame to replace the MediaStream API
await webRtcFrame.evaluate(mockMediaDevicesScript);

// 4. Run a JavaScript function within the IFrame when you want to play an audio file against the MediaStream
webRtcFrame.evaluate((fileNameIn) =&gt; {
    window.mockMediaDevice.playAudio(fileNameIn);
}, `http://localhost:8080/${filename}`);</code></pre><p><a href="https://gist.github.com/SketchingDev/00128173c26dae841a5057803fa4503a">See my full guide on mocking the MediaStream API</a>.</p><h2>Phoning as the customer</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ghkt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0190fa3c-8376-4530-ae2b-724deec1bccd_1080x485.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ghkt!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0190fa3c-8376-4530-ae2b-724deec1bccd_1080x485.png 424w, https://substackcdn.com/image/fetch/$s_!ghkt!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0190fa3c-8376-4530-ae2b-724deec1bccd_1080x485.png 848w, https://substackcdn.com/image/fetch/$s_!ghkt!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0190fa3c-8376-4530-ae2b-724deec1bccd_1080x485.png 1272w, https://substackcdn.com/image/fetch/$s_!ghkt!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0190fa3c-8376-4530-ae2b-724deec1bccd_1080x485.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ghkt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0190fa3c-8376-4530-ae2b-724deec1bccd_1080x485.png" width="1080" height="485" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0190fa3c-8376-4530-ae2b-724deec1bccd_1080x485.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:485,&quot;width&quot;:1080,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:114685,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ghkt!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0190fa3c-8376-4530-ae2b-724deec1bccd_1080x485.png 424w, https://substackcdn.com/image/fetch/$s_!ghkt!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0190fa3c-8376-4530-ae2b-724deec1bccd_1080x485.png 848w, https://substackcdn.com/image/fetch/$s_!ghkt!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0190fa3c-8376-4530-ae2b-724deec1bccd_1080x485.png 1272w, https://substackcdn.com/image/fetch/$s_!ghkt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0190fa3c-8376-4530-ae2b-724deec1bccd_1080x485.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">IVR Tester streams audio over call to Agent&#8217;s Media Device via WebRTC Phone</figcaption></figure></div><p><a href="https://github.com/MakingChatbots/ivr-tester">IVR Tester</a> is an open-source project I built that uses Twilio to automate a customer calling a phone number. The code (<a href="https://github.com/MakingChatbots/ivr-tester/tree/v1-rewrite">based on an ongoing project rewrite</a>) to call the agent&#8217;s queue looks like:</p><pre><code>const result = await ivrTester.run(
  { from: "0123 456 789", to: process.env.GENESYS_PHONE_NUMBER },
  openAiWhisperChat("You are a customer wanting to ....")
)</code></pre><p>I&#8217;ve not gone into detail on this part as I would like to dedicate a blog article to demonstrating how to make AI-driven calls for testing. Subscribe, or <a href="https://www.linkedin.com/in/lucas-woodward-the-dev/">follow me on LinkedIn</a> to know when I post the article.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://makingchatbots.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://makingchatbots.com/subscribe?"><span>Subscribe now</span></a></p><h2>Answering as the agent</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!oqUI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe80d2d78-1ae2-4f5b-b590-259bddcc1b4d_1080x485.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!oqUI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe80d2d78-1ae2-4f5b-b590-259bddcc1b4d_1080x485.png 424w, https://substackcdn.com/image/fetch/$s_!oqUI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe80d2d78-1ae2-4f5b-b590-259bddcc1b4d_1080x485.png 848w, https://substackcdn.com/image/fetch/$s_!oqUI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe80d2d78-1ae2-4f5b-b590-259bddcc1b4d_1080x485.png 1272w, https://substackcdn.com/image/fetch/$s_!oqUI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe80d2d78-1ae2-4f5b-b590-259bddcc1b4d_1080x485.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!oqUI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe80d2d78-1ae2-4f5b-b590-259bddcc1b4d_1080x485.png" width="1080" height="485" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e80d2d78-1ae2-4f5b-b590-259bddcc1b4d_1080x485.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:485,&quot;width&quot;:1080,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:112358,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!oqUI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe80d2d78-1ae2-4f5b-b590-259bddcc1b4d_1080x485.png 424w, https://substackcdn.com/image/fetch/$s_!oqUI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe80d2d78-1ae2-4f5b-b590-259bddcc1b4d_1080x485.png 848w, https://substackcdn.com/image/fetch/$s_!oqUI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe80d2d78-1ae2-4f5b-b590-259bddcc1b4d_1080x485.png 1272w, https://substackcdn.com/image/fetch/$s_!oqUI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe80d2d78-1ae2-4f5b-b590-259bddcc1b4d_1080x485.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Answering a call via the softphone is done by simulating clicks within the softphone&#8217;s UI. Here is the code that uses <a href="https://gist.github.com/SketchingDev/4b0a632e457b724b4eee9d95c5596208">a Page Object Model I created</a> to simplify answering the call by waiting for a call and then clicking the Answer button:</p><pre><code>// 1. Find the softphone page
const frame = await page.waitForFrame((frame) =&gt;
  frame.url().includes("/crm/embeddableFramework.html"),
);

// 2. Pass that into the softphone helper
const softphone = await webRtcSoftphone(frame);

// 3. Waits at most 30 seconds for a call to answer
await softphone.waitForCallThenAnswer(30000);</code></pre><p>I have <a href="https://gist.github.com/SketchingDev/4b0a632e457b724b4eee9d95c5596208">shared the code for the Page Object Mode in GitHub</a>.</p><h3>Listening to the simulated customer</h3><p>It would have been sufficient for my purposes to have the simulated customer and agent speaking across each other with phrases my feature was designed to pick up on. However, where would the fun be in that, so I instead leveraged <a href="https://developer.genesys.cloud/notificationsalerts/notifications/available-topics#v2-conversations--id--transcription">Genesys Cloud&#8217;s transcription topic</a> to get the agent to respond with a sensible reply, allowing the agent and customer to converse thanks to OpenAI&#8217;s APIs.</p><h2>Asserting the UI behaviour</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GHfI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb327e6e6-34c0-46a9-bf37-086d76d562f4_1080x485.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GHfI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb327e6e6-34c0-46a9-bf37-086d76d562f4_1080x485.png 424w, https://substackcdn.com/image/fetch/$s_!GHfI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb327e6e6-34c0-46a9-bf37-086d76d562f4_1080x485.png 848w, https://substackcdn.com/image/fetch/$s_!GHfI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb327e6e6-34c0-46a9-bf37-086d76d562f4_1080x485.png 1272w, https://substackcdn.com/image/fetch/$s_!GHfI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb327e6e6-34c0-46a9-bf37-086d76d562f4_1080x485.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GHfI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb327e6e6-34c0-46a9-bf37-086d76d562f4_1080x485.png" width="1080" height="485" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b327e6e6-34c0-46a9-bf37-086d76d562f4_1080x485.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:485,&quot;width&quot;:1080,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:119969,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!GHfI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb327e6e6-34c0-46a9-bf37-086d76d562f4_1080x485.png 424w, https://substackcdn.com/image/fetch/$s_!GHfI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb327e6e6-34c0-46a9-bf37-086d76d562f4_1080x485.png 848w, https://substackcdn.com/image/fetch/$s_!GHfI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb327e6e6-34c0-46a9-bf37-086d76d562f4_1080x485.png 1272w, https://substackcdn.com/image/fetch/$s_!GHfI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb327e6e6-34c0-46a9-bf37-086d76d562f4_1080x485.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>As the test conversation progressed I checked my feature was behaving as expected. Here&#8217;s an example of some of the code checking that the customer&#8217;s name was correctly extracted: </p><pre><code>const customerFullName = await page.$eval(
  "input#staticFullName",
  (input) =&gt; input.value,
);

assert.strictEqual(customerFullName, "Mr Test");</code></pre><p>It is possible to <a href="https://jestjs.io/docs/puppeteer">integrate Puppeteer into Jest</a>, allowing you to take advantage of existing Jest assertions.</p><h1>Conclusion</h1><p>Hopefully breaking down each part of my automated tests has shown how easy they are to setup. With these tests I can quickly iterate on my feature with confidence that it is behaving as expected.</p><p>It&#8217;s worth pointing out that end to end tests should be used sparingly, as they take longer to run and usually become flaky over time. The <a href="https://sketchingdev.co.uk/sketchnotes/testing-pyramid.html">testing pyramid</a> offers a sensible breakdown of the ratio of each type of test.</p><p>Undoubtedly there are many improvements to be made, and if you find any I&#8217;d love to hear about them!</p>]]></content:encoded></item><item><title><![CDATA[Let’s test a Genesys chatbot with AI]]></title><description><![CDATA[Let&#8217;s create an automated test for our Genesys chatbot that leverages the latest in Generative AI!]]></description><link>https://makingchatbots.com/p/lets-test-a-genesys-chatbot-with-aihtml</link><guid isPermaLink="false">https://makingchatbots.com/p/lets-test-a-genesys-chatbot-with-aihtml</guid><dc:creator><![CDATA[Lucas Woodward]]></dc:creator><pubDate>Mon, 04 Dec 2023 00:00:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07aad6bf-8599-4772-83b1-3b4dec97a401_1320x574.gif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Let&#8217;s create an automated test for our Genesys chatbot that leverages the latest in Generative AI! In this article I thought it might be fun to demonstrate the new feature I created for an <a href="https://github.com/MakingChatbots/genesys-cloud-chatbot-tester">open-source testing tool I created</a>, which I <a href="https://www.linkedin.com/feed/update/urn:li:activity:7132394543659782146/">recently posted about</a>. It&#8217;s super simple to use, so you could even follow along with your own chatbot.</p><p>Let&#8217;s jump straight in and install the tool!</p><h2>Installing Genesys Cloud Chatbot Tester</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!SDQK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa718513d-a0f6-4b44-8722-1c35e2958fa4_1464x618.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!SDQK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa718513d-a0f6-4b44-8722-1c35e2958fa4_1464x618.gif 424w, https://substackcdn.com/image/fetch/$s_!SDQK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa718513d-a0f6-4b44-8722-1c35e2958fa4_1464x618.gif 848w, https://substackcdn.com/image/fetch/$s_!SDQK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa718513d-a0f6-4b44-8722-1c35e2958fa4_1464x618.gif 1272w, https://substackcdn.com/image/fetch/$s_!SDQK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa718513d-a0f6-4b44-8722-1c35e2958fa4_1464x618.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!SDQK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa718513d-a0f6-4b44-8722-1c35e2958fa4_1464x618.gif" width="1456" height="615" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a718513d-a0f6-4b44-8722-1c35e2958fa4_1464x618.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:615,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:496226,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://makingchatbots.com/i/148716950?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa718513d-a0f6-4b44-8722-1c35e2958fa4_1464x618.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!SDQK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa718513d-a0f6-4b44-8722-1c35e2958fa4_1464x618.gif 424w, https://substackcdn.com/image/fetch/$s_!SDQK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa718513d-a0f6-4b44-8722-1c35e2958fa4_1464x618.gif 848w, https://substackcdn.com/image/fetch/$s_!SDQK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa718513d-a0f6-4b44-8722-1c35e2958fa4_1464x618.gif 1272w, https://substackcdn.com/image/fetch/$s_!SDQK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa718513d-a0f6-4b44-8722-1c35e2958fa4_1464x618.gif 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><a href="https://github.com/MakingChatbots/genesys-cloud-chatbot-tester">Genesys Cloud Chatbot Tester</a> is a command-line application you install on your machine. It&#8217;s free, open-source, works on Windows, Mac and Linux and is versatile enough to be integrated into <a href="https://makingchatbots.com/blog/automating-development-of-genesys-chatbotshtml">automated pipelines</a>, as well as run locally on your machine.</p><p>Although we&#8217;ll be creating an AI-based test, you can also use it to write more conventional <a href="https://github.com/MakingChatbots/genesys-cloud-chatbot-tester#testing-with-scripted-dialogues">dialogue based tests</a>.</p><p>To install it just open the command-line and run:</p><pre><code>npm install -g @makingchatbots/genesys-cloud-chatbot-tester-cli</code></pre><p><em>If your computer complains that you don&#8217;t have NPM or Node.js then you can download the installer at <a href="https://nodejs.org/">nodejs.org</a>.</em></p><h2>Creating an API key for OpenAI</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tPmV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77aae5ed-e631-4036-bf37-099c25f500e2_1896x708.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tPmV!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77aae5ed-e631-4036-bf37-099c25f500e2_1896x708.png 424w, https://substackcdn.com/image/fetch/$s_!tPmV!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77aae5ed-e631-4036-bf37-099c25f500e2_1896x708.png 848w, https://substackcdn.com/image/fetch/$s_!tPmV!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77aae5ed-e631-4036-bf37-099c25f500e2_1896x708.png 1272w, https://substackcdn.com/image/fetch/$s_!tPmV!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77aae5ed-e631-4036-bf37-099c25f500e2_1896x708.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tPmV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77aae5ed-e631-4036-bf37-099c25f500e2_1896x708.png" width="1456" height="544" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/77aae5ed-e631-4036-bf37-099c25f500e2_1896x708.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:544,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;API Keys page in OpenAI's User Settings&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="API Keys page in OpenAI's User Settings" title="API Keys page in OpenAI's User Settings" srcset="https://substackcdn.com/image/fetch/$s_!tPmV!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77aae5ed-e631-4036-bf37-099c25f500e2_1896x708.png 424w, https://substackcdn.com/image/fetch/$s_!tPmV!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77aae5ed-e631-4036-bf37-099c25f500e2_1896x708.png 848w, https://substackcdn.com/image/fetch/$s_!tPmV!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77aae5ed-e631-4036-bf37-099c25f500e2_1896x708.png 1272w, https://substackcdn.com/image/fetch/$s_!tPmV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77aae5ed-e631-4036-bf37-099c25f500e2_1896x708.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The testing tool leverages OpenAI&#8217;s ChatGPT to realistically converse with your chatbots during the tests. However, to be able to use OpenAI&#8217;s API you will need an API key.</p><p>Getting an API key is as easy as:</p><ol><li><p><a href="https://openai.com/">Going to OpenAI</a> and creating an account (if you don&#8217;t already have one)</p></li><li><p>Following their <a href="https://help.openai.com/en/articles/4936850-where-do-i-find-my-api-key">instructions for creating an API key</a></p></li><li><p>Following their <a href="https://platform.openai.com/docs/quickstart/step-2-setup-your-api-key">guide to set your API Key</a> on the same computer as the testing tool</p></li></ol><p><em>Whilst my tool is free, using OpenAI&#8217;s API is not - although its pricing seems reasonable, and is usage based.</em></p><h2>Writing our automated AI test</h2><p>Now the fun part, writing our test. A test is defined in a file (a YAML formatted file to be precise) and contains 3 notable parts:</p><ol><li><p><code>deploymentId</code> - The ID of our Web Messenger Deployment that we want to test</p></li><li><p><code>prompt</code> - The Prompt used to instruct ChatGPT how we want it to interact with our bot (more on this below)</p></li><li><p><code>terminatingPhrases</code> - The phrases we want the testing tool to look out for that indicate whether the test passed or failed</p></li></ol><p>We can see these 3 parts in the config file for our test:</p><pre><code>config:
  deploymentId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
  region: xxxx.pure.cloud
  ai:
    provider: chatgpt
scenarios:
  "Chatbot recognises ISBN numbers":
    setup:
      prompt: |
        I want you to play the role of a customer talking to a company's
        online chatbot. You must not break from this role, and all of
        your responses must be based on how a customer would
        realistically talk to a company's chatbot.

        To help you play the role of a customer consider the following 
        points when writing a response:
          * Respond to questions as a customer would to a chatbot
          * Answer with the exact word when given options e.g. if asked
            to answer with either 'yes' or 'no' answer with either 'yes'
            or 'no' without punctuation, such as full stops

        As a customer you would like to get more information for a book,
        based on its ISBN.
        Provide the ISBN 0141439513 and if the title is Jane Austen's
        Pride and Prejudice then say 'PASS' else say 'FAIL' along with
        the reason why you failed.

        If you have understood your role and the purpose of your
        conversation with the company's chatbot then say the word
        'Hello' and nothing else.
      terminatingPhrases:
        pass: ["PASS"]
        fail: ["FAIL"]
</code></pre><h3>Instructing ChatGPT on what to test</h3><p>The prompt section instructs ChatGPT of the role it will be playing when conversing with our chatbot, and what we want it to achieve.</p><p>Getting the prompt just right for your tests can involve a bit of trial and error, but <a href="https://help.openai.com/en/articles/4936848-how-do-i-create-a-good-prompt">there are plenty of guides to help you</a>.</p><h3>Deciding when a test passes or fails</h3><p>The <code>terminatingPhrases</code> are what my tool is looking out for during the conversation. Depending on which one it sees in the response from ChatGPT it will either pass or fail the test.</p><p>In the test above the prompt is instructing ChatGPT to use the words <code>PASS</code> or <code>FAIL</code>.</p><h2>Running the test</h2><p>With the tool installed, OpenAI&#8217;s key set and a test file defined we can now run the test! This is as easy as running the command below and pointing it at the test file we defined above:</p><pre><code>genesys-cloud-chatbot-tester ai test.yaml</code></pre><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;785b80b4-6082-44be-b6cf-280a0befe602&quot;,&quot;duration&quot;:null}"></div><p>It&#8217;s that simple! If you end up using this tool I&#8217;d love to hear how you got on, or what improvements you think could be made to the tool.</p><p>Like what you read? Follow me on <a href="https://www.linkedin.com/in/lucas-woodward-the-dev/">LinkedIn</a> to be notified of future articles.</p>]]></content:encoded></item><item><title><![CDATA[Creating a realtime reporting tool for Genesys flows]]></title><description><![CDATA[At OVO our Architect flows serve customers over 100k times a day, so making sure they work as expected is imperative.]]></description><link>https://makingchatbots.com/p/creating-a-realtime-reporting-tool-for-genesys-flowshtml</link><guid isPermaLink="false">https://makingchatbots.com/p/creating-a-realtime-reporting-tool-for-genesys-flowshtml</guid><dc:creator><![CDATA[Lucas Woodward]]></dc:creator><pubDate>Wed, 19 Apr 2023 00:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/4e20b533-4fb4-4a28-ae1f-45ad21203019_1084x718.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>At OVO our Architect flows serve customers over 100k times a day, so making sure they work as expected is imperative. This was my motivation for creating a tool that captures metrics from any point of a flow in realtime, and display them in the same observability platform used by all the OVO services the flows depend on.</p><p>So far the tool has:</p><ul><li><p>Alerted us to major incidents within seconds of the first customer being affected</p></li><li><p>Provided a realtime insight into customer behaviour across flows and chatbots</p></li><li><p>Measured the success of A/B testing</p></li><li><p>Detected unexpected behaviour, allowing us to pinpoint the external factors influencing customers</p></li><li><p>Allowed all the above to be correlated to services across the business e.g. aiding us in pinpointing the service that is causing slowdown in a flow</p></li></ul><p>Here&#8217;s an example dashboard that leverages the metrics produced by the tool:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0B5B!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02cdc3ac-5bee-4a7c-839c-f1e1b2cdaeb4_1956x620.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0B5B!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02cdc3ac-5bee-4a7c-839c-f1e1b2cdaeb4_1956x620.png 424w, https://substackcdn.com/image/fetch/$s_!0B5B!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02cdc3ac-5bee-4a7c-839c-f1e1b2cdaeb4_1956x620.png 848w, https://substackcdn.com/image/fetch/$s_!0B5B!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02cdc3ac-5bee-4a7c-839c-f1e1b2cdaeb4_1956x620.png 1272w, https://substackcdn.com/image/fetch/$s_!0B5B!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02cdc3ac-5bee-4a7c-839c-f1e1b2cdaeb4_1956x620.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0B5B!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02cdc3ac-5bee-4a7c-839c-f1e1b2cdaeb4_1956x620.png" width="1456" height="462" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/02cdc3ac-5bee-4a7c-839c-f1e1b2cdaeb4_1956x620.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:462,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!0B5B!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02cdc3ac-5bee-4a7c-839c-f1e1b2cdaeb4_1956x620.png 424w, https://substackcdn.com/image/fetch/$s_!0B5B!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02cdc3ac-5bee-4a7c-839c-f1e1b2cdaeb4_1956x620.png 848w, https://substackcdn.com/image/fetch/$s_!0B5B!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02cdc3ac-5bee-4a7c-839c-f1e1b2cdaeb4_1956x620.png 1272w, https://substackcdn.com/image/fetch/$s_!0B5B!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02cdc3ac-5bee-4a7c-839c-f1e1b2cdaeb4_1956x620.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>How does it work?</h2><p>The tool is very simple. It captures specially formatted Participant Data attributes set in flows and uses these to indicate metrics that it pushes to our observability/monitoring platform, DataDog. Once in DataDog we can create dashboards, detect anomalies, correlate metrics with other OVO services and much more&#8230;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wU7f!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c2141b7-7ff8-4592-9946-ae1ad36fdd79_2914x854.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wU7f!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c2141b7-7ff8-4592-9946-ae1ad36fdd79_2914x854.png 424w, https://substackcdn.com/image/fetch/$s_!wU7f!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c2141b7-7ff8-4592-9946-ae1ad36fdd79_2914x854.png 848w, https://substackcdn.com/image/fetch/$s_!wU7f!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c2141b7-7ff8-4592-9946-ae1ad36fdd79_2914x854.png 1272w, https://substackcdn.com/image/fetch/$s_!wU7f!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c2141b7-7ff8-4592-9946-ae1ad36fdd79_2914x854.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wU7f!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c2141b7-7ff8-4592-9946-ae1ad36fdd79_2914x854.png" width="1456" height="427" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4c2141b7-7ff8-4592-9946-ae1ad36fdd79_2914x854.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:427,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!wU7f!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c2141b7-7ff8-4592-9946-ae1ad36fdd79_2914x854.png 424w, https://substackcdn.com/image/fetch/$s_!wU7f!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c2141b7-7ff8-4592-9946-ae1ad36fdd79_2914x854.png 848w, https://substackcdn.com/image/fetch/$s_!wU7f!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c2141b7-7ff8-4592-9946-ae1ad36fdd79_2914x854.png 1272w, https://substackcdn.com/image/fetch/$s_!wU7f!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c2141b7-7ff8-4592-9946-ae1ad36fdd79_2914x854.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Under the hood, the tool uses <a href="https://help.mypurecloud.com/articles/about-the-amazon-eventbridge-integration/">Genesys Cloud&#8217;s EventBridge Integration</a> to capture <a href="https://developer.genesys.cloud/notificationsalerts/notifications/available-topics#v2-detail-events-conversation--id--attributes">AttributeUpdated events</a> which it processes with Lambdas. The Lambdas filter out these &#8216;metric&#8217; attributes, determines which have changed using DynamoDB then pushes a custom metric to DataDog - although it could be configured to push the metrics anywhere.</p><p>It takes approx 40 seconds between capturing a new/updated attribute to the metric appearing on a dashboard. It can process over 4.5 million events a month for $40.</p><h2>Why I didn&#8217;t use:</h2><h3>Flow Milestones</h3><p>Genesys Cloud already has a method of capturing custom metrics within a flow called <a href="https://developer.genesys.cloud/blog/2021-06-10-flow-outcome-milestones/">Flow Milestones</a>. However I didn&#8217;t use them because:</p><ul><li><p>All our services that the Architect flows depend on also use DataDog, so being able to consolidate and correlate metrics in one place allows us to quickly detect patterns and diagnose issues</p></li><li><p>Participant Attributes are visible Genesys Cloud&#8217;s Conversation UI, so we can use these &#8216;metric&#8217; attributes in to debug errors</p></li><li><p>DataDog has many many features for monitoring, graphing and exploring metrics that we can now use</p></li></ul><h3>Data Actions</h3><p>Data Actions are the obvious choice for pushing data out of a flow, but they were&#8217;t suitable for this tool for two reasons:</p><ul><li><p><a href="https://developer.genesys.cloud/organization/organization/limits#data-actions">They have limits which apply to the whole organisation</a> so shouldn&#8217;t be overused</p></li><li><p>They&#8217;re visually noisy, so placing them all over your flows would create some very messy looking flows</p></li></ul><h2>A deeper dive into how it works</h2><p>Let&#8217;s break apart the solution and provide a little more detail on how it works&#8230;</p><h3>&#8216;Encoding&#8217; metrics in Participant Data Attributes</h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!x7vO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbff78442-2eb6-42a5-99e8-f93275101e15_2914x854.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!x7vO!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbff78442-2eb6-42a5-99e8-f93275101e15_2914x854.png 424w, https://substackcdn.com/image/fetch/$s_!x7vO!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbff78442-2eb6-42a5-99e8-f93275101e15_2914x854.png 848w, https://substackcdn.com/image/fetch/$s_!x7vO!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbff78442-2eb6-42a5-99e8-f93275101e15_2914x854.png 1272w, https://substackcdn.com/image/fetch/$s_!x7vO!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbff78442-2eb6-42a5-99e8-f93275101e15_2914x854.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!x7vO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbff78442-2eb6-42a5-99e8-f93275101e15_2914x854.png" width="1456" height="427" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bff78442-2eb6-42a5-99e8-f93275101e15_2914x854.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:427,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!x7vO!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbff78442-2eb6-42a5-99e8-f93275101e15_2914x854.png 424w, https://substackcdn.com/image/fetch/$s_!x7vO!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbff78442-2eb6-42a5-99e8-f93275101e15_2914x854.png 848w, https://substackcdn.com/image/fetch/$s_!x7vO!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbff78442-2eb6-42a5-99e8-f93275101e15_2914x854.png 1272w, https://substackcdn.com/image/fetch/$s_!x7vO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbff78442-2eb6-42a5-99e8-f93275101e15_2914x854.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>It all starts with the flow setting specially formatted Participant Data attributes. The format of these Attributes&#8217; names allows my code (which we&#8217;ll discuss later) to discern them from the non-metric attributes:</p><pre><code>Format: &lt;Flow Name&gt;Metric_&lt;Metric Name&gt;(&lt;DateTime in UTC&gt;)
Example: CustomerRoutingMetric_Unknown(2023-03-05T08:18:04.568Z)
</code></pre><p>If an attribute matches this format then it extracts the:</p><ul><li><p>Flow &amp; Metric Name - The combination of which is unique to a flow preventing duplications across flows</p></li><li><p>DateTime - This ensures the attribute&#8217;s name is unique, so the same metric can be set multiple times in a conversation</p></li></ul><p>The value of the attribute is ignored, as the solution only counts the occurrences of metrics within time intervals.</p><h3>Capturing when Attributes are set</h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8gBi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa81b8feb-1ea4-4462-a0f0-0e6d73d195b3_2914x854.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8gBi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa81b8feb-1ea4-4462-a0f0-0e6d73d195b3_2914x854.png 424w, https://substackcdn.com/image/fetch/$s_!8gBi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa81b8feb-1ea4-4462-a0f0-0e6d73d195b3_2914x854.png 848w, https://substackcdn.com/image/fetch/$s_!8gBi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa81b8feb-1ea4-4462-a0f0-0e6d73d195b3_2914x854.png 1272w, https://substackcdn.com/image/fetch/$s_!8gBi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa81b8feb-1ea4-4462-a0f0-0e6d73d195b3_2914x854.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8gBi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa81b8feb-1ea4-4462-a0f0-0e6d73d195b3_2914x854.png" width="1456" height="427" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a81b8feb-1ea4-4462-a0f0-0e6d73d195b3_2914x854.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:427,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!8gBi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa81b8feb-1ea4-4462-a0f0-0e6d73d195b3_2914x854.png 424w, https://substackcdn.com/image/fetch/$s_!8gBi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa81b8feb-1ea4-4462-a0f0-0e6d73d195b3_2914x854.png 848w, https://substackcdn.com/image/fetch/$s_!8gBi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa81b8feb-1ea4-4462-a0f0-0e6d73d195b3_2914x854.png 1272w, https://substackcdn.com/image/fetch/$s_!8gBi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa81b8feb-1ea4-4462-a0f0-0e6d73d195b3_2914x854.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>For my code to know that a Participant Attribute has been set, updated or deleted, I&#8217;ve configured <a href="https://help.mypurecloud.com/articles/about-the-amazon-eventbridge-integration/">Genesys Cloud&#8217;s EventBridge Integration</a> to produce <a href="https://developer.genesys.cloud/notificationsalerts/notifications/available-topics#v2-detail-events-conversation--id--attributes">AttributeUpdated events</a>. Upon <a href="https://aws.amazon.com/eventbridge/">EventBridge</a> receiving these events it will invoke my Lambda function - more on Lambdas in the next section.</p><p>The AttributeUpdated event that my code processes contains the Conversation&#8217;s ID and all the attributes associated to it, even those that didn&#8217;t change since the last event.</p><pre><code>{
  // ...
  eventBody: {
    // ...
    conversationId: "12341234-1234-1234-1234-123456789012",
    attributes: {
      "CustomerRoutingMetric_Unknown(2023-03-05T08:18:04.568Z)": "1",
      "AccountID": "0-000000"
      }
  }
}
</code></pre><h3>Extracting the Metrics from Attributes</h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!yYrW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4a52be9-314f-4903-bf7c-38ad6b688eee_2914x854.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!yYrW!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4a52be9-314f-4903-bf7c-38ad6b688eee_2914x854.png 424w, https://substackcdn.com/image/fetch/$s_!yYrW!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4a52be9-314f-4903-bf7c-38ad6b688eee_2914x854.png 848w, https://substackcdn.com/image/fetch/$s_!yYrW!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4a52be9-314f-4903-bf7c-38ad6b688eee_2914x854.png 1272w, https://substackcdn.com/image/fetch/$s_!yYrW!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4a52be9-314f-4903-bf7c-38ad6b688eee_2914x854.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!yYrW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4a52be9-314f-4903-bf7c-38ad6b688eee_2914x854.png" width="1456" height="427" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d4a52be9-314f-4903-bf7c-38ad6b688eee_2914x854.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:427,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!yYrW!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4a52be9-314f-4903-bf7c-38ad6b688eee_2914x854.png 424w, https://substackcdn.com/image/fetch/$s_!yYrW!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4a52be9-314f-4903-bf7c-38ad6b688eee_2914x854.png 848w, https://substackcdn.com/image/fetch/$s_!yYrW!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4a52be9-314f-4903-bf7c-38ad6b688eee_2914x854.png 1272w, https://substackcdn.com/image/fetch/$s_!yYrW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4a52be9-314f-4903-bf7c-38ad6b688eee_2914x854.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>When the Lambda function is invoked with an Attribute Updated event (which is per conversation) my code will:</p><ol><li><p>Extract only attributes representing metrics, based on the previously mentioned format</p></li><li><p>Determine which metric attributes have changed by comparing them to the previous event for the conversation, which are saved in a key-value store called DynamoDB</p></li><li><p>Push custom metrics to DataDog. The name of these metrics is based on the name of the metric attribute</p></li><li><p>Save the event to DynamoDB for determining what attributes have changed in the next event</p></li></ol><p>I just mentioned two technologies, which I&#8217;ve described below for those who don&#8217;t know them:</p><ul><li><p><a href="https://aws.amazon.com/lambda/">AWS Lambda</a> is a &#8216;serverless, event-driven compute service that lets you run code for virtually any type of application or backend service without provisioning or managing servers&#8217;</p></li><li><p><a href="https://aws.amazon.com/dynamodb/">AWS DynamoDB</a> is a &#8216;fast, flexible NoSQL database service for single-digit millisecond performance at any scale&#8217;</p></li></ul><p>Both of these technologies are pay-per-use, so we&#8217;re only charged when they&#8217;re being used. They can also scale automatically to handle traffic throughout the day.</p><h3>DataDog</h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Utb3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95c3fda4-7189-428f-897d-3739b867d2a8_2914x854.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Utb3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95c3fda4-7189-428f-897d-3739b867d2a8_2914x854.png 424w, https://substackcdn.com/image/fetch/$s_!Utb3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95c3fda4-7189-428f-897d-3739b867d2a8_2914x854.png 848w, https://substackcdn.com/image/fetch/$s_!Utb3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95c3fda4-7189-428f-897d-3739b867d2a8_2914x854.png 1272w, https://substackcdn.com/image/fetch/$s_!Utb3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95c3fda4-7189-428f-897d-3739b867d2a8_2914x854.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Utb3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95c3fda4-7189-428f-897d-3739b867d2a8_2914x854.png" width="1456" height="427" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/95c3fda4-7189-428f-897d-3739b867d2a8_2914x854.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:427,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Utb3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95c3fda4-7189-428f-897d-3739b867d2a8_2914x854.png 424w, https://substackcdn.com/image/fetch/$s_!Utb3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95c3fda4-7189-428f-897d-3739b867d2a8_2914x854.png 848w, https://substackcdn.com/image/fetch/$s_!Utb3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95c3fda4-7189-428f-897d-3739b867d2a8_2914x854.png 1272w, https://substackcdn.com/image/fetch/$s_!Utb3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95c3fda4-7189-428f-897d-3739b867d2a8_2914x854.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The Lambda function uses DataDog&#8217;s <a href="https://docs.datadoghq.com/serverless/libraries\_integrations/extension/">Lambda Layer</a> to push <a href="https://docs.datadoghq.com/metrics/custom\_metrics/">Custom Metrics</a> to DataDog. This layer handles the complexity of collecting and sending metrics from concurrent Lambda invocations.</p><p>The power and simplicity of DataDog does come at a price though, with custom metrics costing <a href="https://www.datadoghq.com/pricing/list/">approx $5 per 100 custom metrics</a> - with a custom metric being the combination of name and tags.</p><h2>Conclusion</h2><p>Thanks to Genesys Cloud&#8217;s increasing integrations to other tooling, I&#8217;ve been able to quickly build a solution which has allowed me to continue my aim of bringing the development and monitoring of our Flows and Bots closer to that of building software.</p><p>You can read my other articles on this subject here:</p><ul><li><p><a href="https://makingchatbots.com/p/automating-development-of-genesys-chatbotshtml">Automating development of Genesys chatbots</a></p></li><li><p><a href="https://makingchatbots.com/p/automate-testing-genesys-web-messengerhtml">Automate testing Genesys&#8217; Web Messenger</a></p></li></ul><p>Like what you read? Follow me on <a href="https://www.linkedin.com/in/lucas-woodward-the-dev/">LinkedIn</a> to be notified of future articles.</p>]]></content:encoded></item><item><title><![CDATA[Automating development of Genesys chatbots]]></title><description><![CDATA[When developing chatbots at OVO we aim to reduce the feedback loop as much as possible, as a short feedback loop means we can adapt to customer feedback more quickly.]]></description><link>https://makingchatbots.com/p/automating-development-of-genesys-chatbotshtml</link><guid isPermaLink="false">https://makingchatbots.com/p/automating-development-of-genesys-chatbotshtml</guid><dc:creator><![CDATA[Lucas Woodward]]></dc:creator><pubDate>Fri, 03 Feb 2023 00:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/de848d36-b226-4cf4-aa5e-ad9d6b072324_1084x718.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When developing chatbots at OVO we aim to reduce the feedback loop as much as possible, as a short feedback loop means we can adapt to customer feedback more quickly. However, to ensure quality is maintained (even increased) we leverage automation as much as possible. In this article, I&#8217;ll explain the automation pipeline I&#8217;ve created that achieves this&#8230;</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!dPKI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4336250c-4216-4e41-af31-becee1c3f896_2992x444.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dPKI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4336250c-4216-4e41-af31-becee1c3f896_2992x444.png 424w, https://substackcdn.com/image/fetch/$s_!dPKI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4336250c-4216-4e41-af31-becee1c3f896_2992x444.png 848w, https://substackcdn.com/image/fetch/$s_!dPKI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4336250c-4216-4e41-af31-becee1c3f896_2992x444.png 1272w, https://substackcdn.com/image/fetch/$s_!dPKI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4336250c-4216-4e41-af31-becee1c3f896_2992x444.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dPKI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4336250c-4216-4e41-af31-becee1c3f896_2992x444.png" width="1456" height="216" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4336250c-4216-4e41-af31-becee1c3f896_2992x444.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:216,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!dPKI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4336250c-4216-4e41-af31-becee1c3f896_2992x444.png 424w, https://substackcdn.com/image/fetch/$s_!dPKI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4336250c-4216-4e41-af31-becee1c3f896_2992x444.png 848w, https://substackcdn.com/image/fetch/$s_!dPKI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4336250c-4216-4e41-af31-becee1c3f896_2992x444.png 1272w, https://substackcdn.com/image/fetch/$s_!dPKI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4336250c-4216-4e41-af31-becee1c3f896_2992x444.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>The automated pipeline, known formally as a <a href="https://en.wikipedia.org/wiki/CI/CD">CI/CD pipeline</a> is triggered against every change and will:</p><ol><li><p>Automatically deploy the bot and its dependencies to test environments</p></li><li><p>Run a suite of automated tests to assert the behaviour of the new functionality, and catch any regressions in existing functionality</p></li><li><p>Enforce that tests pass and changes are peer-reviewed before being able to progress</p></li><li><p>Once approved it automatically deploys changes to a User Acceptance Testing (UAT) environment</p></li><li><p>Notifies a QA Engineer to perform exploratory testing</p></li><li><p>Once approved by a QA Engineer then automatically deploy changes to production</p></li></ol><p>The more obvious benefits of this are:</p><ul><li><p>Reducing the feedback loop from hours/days to seconds/minutes</p></li><li><p>Deployments of chatbots and their dependencies that are identical across environments. If it works in UAT, it will work in Prod.</p></li><li><p>Assurance of quality through automated tests. Every change, no matter how small is subjected to over 40 end-to-end tests - and since they are run concurrently they take less than 2 mins</p></li></ul><h2>Implementation</h2><p>Let&#8217;s break down the pipeline and examine each part of it&#8230;</p><h3>Source-control</h3><p>All the flows, chatbots, dependencies, tests, and even the definition of the pipeline itself live in source-control - which for OVO is <a href="https://github.com/">GitHub</a>. This git repository forms the source of truth.</p><p>When an update or revert occurs against anything in the repository then it is tracked (by virtue of it being in source-control) and the automated pipeline is triggered. Only when all the pipeline&#8217;s checks pass will the change make its way to production.</p><h3>Pipeline</h3><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QgNB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb18b4548-b93c-4066-9452-44d3befb3c66_2992x267.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QgNB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb18b4548-b93c-4066-9452-44d3befb3c66_2992x267.png 424w, https://substackcdn.com/image/fetch/$s_!QgNB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb18b4548-b93c-4066-9452-44d3befb3c66_2992x267.png 848w, https://substackcdn.com/image/fetch/$s_!QgNB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb18b4548-b93c-4066-9452-44d3befb3c66_2992x267.png 1272w, https://substackcdn.com/image/fetch/$s_!QgNB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb18b4548-b93c-4066-9452-44d3befb3c66_2992x267.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QgNB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb18b4548-b93c-4066-9452-44d3befb3c66_2992x267.png" width="1456" height="130" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b18b4548-b93c-4066-9452-44d3befb3c66_2992x267.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:130,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Overview of pipeline, from dev, uat to prod&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Overview of pipeline, from dev, uat to prod" title="Overview of pipeline, from dev, uat to prod" srcset="https://substackcdn.com/image/fetch/$s_!QgNB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb18b4548-b93c-4066-9452-44d3befb3c66_2992x267.png 424w, https://substackcdn.com/image/fetch/$s_!QgNB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb18b4548-b93c-4066-9452-44d3befb3c66_2992x267.png 848w, https://substackcdn.com/image/fetch/$s_!QgNB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb18b4548-b93c-4066-9452-44d3befb3c66_2992x267.png 1272w, https://substackcdn.com/image/fetch/$s_!QgNB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb18b4548-b93c-4066-9452-44d3befb3c66_2992x267.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>The pipeline is defined in the human-readable language YAML and is executed by CircleCI. It defines what each step does and the order they do it.</p><pre><code># Job definitions redacted

workflows:
  development:
    jobs:
      - terraform-autoapply-dev:
          filters: *ignore-main-branch
          context:
            - aws-dev
            - genesys-dev
      - test-web-messaging:
          filters: *ignore-main-branch
          requires:
            - terraform-autoapply-dev
      - test-ivr-flow:
          filters: *ignore-main-branch
          requires:
            - terraform-autoapply-dev
  main:
    jobs:
      - terraform-autoapply-uat:
          filters: *only-main-branch
          context:
            - aws-uat
            - genesys-uat
      - manual-testing:
          type: approval
          requires:
            - terraform-autoapply-uat
      - terraform-apply-prod:
          filters: *only-main-branch
          context:
            - aws-prod
            - genesys-prod
          requires:
            - manual-testing
</code></pre><h3>Deploy using Terraform</h3><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Yp1m!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe08d7292-3861-4bb8-b616-f078d78f368f_2992x267.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Yp1m!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe08d7292-3861-4bb8-b616-f078d78f368f_2992x267.png 424w, https://substackcdn.com/image/fetch/$s_!Yp1m!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe08d7292-3861-4bb8-b616-f078d78f368f_2992x267.png 848w, https://substackcdn.com/image/fetch/$s_!Yp1m!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe08d7292-3861-4bb8-b616-f078d78f368f_2992x267.png 1272w, https://substackcdn.com/image/fetch/$s_!Yp1m!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe08d7292-3861-4bb8-b616-f078d78f368f_2992x267.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Yp1m!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe08d7292-3861-4bb8-b616-f078d78f368f_2992x267.png" width="1456" height="130" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e08d7292-3861-4bb8-b616-f078d78f368f_2992x267.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:130,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Pipeline with Terraform tasks highlighted&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Pipeline with Terraform tasks highlighted" title="Pipeline with Terraform tasks highlighted" srcset="https://substackcdn.com/image/fetch/$s_!Yp1m!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe08d7292-3861-4bb8-b616-f078d78f368f_2992x267.png 424w, https://substackcdn.com/image/fetch/$s_!Yp1m!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe08d7292-3861-4bb8-b616-f078d78f368f_2992x267.png 848w, https://substackcdn.com/image/fetch/$s_!Yp1m!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe08d7292-3861-4bb8-b616-f078d78f368f_2992x267.png 1272w, https://substackcdn.com/image/fetch/$s_!Yp1m!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe08d7292-3861-4bb8-b616-f078d78f368f_2992x267.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><a href="https://www.terraform.io/">Terraform</a> offers a way to declaratively define resources that you want it to deploy. This way you know that the deployments will always match what is in source-control.</p><p>Since many <a href="https://registry.terraform.io/browse/providers">providers support Terraform</a> we can define everything in one place; from chatbots, flows, data-actions to their backend services. Here&#8217;s an example of a Terraform definition:</p><pre><code>resource "genesyscloud_integration_action" "create_survery_data_action" {
  # Prevent any change that creates a new UUID
  lifecycle {
    prevent_destroy = true
  }
  name           = "Create Survey (created via Terraform)"
  category       = "Web Services Data Actions"
  integration_id = var.integration_id
  secure         = false
  config_request {
    // ...
  }
  config_response {
    // ...
  }
  contract_input = &lt;&lt;DEFINITION
        // ...
        DEFINITION
  contract_output = &lt;&lt;DEFINITION
        // ...
        DEFINITION
}

resource "genesyscloud_flow" "flow" {
  filepath          = var.flow_file
  file_content_hash = filesha256(var.flow_file)

  substitutions = {
    flow_name     = "${var.flow_name} - (created via Terraform)"
    flow_division = var.flow_division
    data_action_name = genesyscloud_integration_action.create_survery_data_action.name
  }
}

data "genesyscloud_webdeployments_configuration" "config" {
  name = var.web_deployments_configuration
}

resource "genesyscloud_webdeployments_deployment" "survey_deployment" {
  name              = "Survey - (created via Terraform)"
  flow_id           = genesyscloud_flow.flow.id
  allow_all_domains = true

  configuration {
    id      = data.genesyscloud_webdeployments_configuration.config.id
    version = data.genesyscloud_webdeployments_configuration.config.version
  }
}
</code></pre><h3>Automated testing</h3><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!VGFe!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5797f1cb-dda2-4ca5-8b81-357550ea73d1_2992x267.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!VGFe!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5797f1cb-dda2-4ca5-8b81-357550ea73d1_2992x267.png 424w, https://substackcdn.com/image/fetch/$s_!VGFe!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5797f1cb-dda2-4ca5-8b81-357550ea73d1_2992x267.png 848w, https://substackcdn.com/image/fetch/$s_!VGFe!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5797f1cb-dda2-4ca5-8b81-357550ea73d1_2992x267.png 1272w, https://substackcdn.com/image/fetch/$s_!VGFe!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5797f1cb-dda2-4ca5-8b81-357550ea73d1_2992x267.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!VGFe!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5797f1cb-dda2-4ca5-8b81-357550ea73d1_2992x267.png" width="1456" height="130" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5797f1cb-dda2-4ca5-8b81-357550ea73d1_2992x267.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:130,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Pipeline with automated testing tasks highlighted&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Pipeline with automated testing tasks highlighted" title="Pipeline with automated testing tasks highlighted" srcset="https://substackcdn.com/image/fetch/$s_!VGFe!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5797f1cb-dda2-4ca5-8b81-357550ea73d1_2992x267.png 424w, https://substackcdn.com/image/fetch/$s_!VGFe!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5797f1cb-dda2-4ca5-8b81-357550ea73d1_2992x267.png 848w, https://substackcdn.com/image/fetch/$s_!VGFe!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5797f1cb-dda2-4ca5-8b81-357550ea73d1_2992x267.png 1272w, https://substackcdn.com/image/fetch/$s_!VGFe!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5797f1cb-dda2-4ca5-8b81-357550ea73d1_2992x267.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>The tools we use at OVO to automate the testing of chatbots are written by me, and as such are open-source:</p><ul><li><p><a href="https://github.com/ovotech/genesys-web-messaging-tester">Web Messenger Tester</a> for testing Inbound Message flows via a Web Messenger Deployment</p><ul><li><p>Since the WhatsApp integration uses Incoming Message Flows it means we can also test WhatsApp-specific chatbots with this tool</p></li></ul></li><li><p><a href="https://github.com/MakingChatbots/ivr-tester">IVR Tester</a> for testing IVR flows</p><ul><li><p>This can test our IVR-based chatbots flows by impersonating a customer calling OVO, interpreting what it hears, and responding accordingly to traverse the journey. Any unexpected response is flagged</p></li></ul></li></ul><p>Both tools define their tests in files that can be stored alongside the chatbots in source-control and act as living documentation:</p><pre><code>scenarios:
  "Customer asked to score experience if they say yes":
    - say: Thank you, bye
    - waitForReplyContaining: Before you go could you answer a quick survey?
    - say: yes
    - waitForReplyContaining: Overall, how satisfied or dissatisfied are you with our company?
    - say: "10"
    - waitForReplyContaining: We thank you for your time spent taking this survey. Your response has been recorded.
  "Conversation ended if they say no":
    - say: Thank you, bye
    - waitForReplyContaining: Before you go could you answer a quick survey?
    - say: no
    - waitForReplyContaining: We hope you have a nice day, goodbye
</code></pre><h2>Conclusion</h2><p>This has been a whistle-stop tour of the pipeline and the benefits it brought us. Hopefully, it has provided enough information for you to get started with your own pipelines.</p><p>Like what you read? Follow me on <a href="https://www.linkedin.com/in/lucas-woodward-the-dev/">LinkedIn</a> to be notified of future articles.</p>]]></content:encoded></item><item><title><![CDATA[Automate testing Genesys’ Web Messenger]]></title><description><![CDATA[Manually testing chatbots can be a slow and error-prone process, especially when testing all potential customer journeys.]]></description><link>https://makingchatbots.com/p/automate-testing-genesys-web-messengerhtml</link><guid isPermaLink="false">https://makingchatbots.com/p/automate-testing-genesys-web-messengerhtml</guid><dc:creator><![CDATA[Lucas Woodward]]></dc:creator><pubDate>Tue, 15 Mar 2022 00:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/9ec22083-7ae5-48bd-a80e-8e86e7cac1fd_1084x718.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Manually testing chatbots can be a slow and error-prone process, especially when testing all potential customer journeys. The quicker and more reliable approach to testing is to rely on automated tests, which can be triggered with a click of a button, test all the functionality in a fraction of the time and even act as documentation.</p><p>In this article I will guide you through how to write automated tests for <a href="https://help.mypurecloud.com/articles/about-web-messaging/">Genesys&#8217; Web Messenger</a> using a tool I wrote (in the absence of any others) aptly named <a href="https://github.com/MakingChatbots/genesys-cloud-chatbot-tester">Genesys Cloud Chatbot Tester</a>. As an aside, we use this tool at OVO as part of a CI/CD process to test our chatbots before they&#8217;re deployed to production.</p><p>If you want to see the tool and its code head on over to <a href="https://github.com/MakingChatbots/genesys-cloud-chatbot-tester">Genesys Cloud Chatbot Tester on GitHub</a>, or check out <a href="https://genesys-messenger-tester.makingchatbots.com/">its documentation</a>.</p><h2>Writing automated tests</h2><p>The tool I&#8217;ve written uses <a href="https://developer.genesys.cloud/api/digital/webmessaging/websocketapi">Web Messenger&#8217;s guest API</a> to simulate a customer talking to a Web Messenger Deployment. Once the tool starts an interaction it follows instructions defined in a file called a &#8216;test-script&#8217;, which tells it what to say and what it should expect in response. If the response deviates from the test-script then the tool flags the test as a failure, otherwise the test passes.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Cnnd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e34d30b-94c6-4133-852a-a6f2225e37e0_2143x841.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Cnnd!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e34d30b-94c6-4133-852a-a6f2225e37e0_2143x841.png 424w, https://substackcdn.com/image/fetch/$s_!Cnnd!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e34d30b-94c6-4133-852a-a6f2225e37e0_2143x841.png 848w, https://substackcdn.com/image/fetch/$s_!Cnnd!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e34d30b-94c6-4133-852a-a6f2225e37e0_2143x841.png 1272w, https://substackcdn.com/image/fetch/$s_!Cnnd!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e34d30b-94c6-4133-852a-a6f2225e37e0_2143x841.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Cnnd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e34d30b-94c6-4133-852a-a6f2225e37e0_2143x841.png" width="1456" height="571" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4e34d30b-94c6-4133-852a-a6f2225e37e0_2143x841.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:571,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Diagram showing tool using test-script to test Genesys Web Messenger&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Diagram showing tool using test-script to test Genesys Web Messenger" title="Diagram showing tool using test-script to test Genesys Web Messenger" srcset="https://substackcdn.com/image/fetch/$s_!Cnnd!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e34d30b-94c6-4133-852a-a6f2225e37e0_2143x841.png 424w, https://substackcdn.com/image/fetch/$s_!Cnnd!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e34d30b-94c6-4133-852a-a6f2225e37e0_2143x841.png 848w, https://substackcdn.com/image/fetch/$s_!Cnnd!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e34d30b-94c6-4133-852a-a6f2225e37e0_2143x841.png 1272w, https://substackcdn.com/image/fetch/$s_!Cnnd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e34d30b-94c6-4133-852a-a6f2225e37e0_2143x841.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>It&#8217;s all pretty straight forward, and as a bonus, because the test-script looks a lot like a transcript (as you&#8217;ll see later) it can be shared with the wider business as documentation on how your messenger flow works from a customer&#8217;s perspective.</p><p>Now we have an overview let&#8217;s press on with installing the tool and writing a test for a highly contrived chatbot&#8230;</p><h3>1. Install the prerequisites</h3><p>Firstly, we need to <a href="https://nodejs.org/en/download/">download and install the Node.js runtime</a>. This will allow you to install and run the testing tool.</p><h3>2. Install the tool</h3><p>Next install the <a href="https://github.com/MakingChatbots/genesys-cloud-chatbot-tester">Genesys Cloud Chatbot Tester tool</a> by running the following in <a href="https://www.howtogeek.com/235101/10-ways-to-open-the-command-prompt-in-windows-10/">Command Prompt for Windows</a>, or Terminal for Mac/Linux:</p><pre><code>npm install -g @makingchatbots/genesys-cloud-chatbot-tester-cli</code></pre><p>Once installed you can run the command <code>genesys-cloud-chatbot-tester --help</code> to see how to use the tool.</p><pre><code>$ genesys-cloud-chatbot-tester --help
Usage: index [options] &lt;filePath&gt;

Arguments:
  filePath                             Path of the YAML test-script file

Options:
  -id, --deployment-id &lt;deploymentId&gt;  Web Messenger Deployment's ID
  -r, --region &lt;region&gt;                Region of Genesys instance that hosts the Web Messenger Deployment
  -o, --origin &lt;origin&gt;                Origin domain used for restricting Web Messenger Deployment
  -p, --parallel &lt;number&gt;              Maximum scenarios to run in parallel (default: 1)
  -h, --help                           display help for command
</code></pre><h3>3. Write a Test-Script</h3><p>We are now ready to write a test-script for a Web Messenger Deployment.</p><p>The highly contrived chatbot that we&#8217;ll use as the subject of our test does the following:</p><ol><li><p>Asks the customer for their name</p></li><li><p>Greets them by their name and asks how it may help</p></li></ol><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1EtH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3f7df9e-2743-4828-bcbd-29880cb52418_774x954.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1EtH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3f7df9e-2743-4828-bcbd-29880cb52418_774x954.png 424w, https://substackcdn.com/image/fetch/$s_!1EtH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3f7df9e-2743-4828-bcbd-29880cb52418_774x954.png 848w, https://substackcdn.com/image/fetch/$s_!1EtH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3f7df9e-2743-4828-bcbd-29880cb52418_774x954.png 1272w, https://substackcdn.com/image/fetch/$s_!1EtH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3f7df9e-2743-4828-bcbd-29880cb52418_774x954.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1EtH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3f7df9e-2743-4828-bcbd-29880cb52418_774x954.png" width="368" height="453.5813953488372" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f3f7df9e-2743-4828-bcbd-29880cb52418_774x954.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:954,&quot;width&quot;:774,&quot;resizeWidth&quot;:368,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Web Messenger Conversation&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Web Messenger Conversation" title="Web Messenger Conversation" srcset="https://substackcdn.com/image/fetch/$s_!1EtH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3f7df9e-2743-4828-bcbd-29880cb52418_774x954.png 424w, https://substackcdn.com/image/fetch/$s_!1EtH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3f7df9e-2743-4828-bcbd-29880cb52418_774x954.png 848w, https://substackcdn.com/image/fetch/$s_!1EtH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3f7df9e-2743-4828-bcbd-29880cb52418_774x954.png 1272w, https://substackcdn.com/image/fetch/$s_!1EtH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3f7df9e-2743-4828-bcbd-29880cb52418_774x954.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The test-script for such as simple bot is equally simple:</p><pre><code># test-script.yaml

config:
  deploymentId: 12345c7d-123a-123a-1f3d-a104e02a86a7
  region: usw2.pure.cloud
scenarios:
  "Customer is greeted by the name they provide":
    - say: hi
    - waitForReplyContaining: what is your name?
    - say: Lucas
    - waitForReplyContaining: Hello Lucas, how may I help you today?
</code></pre><p>The test-script is written in a format known as <a href="https://en.wikipedia.org/wiki/YAML">YAML</a>, and consists of two sections:</p><h4>Config</h4><p>This section contains the attributes necessary for the tool to find the Messenger Deployment it will test:</p><ul><li><p><code>deploymentId</code> - ID for the messenger deployment taken from the <a href="https://help.mypurecloud.com/articles/deploy-messenger/">Messenger Deployment page</a></p></li><li><p><code>region</code> - Region of the Genesys instance that manages the Messenger Deployment (<a href="https://help.mypurecloud.com/faqs/how-do-i-select-my-region/">see your region in the Genesys URL</a>)</p></li></ul><h4>Scenarios</h4><p>This section contains a list of scenarios that you want to test, along with the instructions of what to say/expect beneath each of them. In this case there is only one scenario, but in reality you&#8217;d have many more.</p><h3>4. Run the test</h3><p>The final and most satisfying part is now upon us, running the tests! It&#8217;s pretty straightforward, you just point the Web Messaging Tester tool at the test-script file:</p><pre><code>genesys-cloud-chatbot-tester test-script.yaml</code></pre><p>Then watch it test the deployment:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!KRqQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa15af29b-260d-47bc-8fba-40d1499ac807_1100x428.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!KRqQ!,w_424,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa15af29b-260d-47bc-8fba-40d1499ac807_1100x428.gif 424w, https://substackcdn.com/image/fetch/$s_!KRqQ!,w_848,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa15af29b-260d-47bc-8fba-40d1499ac807_1100x428.gif 848w, https://substackcdn.com/image/fetch/$s_!KRqQ!,w_1272,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa15af29b-260d-47bc-8fba-40d1499ac807_1100x428.gif 1272w, https://substackcdn.com/image/fetch/$s_!KRqQ!,w_1456,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa15af29b-260d-47bc-8fba-40d1499ac807_1100x428.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!KRqQ!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa15af29b-260d-47bc-8fba-40d1499ac807_1100x428.gif" width="1100" height="428" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a15af29b-260d-47bc-8fba-40d1499ac807_1100x428.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:428,&quot;width&quot;:1100,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Recording of Web Messenger test&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Recording of Web Messenger test" title="Recording of Web Messenger test" srcset="https://substackcdn.com/image/fetch/$s_!KRqQ!,w_424,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa15af29b-260d-47bc-8fba-40d1499ac807_1100x428.gif 424w, https://substackcdn.com/image/fetch/$s_!KRqQ!,w_848,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa15af29b-260d-47bc-8fba-40d1499ac807_1100x428.gif 848w, https://substackcdn.com/image/fetch/$s_!KRqQ!,w_1272,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa15af29b-260d-47bc-8fba-40d1499ac807_1100x428.gif 1272w, https://substackcdn.com/image/fetch/$s_!KRqQ!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa15af29b-260d-47bc-8fba-40d1499ac807_1100x428.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Conclusion</h2><p>Hopefully this article has shown how easy it is to test Web Messenger Deployments, along with the advantages that come with automation! However, automated testing doesn&#8217;t have to stop here&#8230; I&#8217;m working on another tool for <a href="https://makingchatbots.com/p/automating-how-ivr-call-flows-are-testedhtml">automating the testing of call flows</a> which I&#8217;d like to blog about soon.</p><p>Lastly, if you have any questions about the tool discussed in this article then <a href="https://genesys-messenger-tester.makingchatbots.com/">checkout the documentation</a> or message me on <a href="https://www.linkedin.com/in/lucas-woodward-the-dev/">LinkedIn</a>.</p>]]></content:encoded></item><item><title><![CDATA[Genesys: Troubleshooting Web Service Data Actions]]></title><description><![CDATA[When creating Web Service Data Actions (and their dependent flows) in Genesys I spent a lot of time debugging problems around these Data Actions - the main culprit being input values that resulted in unexpected responses from a downstream API, breaking contracts/mappings.]]></description><link>https://makingchatbots.com/p/genesys-troubleshooting-data-actionshtml</link><guid isPermaLink="false">https://makingchatbots.com/p/genesys-troubleshooting-data-actionshtml</guid><dc:creator><![CDATA[Lucas Woodward]]></dc:creator><pubDate>Fri, 04 Mar 2022 00:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/ee0d823a-ec53-40bd-afb1-bf831fa513c6_1084x718.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When creating Web Service Data Actions (and their dependent flows) in <a href="https://www.genesys.com/">Genesys</a> I spent a lot of time debugging problems around these Data Actions - the main culprit being input values that resulted in unexpected responses from a downstream API, breaking contracts/mappings. The following is how I sped up diagnosing problems by spying on the interaction between my Web Service Data Actions and downstream APIs.</p><p><strong>WARNING: The tool used below should never be used to spy on Data Actions that are used by real customers. It terminates after a fixed period of time, has limited bandwidth and may leak secrets.</strong></p><h2>Overview</h2><p>We will intercept a Data Action&#8217;s requests by configuring the Data Action to point at a tunnel created by a tool called <a href="https://ngrok.com/">ngrok</a>. This tunnel will forward requests to the Data Action&#8217;s original URL, and importantly will allow us to inspect any request that passes through it.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wRf5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F745ef1b4-2c80-4f4e-a3d2-f955cf652453_1276x295.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wRf5!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F745ef1b4-2c80-4f4e-a3d2-f955cf652453_1276x295.png 424w, https://substackcdn.com/image/fetch/$s_!wRf5!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F745ef1b4-2c80-4f4e-a3d2-f955cf652453_1276x295.png 848w, https://substackcdn.com/image/fetch/$s_!wRf5!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F745ef1b4-2c80-4f4e-a3d2-f955cf652453_1276x295.png 1272w, https://substackcdn.com/image/fetch/$s_!wRf5!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F745ef1b4-2c80-4f4e-a3d2-f955cf652453_1276x295.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wRf5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F745ef1b4-2c80-4f4e-a3d2-f955cf652453_1276x295.png" width="1276" height="295" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/745ef1b4-2c80-4f4e-a3d2-f955cf652453_1276x295.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:295,&quot;width&quot;:1276,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Diagram showing flow: Architect Flow > Data Action > Tunnel > API&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Diagram showing flow: Architect Flow > Data Action > Tunnel > API" title="Diagram showing flow: Architect Flow > Data Action > Tunnel > API" srcset="https://substackcdn.com/image/fetch/$s_!wRf5!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F745ef1b4-2c80-4f4e-a3d2-f955cf652453_1276x295.png 424w, https://substackcdn.com/image/fetch/$s_!wRf5!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F745ef1b4-2c80-4f4e-a3d2-f955cf652453_1276x295.png 848w, https://substackcdn.com/image/fetch/$s_!wRf5!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F745ef1b4-2c80-4f4e-a3d2-f955cf652453_1276x295.png 1272w, https://substackcdn.com/image/fetch/$s_!wRf5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F745ef1b4-2c80-4f4e-a3d2-f955cf652453_1276x295.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><h2>Installing ngrok</h2><p>Creating the tunnel will require <a href="https://ngrok.com/">ngrok</a> to be installed locally by following the steps:</p><ol><li><p>Follow the <a href="https://ngrok.com/download">official instructions to install ngrok</a></p></li><li><p><a href="https://dashboard.ngrok.com/signup">Sign up for a free account</a>. You&#8217;ll need this to be able to configure the proxy</p></li><li><p><a href="https://ngrok.com/docs#getting-started-authtoken">Configure ngrok with an auth token</a> from the account you set up above</p></li></ol><h2>Creating a tunnel</h2><p>Create the tunnel by running the following command, configured with the host from the Data Action&#8217;s URL</p><pre><code>ngrok http -host-header=&lt;host&gt; &lt;host&gt;:&lt;port&gt;
</code></pre><ul><li><p><code>-host-header=&lt;host&gt;</code> - Set the <a href="https://ngrok.com/docs#http-host-header">host-header switch</a> to the host of the Data Action&#8217;s current URL</p></li><li><p><code>&lt;host&gt;:&lt;port&gt;</code> - Set this to the host and port of the Data Action&#8217;s current URL</p></li></ul><h3>Example</h3><p>If the Data Action&#8217;s URL is</p><pre><code>https://example.com/account/${input.AccountId} 
</code></pre><p>Then the command will be:</p><pre><code>ngrok http -host-header=example.com example.com:443
</code></pre><p><em>Port 443 = HTTPS</em></p><h2>Configuring the Data Action</h2><p>When you run the ngrok command in the previous step you&#8217;ll be presented with the output below. Contained within this output is the randomly generated forwarding address. We will configure our Data Action to use this URL.</p><pre><code>ngrok by @inconshreveable                                                                                                                                                                   (Ctrl+C to quit)

Session Status                online
Account                       xxxx@xxxx.com (Plan: Free)
Version                       2.3.35
Region                        United States (us)
Web Interface                 http://127.0.0.1:4040
Forwarding                    https://12abc-12abc-12abc.ngrok.io -&gt; https://example.com:443

Connections                   ttl     opn     rt1     rt5     p50     p90
                              0       0       0.00    0.00    0.00    0.00
</code></pre><h3>Update the Data Action&#8217;s URL</h3><ol><li><p>Take the forwarding address from output, which in the example above is:</p><pre><code>https://12abc-12abc-12abc.ngrok.io
</code></pre></li><li><p>Update the Request URL Template in the Data Action to use the forwarding address:</p><pre><code>https://12abc-12abc-12abc.ngrok.io/account/${input.AccountId}
</code></pre></li></ol><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!roGu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F38a3d13a-24cf-4bad-a141-2a22b2f180b7_1510x508.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!roGu!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F38a3d13a-24cf-4bad-a141-2a22b2f180b7_1510x508.png 424w, https://substackcdn.com/image/fetch/$s_!roGu!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F38a3d13a-24cf-4bad-a141-2a22b2f180b7_1510x508.png 848w, https://substackcdn.com/image/fetch/$s_!roGu!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F38a3d13a-24cf-4bad-a141-2a22b2f180b7_1510x508.png 1272w, https://substackcdn.com/image/fetch/$s_!roGu!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F38a3d13a-24cf-4bad-a141-2a22b2f180b7_1510x508.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!roGu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F38a3d13a-24cf-4bad-a141-2a22b2f180b7_1510x508.png" width="1456" height="490" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/38a3d13a-24cf-4bad-a141-2a22b2f180b7_1510x508.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:490,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Screenshot of Data Action's URL being modified in Genesys&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Screenshot of Data Action's URL being modified in Genesys" title="Screenshot of Data Action's URL being modified in Genesys" srcset="https://substackcdn.com/image/fetch/$s_!roGu!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F38a3d13a-24cf-4bad-a141-2a22b2f180b7_1510x508.png 424w, https://substackcdn.com/image/fetch/$s_!roGu!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F38a3d13a-24cf-4bad-a141-2a22b2f180b7_1510x508.png 848w, https://substackcdn.com/image/fetch/$s_!roGu!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F38a3d13a-24cf-4bad-a141-2a22b2f180b7_1510x508.png 1272w, https://substackcdn.com/image/fetch/$s_!roGu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F38a3d13a-24cf-4bad-a141-2a22b2f180b7_1510x508.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Inspect requests</h2><p>Now ngrok is running and your Data Action is pointing at ngrok&#8217;s forwarding address (aka tunnel) you can inspect HTTP(S) traffic going through it.</p><p>Navigate to <a href="http://127.0.0.1:4040/inspect/http">http://127.0.0.1:4040/inspect/http</a> to see the traffic, or <a href="https://ngrok.com/docs#getting-started-inspect">follow the official guide</a>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QvVq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa721ed67-cbf1-4cc8-87d9-1e762713b6ee_1262x942.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QvVq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa721ed67-cbf1-4cc8-87d9-1e762713b6ee_1262x942.png 424w, https://substackcdn.com/image/fetch/$s_!QvVq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa721ed67-cbf1-4cc8-87d9-1e762713b6ee_1262x942.png 848w, https://substackcdn.com/image/fetch/$s_!QvVq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa721ed67-cbf1-4cc8-87d9-1e762713b6ee_1262x942.png 1272w, https://substackcdn.com/image/fetch/$s_!QvVq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa721ed67-cbf1-4cc8-87d9-1e762713b6ee_1262x942.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QvVq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa721ed67-cbf1-4cc8-87d9-1e762713b6ee_1262x942.png" width="1262" height="942" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a721ed67-cbf1-4cc8-87d9-1e762713b6ee_1262x942.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:942,&quot;width&quot;:1262,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Screenshot of viewing intercepted requests in ngrok&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Screenshot of viewing intercepted requests in ngrok" title="Screenshot of viewing intercepted requests in ngrok" srcset="https://substackcdn.com/image/fetch/$s_!QvVq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa721ed67-cbf1-4cc8-87d9-1e762713b6ee_1262x942.png 424w, https://substackcdn.com/image/fetch/$s_!QvVq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa721ed67-cbf1-4cc8-87d9-1e762713b6ee_1262x942.png 848w, https://substackcdn.com/image/fetch/$s_!QvVq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa721ed67-cbf1-4cc8-87d9-1e762713b6ee_1262x942.png 1272w, https://substackcdn.com/image/fetch/$s_!QvVq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa721ed67-cbf1-4cc8-87d9-1e762713b6ee_1262x942.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Cleanup</h2><p>When you close ngrok it will also close the tunnel (which is unique each time), so you&#8217;ll have to revert your Data Action&#8217;s URL after inspecting the traffic.</p><p>Like what you read? Follow me on <a href="https://www.linkedin.com/in/lucas-woodward-the-dev/">LinkedIn</a> to be notified of future articles.</p>]]></content:encoded></item><item><title><![CDATA[Automating how IVR call flows are tested]]></title><description><![CDATA[We are all familiar with the automated systems that answer our calls then ask a list of predefined questions to try and resolve simple queries.]]></description><link>https://makingchatbots.com/p/automating-how-ivr-call-flows-are-testedhtml</link><guid isPermaLink="false">https://makingchatbots.com/p/automating-how-ivr-call-flows-are-testedhtml</guid><dc:creator><![CDATA[Lucas Woodward]]></dc:creator><pubDate>Wed, 03 Mar 2021 00:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/521adce3-8b32-452b-be78-c5453acdd47c_1084x718.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>We are all familiar with the automated systems that answer our calls then ask a list of predefined questions to try and resolve simple queries. They&#8217;re known as Interactive Voice Response (IVR) call flows and are incredibly useful at allowing call-centre staff to spend more time answering the difficult queries.</p><p>Having recently helped develop such IVR flows, I&#8217;ve been surprised by the lack of freely available tooling to automate testing them. I&#8217;ve instead been subjected to manually calling the flow each time I wanted to test a change - a slow and erroneous process.</p><p>To ease my suffering, I&#8217;m creating <a href="https://github.com/SketchingDev/ivr-tester">IVR Tester</a>, a tool that automates calling IVR flows and traversing them based on what it hears. The benefits of such a tool are:</p><ul><li><p>Customers get value quicker. Those developing flows don&#8217;t have to waste time manually calling them each time they them want to regression test it (reducing <a href="https://www.davefarley.net/?p=218">cycle time</a>)</p></li><li><p><a href="https://en.wikipedia.org/wiki/Synthetic_monitoring">Synthetic testing</a> can be set up to routinely test that production call flows are working as expected from the customer&#8217;s perspective</p></li><li><p>End-to-end tests can test flows and their integrations, as part of a continuous delivery pipeline</p></li></ul><p>Developing this tool has been an interesting journey and one I&#8217;d like to share with you from a high-level (hopefully non-technical) perspective. You can read <a href="https://ivr-tester.makingchatbots.com/">IVR Tester&#8217;s documentation</a> for a more technical overview.</p><p>Let us begin by observing a human interacting with a call flow&#8230;</p><h2>How a human interacts with an IVR call flow</h2><p>From the customer&#8217;s perspective they:</p><ol><li><p>Call the number from their phone</p></li><li><p>Hear a (often computer generated) voice asking a question, e.g. &#8220;Press 1 to make an appointment or press 2 to &#8230;&#8221;</p></li><li><p>Respond by either speaking a word, or more likely by pressing a key on the keypad</p></li><li><p>Repeat from step 2 until their query is resolved, they&#8217;re forwarded to a human, or they hang up in frustration</p></li></ol><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zWMX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4cc948c7-89b5-45bd-aecc-e2cbb9585447_1424x534.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zWMX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4cc948c7-89b5-45bd-aecc-e2cbb9585447_1424x534.png 424w, https://substackcdn.com/image/fetch/$s_!zWMX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4cc948c7-89b5-45bd-aecc-e2cbb9585447_1424x534.png 848w, https://substackcdn.com/image/fetch/$s_!zWMX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4cc948c7-89b5-45bd-aecc-e2cbb9585447_1424x534.png 1272w, https://substackcdn.com/image/fetch/$s_!zWMX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4cc948c7-89b5-45bd-aecc-e2cbb9585447_1424x534.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zWMX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4cc948c7-89b5-45bd-aecc-e2cbb9585447_1424x534.png" width="1424" height="534" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4cc948c7-89b5-45bd-aecc-e2cbb9585447_1424x534.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:534,&quot;width&quot;:1424,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Human calling IVR call flow and pressing keypad in response to questions&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Human calling IVR call flow and pressing keypad in response to questions" title="Human calling IVR call flow and pressing keypad in response to questions" srcset="https://substackcdn.com/image/fetch/$s_!zWMX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4cc948c7-89b5-45bd-aecc-e2cbb9585447_1424x534.png 424w, https://substackcdn.com/image/fetch/$s_!zWMX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4cc948c7-89b5-45bd-aecc-e2cbb9585447_1424x534.png 848w, https://substackcdn.com/image/fetch/$s_!zWMX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4cc948c7-89b5-45bd-aecc-e2cbb9585447_1424x534.png 1272w, https://substackcdn.com/image/fetch/$s_!zWMX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4cc948c7-89b5-45bd-aecc-e2cbb9585447_1424x534.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Simulating a human interacting with an IVR call flow</h2><p>Let&#8217;s tackle each step and build out our application as we go. We start with a blank application that runs on any computer.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!oLBf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2f253a6-7636-46ff-88ca-b0d94aed3bde_450x386.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!oLBf!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2f253a6-7636-46ff-88ca-b0d94aed3bde_450x386.png 424w, https://substackcdn.com/image/fetch/$s_!oLBf!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2f253a6-7636-46ff-88ca-b0d94aed3bde_450x386.png 848w, https://substackcdn.com/image/fetch/$s_!oLBf!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2f253a6-7636-46ff-88ca-b0d94aed3bde_450x386.png 1272w, https://substackcdn.com/image/fetch/$s_!oLBf!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2f253a6-7636-46ff-88ca-b0d94aed3bde_450x386.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!oLBf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2f253a6-7636-46ff-88ca-b0d94aed3bde_450x386.png" width="450" height="386" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f2f253a6-7636-46ff-88ca-b0d94aed3bde_450x386.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:386,&quot;width&quot;:450,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Blank application ready for functionality to be added&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Blank application ready for functionality to be added" title="Blank application ready for functionality to be added" srcset="https://substackcdn.com/image/fetch/$s_!oLBf!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2f253a6-7636-46ff-88ca-b0d94aed3bde_450x386.png 424w, https://substackcdn.com/image/fetch/$s_!oLBf!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2f253a6-7636-46ff-88ca-b0d94aed3bde_450x386.png 848w, https://substackcdn.com/image/fetch/$s_!oLBf!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2f253a6-7636-46ff-88ca-b0d94aed3bde_450x386.png 1272w, https://substackcdn.com/image/fetch/$s_!oLBf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2f253a6-7636-46ff-88ca-b0d94aed3bde_450x386.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>Calling the IVR flow</h3><p>Calling a phone number is a complicated business, but thankfully companies like <a href="http://twilio.com/">Twilio</a> abstract away this complexity. In Twilio&#8217;s case, they offer their <a href="https://www.twilio.com/blog/media-streams-public-beta">MediaStream API</a>, which can call a phone number and then establish a bi-directional audio stream with our application. Our application is then capable of listening to a call&#8217;s audio, and responding with its own audio.</p><p>Once plumbed in, it is a 3-step process to establish a call:</p><ol><li><p>Our application requests that Twilio makes the phone call for us</p></li><li><p>Twilio does the complicated business of making the call</p></li><li><p>Twilio then establishes the bi-directional audio stream with our application</p></li></ol><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!DMX3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd8dfe01-ee42-4b14-a860-9e60f0d36418_1280x540.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!DMX3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd8dfe01-ee42-4b14-a860-9e60f0d36418_1280x540.png 424w, https://substackcdn.com/image/fetch/$s_!DMX3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd8dfe01-ee42-4b14-a860-9e60f0d36418_1280x540.png 848w, https://substackcdn.com/image/fetch/$s_!DMX3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd8dfe01-ee42-4b14-a860-9e60f0d36418_1280x540.png 1272w, https://substackcdn.com/image/fetch/$s_!DMX3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd8dfe01-ee42-4b14-a860-9e60f0d36418_1280x540.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!DMX3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd8dfe01-ee42-4b14-a860-9e60f0d36418_1280x540.png" width="1280" height="540" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fd8dfe01-ee42-4b14-a860-9e60f0d36418_1280x540.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:540,&quot;width&quot;:1280,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Application establishing bi-directional audio stream with IVR flow&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Application establishing bi-directional audio stream with IVR flow" title="Application establishing bi-directional audio stream with IVR flow" srcset="https://substackcdn.com/image/fetch/$s_!DMX3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd8dfe01-ee42-4b14-a860-9e60f0d36418_1280x540.png 424w, https://substackcdn.com/image/fetch/$s_!DMX3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd8dfe01-ee42-4b14-a860-9e60f0d36418_1280x540.png 848w, https://substackcdn.com/image/fetch/$s_!DMX3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd8dfe01-ee42-4b14-a860-9e60f0d36418_1280x540.png 1272w, https://substackcdn.com/image/fetch/$s_!DMX3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd8dfe01-ee42-4b14-a860-9e60f0d36418_1280x540.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>If you&#8217;re interested, you can see what the code looks like to achieve this: <a href="https://github.com/SketchingDev/ivr-tester/blob/4d85b12d4d1187072145690e70f4a6a456401119/packages/ivr-tester/src/call/TwilioCaller.ts#L40-L61">TwilioCaller.ts</a></p><p>We now have our call. The next problem is trying to understand what the IVR call flow is asking us&#8230;</p><h3>Hearing the IVR flow</h3><p>Millions of years of evolution and a basic education means that us humans can understand the flow&#8217;s audio prompts with ease, however computers haven&#8217;t been so fortunate. To provide the application with a basic recognition capability, we&#8217;re going to transcribe the audio, as text is much easier to perform matches against (which we&#8217;ll do later on).</p><p>The two main providers for transcribing audio streams are <a href="https://cloud.google.com/speech-to-text">Google&#8217;s Speech-to-Text</a> and <a href="https://aws.amazon.com/transcribe/">Amazon&#8217;s Transcribe</a>. Although both APIs are very similar, Google&#8217;s is more geared towards telephony, as it allows you to provide the telephony standard audio format of 8-bit PCM mono uLaw (8Khz sampling rate) and has a model pre-trained for phone calls.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!72C0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f2c8ee8-811b-443b-9650-080cb48358aa_1872x452.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!72C0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f2c8ee8-811b-443b-9650-080cb48358aa_1872x452.png 424w, https://substackcdn.com/image/fetch/$s_!72C0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f2c8ee8-811b-443b-9650-080cb48358aa_1872x452.png 848w, https://substackcdn.com/image/fetch/$s_!72C0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f2c8ee8-811b-443b-9650-080cb48358aa_1872x452.png 1272w, https://substackcdn.com/image/fetch/$s_!72C0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f2c8ee8-811b-443b-9650-080cb48358aa_1872x452.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!72C0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f2c8ee8-811b-443b-9650-080cb48358aa_1872x452.png" width="1456" height="352" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9f2c8ee8-811b-443b-9650-080cb48358aa_1872x452.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:352,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Application transcribing audio from Twilio&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Application transcribing audio from Twilio" title="Application transcribing audio from Twilio" srcset="https://substackcdn.com/image/fetch/$s_!72C0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f2c8ee8-811b-443b-9650-080cb48358aa_1872x452.png 424w, https://substackcdn.com/image/fetch/$s_!72C0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f2c8ee8-811b-443b-9650-080cb48358aa_1872x452.png 848w, https://substackcdn.com/image/fetch/$s_!72C0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f2c8ee8-811b-443b-9650-080cb48358aa_1872x452.png 1272w, https://substackcdn.com/image/fetch/$s_!72C0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f2c8ee8-811b-443b-9650-080cb48358aa_1872x452.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Once again, here&#8217;s the code if you&#8217;re interested: <a href="https://github.com/SketchingDev/ivr-tester/blob/4d85b12d4d1187072145690e70f4a6a456401119/packages/transcriber-google-speech-to-text/src/GoogleSpeechToText.ts">GoogleSpeechToText.ts</a></p><p>Now when we establish a call we can forward the audio to Google&#8217;s Speech-to-Text service and receive a transcription like below:</p><blockquote><p>Please enter the numbers from your post code. For example, if your post code is a 12 8 B c. He would enter 12 indeed. Please. Breath has when you are finished</p></blockquote><p>The observant amongst you will have noticed the last part makes no sense at all, and herein lies the Achilles heel of this approach. Transcriptions aren&#8217;t perfect (although they can be trained), so we have to be lenient to these mistakes, e.g. by matching on the section of text, &#8220;Please enter the numbers from your postcode&#8221;.</p><h3>Responding to a question</h3><p>Navigating a call flow is more reliably performed using your phone&#8217;s keypad - we&#8217;ve all had a frustrating experience with voice-recognition. Pressing your keypad works by producing a tone within the voice-frequency band that is unique to each key - known as DTMF or touch tones.</p><p>Producing them programmatically is beyond my expertise, however <a href="https://github.com/SketchingDev/ivr-tester/tree/4d85b12d4d1187072145690e70f4a6a456401119/packages/ivr-tester/src/call/dtmf/raw">creating audio files that can be played back isn&#8217;t</a>. These audio files can be easily created using <a href="http://sox.sourceforge.net/">Sound eXchange (SoX)</a>:</p><pre><code># Generates tone for '1' by combining 1209 Hz and 697 Hz sine waves
sox -n -r 8000 -t raw -e u-law -c 1 -b 8 1.raw synth 0.5 sin 1209 sin 697 pad 0 0.5
</code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QaOv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d169e2e-8004-4188-80e8-14dfeb389ec5_1872x552.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QaOv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d169e2e-8004-4188-80e8-14dfeb389ec5_1872x552.png 424w, https://substackcdn.com/image/fetch/$s_!QaOv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d169e2e-8004-4188-80e8-14dfeb389ec5_1872x552.png 848w, https://substackcdn.com/image/fetch/$s_!QaOv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d169e2e-8004-4188-80e8-14dfeb389ec5_1872x552.png 1272w, https://substackcdn.com/image/fetch/$s_!QaOv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d169e2e-8004-4188-80e8-14dfeb389ec5_1872x552.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QaOv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d169e2e-8004-4188-80e8-14dfeb389ec5_1872x552.png" width="1456" height="429" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6d169e2e-8004-4188-80e8-14dfeb389ec5_1872x552.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:429,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Application responding to a call with DTMF tones&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Application responding to a call with DTMF tones" title="Application responding to a call with DTMF tones" srcset="https://substackcdn.com/image/fetch/$s_!QaOv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d169e2e-8004-4188-80e8-14dfeb389ec5_1872x552.png 424w, https://substackcdn.com/image/fetch/$s_!QaOv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d169e2e-8004-4188-80e8-14dfeb389ec5_1872x552.png 848w, https://substackcdn.com/image/fetch/$s_!QaOv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d169e2e-8004-4188-80e8-14dfeb389ec5_1872x552.png 1272w, https://substackcdn.com/image/fetch/$s_!QaOv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d169e2e-8004-4188-80e8-14dfeb389ec5_1872x552.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The application can now push the contents of these files onto the call&#8217;s audio stream to simulate a phone&#8217;s keypad being pressed.</p><h3>When to play a response</h3><p>Our application can now establish calls, transcribe their audio and simulate a keypad being pressed. However, it doesn&#8217;t yet know how to recognise an instruction in the transcription and what it should respond with - without this it cannot traverse an IVR flow.</p><p>Naturally, we don&#8217;t want to entangle these instructions within the application since they&#8217;ll be different for each flow, so instead we&#8217;ll create external files that define how our application should traverse a flow, like so:</p><pre><code>const test = {
  name: "Customer is asked for their account number",
  instructions: inOrder([
    {
      whenPrompt: contains("please enter your account number"),
      then: press("1234567"),
    },
    // ...
  ]),
}
</code></pre><p>This example &#8216;definition file&#8217; tells our application that when the call&#8217;s transcription contains <em>&#8220;please enter your account number&#8221;</em>, it should then simulate pressing the keys &#8216;1234567&#8217; on the keypad. Hopefully our definition is also fluent enough to act as documentation for the flow too!</p><h3>Putting it all together</h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Ttqv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfa6fade-4c20-44cc-8e7b-cee468d04458_1872x550.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Ttqv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfa6fade-4c20-44cc-8e7b-cee468d04458_1872x550.png 424w, https://substackcdn.com/image/fetch/$s_!Ttqv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfa6fade-4c20-44cc-8e7b-cee468d04458_1872x550.png 848w, https://substackcdn.com/image/fetch/$s_!Ttqv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfa6fade-4c20-44cc-8e7b-cee468d04458_1872x550.png 1272w, https://substackcdn.com/image/fetch/$s_!Ttqv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfa6fade-4c20-44cc-8e7b-cee468d04458_1872x550.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Ttqv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfa6fade-4c20-44cc-8e7b-cee468d04458_1872x550.png" width="1456" height="428" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cfa6fade-4c20-44cc-8e7b-cee468d04458_1872x550.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:428,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Application that can establish, translate and respond to calls&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Application that can establish, translate and respond to calls" title="Application that can establish, translate and respond to calls" srcset="https://substackcdn.com/image/fetch/$s_!Ttqv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfa6fade-4c20-44cc-8e7b-cee468d04458_1872x550.png 424w, https://substackcdn.com/image/fetch/$s_!Ttqv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfa6fade-4c20-44cc-8e7b-cee468d04458_1872x550.png 848w, https://substackcdn.com/image/fetch/$s_!Ttqv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfa6fade-4c20-44cc-8e7b-cee468d04458_1872x550.png 1272w, https://substackcdn.com/image/fetch/$s_!Ttqv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfa6fade-4c20-44cc-8e7b-cee468d04458_1872x550.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>After gluing it all together, and adding a few bells and whistles, you end up with something like <a href="https://github.com/SketchingDev/ivr-tester">IVR Tester</a>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8gR8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d687382-d5b5-413e-ac7b-abd734962797_1090x796.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8gR8!,w_424,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d687382-d5b5-413e-ac7b-abd734962797_1090x796.gif 424w, https://substackcdn.com/image/fetch/$s_!8gR8!,w_848,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d687382-d5b5-413e-ac7b-abd734962797_1090x796.gif 848w, https://substackcdn.com/image/fetch/$s_!8gR8!,w_1272,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d687382-d5b5-413e-ac7b-abd734962797_1090x796.gif 1272w, https://substackcdn.com/image/fetch/$s_!8gR8!,w_1456,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d687382-d5b5-413e-ac7b-abd734962797_1090x796.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8gR8!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d687382-d5b5-413e-ac7b-abd734962797_1090x796.gif" width="1090" height="796" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0d687382-d5b5-413e-ac7b-abd734962797_1090x796.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:796,&quot;width&quot;:1090,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Terminal running a test with IVR Tester&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Terminal running a test with IVR Tester" title="Terminal running a test with IVR Tester" srcset="https://substackcdn.com/image/fetch/$s_!8gR8!,w_424,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d687382-d5b5-413e-ac7b-abd734962797_1090x796.gif 424w, https://substackcdn.com/image/fetch/$s_!8gR8!,w_848,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d687382-d5b5-413e-ac7b-abd734962797_1090x796.gif 848w, https://substackcdn.com/image/fetch/$s_!8gR8!,w_1272,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d687382-d5b5-413e-ac7b-abd734962797_1090x796.gif 1272w, https://substackcdn.com/image/fetch/$s_!8gR8!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d687382-d5b5-413e-ac7b-abd734962797_1090x796.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Conclusion</h2><p>This article has focused on just one of many interesting problems which come with making a tool like this. However, the most exciting of these will be integrating it into the testing of call flows used by hundreds of customers - a process that I will be sure to blog about!</p><p>Like what you read? Follow me on <a href="https://www.linkedin.com/in/lucas-woodward-the-dev/">LinkedIn</a> to be notified of future articles.</p>]]></content:encoded></item></channel></rss>