
My First AWS Contact Centre – Part 3
This content was last updated more than 2 years ago. Some information may no longer be current.
This week I’ve been dipping my toe into getting Connect to do something useful and the best way to do that is to hook it up to external data sources, this has been a good learning week from the sense that there are no ‘point and click’ guides that I’ve found to get this working, a good amount was found in various places (API Guides / Help Pages), some of this was trial and error, which is great fun when it works 🙂
So in this blog post we will be going over:
- Connecting between Connect and Lambda to pass back a static Key Value Pair (KVP)
- Connecting between Connect and Lambda which then queries a database (DynamoDB) to return data to use in the call flow
- Connecting between Connect and Lambda which then gets data from a Database to then create a dyanmic SSML reply played back to the caller.
Connecting between Connect and Lambda
If you’ve never heard of Lambda don’t fret. It is a hot topic in the world of ‘Server-less’ computing right now but it’s only really been on the scene for 2.5-3 years. I would highly recommend you go read up about it as this is quickly becoming a new way to architect, design and build services and a significant portion of the Amazon Connect platforms’ flexibility and a key differentiator is going to be this integration capability, so get cosy with code!
To get Connect up and running with Lambda you need to do a few things (This will become easier in the future no doubt)
- Build your Lambda Function
- Allow Permission for Connect to consume your new Function
- Tell Connect to use it in a Contact Flow
1exports.handler = (event, context, callback) => {
2 console.log("Received event from Lily");
3 callback(null, buildResponse());
4 };
5 function buildResponse() {
6 return {
7 foo: "bar",
8 lambdaResult:"Success"
9 };
10 }
The above code is written in Node.JS and is provided by the Connect team in their support documentation. This code is nice and easy to read and what this is basically going to do is send back 2 KVPs as such:

Creating a lamdba query is very simple, just make sure its in the same region as Connect and follow one of the many guides on YouTube or the AWS Help sites.
Once you have created your Lambda function you’ll be able to copy the ARN from the top right of the page:

You need two parts of this for later, the account (that I’ve scrubbed out) and the function name ‘EXAMPLEDB’
Granting Permissions for Connect to consume your new Lambda Query
This is detailed in the Admin guide for connect, to allow this to work you need to ensure that you have the AWS CLI installed, if not get it from AWS here that is installed you need to run AWS CONFIGURE and setup your ACCESS KEY ID and SECRET ACCESS KEY (Create them from IAM, be careful here please, know what you are doing) and make sure your default region matches that where your running Amazon Connect from.
Once that is done then your ready to run the below command, substituting the 3 items in bold with your own information, 2 of the pieces of information came form your Lamdba ARN, the arn:aws:connect needs to come from your Connect admin page.
1aws lambda add-permission –function-name function:EXAMPLEDB /
2–statement-id 1 –principal connect.amazonaws.com /
3–action lambda:InvokeFunction /
4–source-arn arn:aws:connect:us-east-1:123456789012:instance/60504a8c-4795-4488-b563-b23579c5bbd8 /
5–source-account 1234567890
If it works you’ll get something like this:
1{
2 "Statement": {
3 "Sid": "1",
4 "Resource": "arn:aws:lambda:us-east-1:1234567890:function:EXAMPLEDB",
5 "Effect": "Allow",
6 "Principal": {
7 "Service": "connect.amazonaws.com"
8 },
9 "Action": [
10 "lambda:InvokeFunction"
11 ],
12 "Condition": {
13 "StringEquals": {
14 "AWS:SourceAccount": "123456789012"
15 },
16 "ArnLike": {
17 "AWS:SourceArn": "arn:aws:connect:us-east-1:123456789012:instance/60504e3c-4795-4588-b663-b11179c5aaa8"
18 }
19 }
20 }
21}
Configure Connect.
Now we have Lambda and a working IAM policy we now need to get connect to consume this, how you use it is going to be upto yourselves, for this Lambda call it only returns static KVPs. so this Contact Flow will be fine:

Step by step:

In summary, we provide the Lamdba arn in the Invoke step (no other details required) we then move the reply varaible of ‘foo’ (which has the vaule of ‘bar’) into a USER DEFINED variable of myFirstKey. We then use TTS to play the contents of myFirstKey to the caller (so they hear ‘bar’) and the call is disconnected.
This is a good shake down test that you have everything working before you move onto more complex items such as:
Connecting between Connect and Lambda which then queries a database (DynamoDB) to return data to use in the call flow
Ok so this time we use the below code:
1var AWS = require("aws-sdk");
2var docClient = new AWS.DynamoDB.DocumentClient();
3
4exports.handler = function(event, context, callback) {
5 var table = process.env.table;
6 var ANI = event.Details.ContactData.CustomerEndpoint.Address;
7
8 var params = {
9 TableName: table,
10 Key: {
11 "ANI": ANI
12 }
13 };
14
15 docClient.get(params, function(err, data) {
16 if (err) {
17 console.error("Unable to read item. Error JSON:", JSON.stringify(err, null, 2));
18 } else {
19 console.log("GetItem succeeded:", JSON.stringify(data, null, 2));
20 }
21 callback(null, data.Item);
22 });
23};
This code is taking in 2 variables, creates a DynamoDB call and returning the results of the call back to Connect. I have specifically used 2 types of variables that your likely to have not seen before (unless your all over connect and lambda that it :). They are:
| var table = process.env.table;
| var ANI = event.Details.ContactData.CustomerEndpoint.Address;
process.env.table is a Lambda feature that allows for Environment Variables to be used within Lambda code without the need for different Lamdba calls for different environments. (you can use it for much more than that, but that’s the selling point). What we do here is create a variable outside of the code and then the code pulls that in at run-time. This variable has been set as:

CONNECT-ANI-CHECK is my DynamoDB Table (I’ve hard-coded it here for ease of you following the code trail)
The second variable is: event.Details.ContactData.CustomerEndpoint.Address; and this is taken from the JSON request that Connect sent to Lambda. This element is the callers ANI, which is passed along with all the below as default with every Lambda call from Connect:

Ok so we have our code, we have an ANI and a Table to hit… now for the DynamoDB table…..

As you can see this table is fairly simple for our testing purpose. We can test our Lambda call by using the TEST feature within Lambda, so let’s mimic a call from Connect for caller with ANI +441234567890

And we get the below results:

And as requested by Connect we provide simple KVPs as the reply. And as these are external variables you need to use the SET ATTRIBUTE step to be able to save them to the CTRs, as we did in the first example.
Connecting between Connect and Lambda which then gets data from a Database to then create a dynamic SSML reply played back to the caller.
Ok we’re on the home stretch now, we have Lambda working, we now have Database integration but what about dynamic messages… oohhhhh 🙂 In this example we use the same scenario as Part Two with SSML and the caller needing to be reminded of their PIN. SSML is great for proving that great customer experience but how can we do that on the fly… here’s how…
Setup a new Lambda call (You need to do the Policy update this new Lambda on the AWS CLI). Here’s the code:
The code here again pulls back all the info from Dynamo (we can change this if needed), but this time it takes PIN, converts it to a string and build a SSML sentence that matched exactly the example from part two. This SSML is then sent back to Connect as a KVP such as:
1var AWS = require("aws-sdk");
2var docClient = new AWS.DynamoDB.DocumentClient();
3
4exports.handler = function(event, context, callback) {
5 var table = process.env.table;
6 var ANI = event.Details.ContactData.CustomerEndpoint.Address;
7
8 var params = {
9 TableName: table,
10 Key: {
11 "ANI": ANI
12 }
13 };
14
15 docClient.get(params, function(err, data) {
16 if (err) {
17 console.error("Unable to read item. Error JSON:", JSON.stringify(err, null, 2));
18 } else {
19 console.log("GetItem succeeded:", JSON.stringify(data, null, 2));
20 }
21
22 var PINRAW = data.Item.PIN.toString();
23 var text = "<speak>Your reminder pin is <break time='3s'/>" + PINRAW[0];
24 text = text + "<break time='3s'/>" + PINRAW[1];
25 text = text + "<break time='3s'/>" + PINRAW[2];
26 text = text + "<break time='3s'/>" + PINRAW[3] + '. Thank you for calling my first aws contact centre… goodbye now! </speak>';
27
28 console.log(data);
29 console.log(text);
30
31 callback(null, {PIN: text});
32 });
33};

Thus in the Contact Flow we have the following settings:

And it sounds great!
CTRs:

Note SSML is not saved, only the text.
Tidbits:
- The crosses on the contact flow are too small (in properties)
- Getting this working was trail and error, I hope you enjoy and reciprocate 🙂
- Lambda calls need to be sized right with CPU. - You do this by increasing your Memory allocation for testing a 1000ms RTT is ok, but not for production, get that down to sub <40ms with a simple CPU boost
- Lambda calls might need to be pre-warmed
- Monitor, log, monitor and log, oh and monitor.
That’s all for this time!