AWS Startups Blog

Create Post-Purchase Notifications using AWS Lambda & Amazon API Gateway with ClaudiaJS

Guest post by Richard Moot, Developer Evangelist, Shippo

Shippo AWS use case

An easy way for an ecommerce store to improve customer retention is to provide a better post-purchase experience. If you improve the experience for customers after they purchase your product, it increases the likelihood that they will purchase from you again.

One solution is to connect Shippo’s shipment tracking webhooks with Twilio’s SMS API. In this way, we can track notifications that are sent to a customer whenever there is an update to an order’s status while it’s in transit. We also want to know how many people are opting in to receive notifications, and how often we might need to send those notifications. Here is where AWS Lambda and Amazon API Gateway can really shine. Using those AWS services helps us to avoid the tedious work of creating a system to dynamically allocate sufficient resources to manage user load. We can scale as needed, and we can also use serverless pay-per-use Lambda functions so that we don’t have to pay for infrastructure. To make everything even easier, we use a deployment automation tool called ClaudiaJS (more on that later) to do most of the heavy lifting for us.

In this post, I walk you through a sample project that uses a Twilio API and a Shippo API to create a service that automatically sends SMS shipment tracking updates. Twilio provides the ability to send the SMS messages, while Shippo pushes the tracking updates to our API Gateway webhook URL.

The following diagram shows how this works (the green path is the data flow).

Twilio and Shippo API architecture

To get started with this tutorial, you need the following:

  • Twilio account – You need your account SID and auth token from the account (you can find both in your dashboard after signing up).
  • Shippo account – You just need to plug in your API endpoint URL to the webhooks area to have it work.
  • Node.js 4.3.2 – The functions run on NodeJS in AWS.
  • ClaudiaJS – You use this tool to automate the deployment process.

ClaudiaJS is a deployment management tool that simplifies the process of creating and managing AWS Lambda functions and Amazon API Gateway endpoints. It automates all the error-prone deployment and configuration tasks and sets everything up out of the box, the way JavaScript developers expect.

You can get ClaudiaJS by installing it globally on your machine using the following command:

npm install -g Claudia

Claudia needs access to your AWS account. For information about setting up access credentials for ClaudiaJS so that you can create Lambda functions and API endpoints, see Installing and Configuring ClaudiaJS.

If you want to use a separate user account instead of the main user account, assign the following roles to the user:

  • AWSLambdaFullAccess – Required for all Claudia deployments.
  • IAMFullAccess – Required if you want Claudia to automatically create execution roles for your Lambda function (recommended for beginners). If you can’t use this role because of corporate policies, or if you don’t want to grant Claudia access to the AWS IAM service, then you can create a Lambda execution role manually and pass the name --role <ROLE NAME> using  when executing claudia create.
  • AmazonAPIGatewayAdministrator – Required if you want to use Claudia API Builder or Claudia Bot Builder, or if you want to deploy the API Gateway Proxy APIs.

You can create the project folder using the following command (you can skip this if you simply cloned the repo):

mkdir twilio-shippo && cd twilio-shippo

You can speed up initializing your project using the following command, which generates package.json for you:

npm init --yes

After you create package.json, you can install the dependencies that you need for the function to work. You need the ClaudiaJS API Builder and the Twilio node library to get up and running:

npm install -S twilio claudia-api-builder

The end goal is to get something like what we have at app.js in the repo. Feel free to simply copy and modify from there, or use the next set of instructions in this tutorial to deploy using ClaudiaJS.

Next, create an app file called app.js where you will build out your Lambda function. You also need to specify how your API endpoint will work. Start by adding your function dependencies at the top of your file:

var ApiBuilder = require('claudia-api-builder'),
    api = new ApiBuilder(),
    twilio = require('twilio')('TWILIO_ACCOUNT_SID', 'TWILIO_AUTH_TOKEN');

From here, create the API endpoint that you will put into Shippo’s webhook interface for capturing all of your tracking updates. Every time Shippo detects a new update to the status of a tracking number that you have POSTed to them, Shippo will send updates to your endpoint.

You must export your function so that Claudia can package everything up to be deployed to AWS for you. You can continue with the following in your app.js file:You are creating a POST endpoint because Shippo will be POSTing the tracking updates to you. You then parse the data to relay over to Twilio to send out your SMS messages.

var ApiBuilder = require('claudia-api-builder'),
    api = new ApiBuilder(),
    twilio = require('twilio')('TWILIO_ACCOUNT_SID', 'TWILIO_AUTH_TOKEN');

module.exports = api;

api.post('sms-updates', function(req){
    // Our Lambda logic will go here
});

You are creating a POST endpoint because Shippo will be POSTing the tracking updates to you. You then parse the data to relay over to Twilio to send out your SMS messages.

As an example, let’s start by parsing the body of a message that Shippo has sent to us. We’ll set up a few variables to prevent repeating ourselves, and we’ll add some logic in there to handle if there is no location provided with our tracking update:

api.post('/sms-updates', function(req) {
  var body = req.body,
      trackingStatus = body.tracking_status,
      trackingLocation = 'UNKNOWN';

  if (trackingStatus.location && trackingStatus.location.city) {
      trackingLocation = 
          trackingStatus.location.city + ', ' + trackingStatus.location.state
  }

  // Next we’ll implement our call to Twilio
});

Now that we have our logic built for handling the body of the response and can safely handle when we don’t get a location with our tracking status, we can dig into sending a formatted SMS using Twilio.

The basic format for sending Twilio messages requires that we have a destination number (to send our SMS to), our Twilio number that we’re sending from, and a message to send (duh!).

Here’s what it looks like after we add the code to send our message:

api.post('/sms-updates', function(req) {
  var body = req.body,
      trackingStatus = body.tracking_status,
      trackingLocation = '';

  if (trackingStatus.location && trackingStatus.location.city) {
      trackingLocation = 
          trackingStatus.location.city + ', ' + trackingStatus.location.state
  }

  return twilio
      .sendMessage({
        to: '+1-TEST_NUMBER',     // This should be your destination number
        from: '+1-TWILIO_NUMBER', // This is your Twilio number in your account
        body: 'Tracking #: ' + body.tracking_number + // Here's our message
              '\nStatus: ' + trackingStatus.status +
              '\nLocation: ' + trackingLocation
      })
      .then(function(success) {
        // We are using a promise here to help Claudiajs
        // make sure the request finishes executing, otherwise
        // our function will exit before it we're successfully send our
        // request
        console.log(success);
      })
      .catch(function(error) {
        console.log(error);
      });
});

In the preceding code, note that we use a Promise to resolve the function. We do this because ClaudiaJS looks for whether you’re using a Promise in your Lambda function, and then lets it continue to run until the Promise resolves (or your function times out, which is around 3 seconds by default in AWS).

Now that you have a composed Lambda function and an API Gateway endpoint, you can deploy all of this to AWS using your ClaudiaJS CLI tool. If you set up your AWS credentials at ~/.aws/credentials  (as specified at https://claudiajs.com/tutorials/installing.html), you can just use the following command:

claudia create --name twilio-shippo --region us-west-2 --api-module app --profile Claudia

As you can see, the preceding command follows this format:

claudia create --name NAME_OF_APP --region AWS_REGION --api-module FILENAME --profile AWS_CREDENTIALS_PROFILE

There are some scripts in package.json named create and  update that can be useful when you’re crafting your Lambda function.

Next, ClaudiaJS will package and deploy the Lambda function that you’ve created and also will create an Amazon API Gateway endpoint. The Amazon API Gateway endpoint is tied to your function to execute whenever a request is received. At the completion of your deployment, ClaudiaJS will provide a URL that points to the API Gateway endpoint.

You can plug the API Gateway endpoint link shown in the console into Shippo to start sending your tracking updates. You’ll see our link printed out to the terminal under “url“. That is the link you paste into Shippo:

{
  "lambda": {
    "role": "twilio-shippo-executor",
    "name": "twilio-shippo",
    "region": "us-west-2"
  },
  "api": {
    "id": "YOUR_UNIQUE_ID",
    "module": "app",
    "url": "https://YOUR_UNIQUE_ID.execute-api.us-west-2.amazonaws.com/latest"
  }
}

Next, navigate to https://app.goshippo.com/api, scroll down to Webhooks, and then choose + Add webhook. Because you had your route go to sms-updates, you append that to your url so that the updates post to the right place. This  gives you something like the following:

https://YOUR_UNIQUE_ID.execute-api.us-west-2.amazonaws.com/latest/sms-updates

add webhooks in account settings

Paste this into the URL field in Shippo, make sure that the dropdown under Event Type is set to tracking, and then choose the green check box to save it. Now you can test the function by choosing test on the right. If everything goes well, you should receive an SMS with tracking information at the number you had in the to field of your Twilio  sendMessage object.

Now you can get SMS updates for all the numbers that you post to Shippo automatically without having to provision any servers, and you pay only when you receive updates using AWS Lambda and Amazon API Gateway with AWS. You could take it a step further by including phone numbers for SMS updates in the metadata field when POSTing to Shippo, and you could parse that out to dynamically send SMS updates to customers.


For more information about Shippo and how to use their shipping API to improve your shipping experience, see https://goshippo.com/docs.