Creating a Webhook Listener
As described in our Setting Up Webhooks guide,
testing webhooks using RequestBin.com is a great way to get started with using and understanding webhooks.
It provides temporary URLs that you can register through the ShipEngine dashboard or by using the v1/environment/webhooks
endpoint.
When using ShipEngine in a production environment, you will need to provide a more robust web service to host your own
custom endpoints. This guide walks you through creating a simple web application that exposes an endpoint you can use to subscribe
to ShipEngine track
webhooks.
We will be developing a web application that listens for webhook requests, often called a webhook listener. Our application will run a web server and listen for HTTP POST requests on a specified endpoint This example is written in JavaScript/ NodeJS and uses the Express web framework.
Requirements
To follow along with the steps in this guide, you will need to do the following:
- Install NodeJS per the site's instructions. Likewise, you can use other package managers, such as Homebrew on macOS or Linux, and Chocolatey for Windows.
- Verify that npm was installed successfully along with NodeJS by running the following command
from a terminal:
npm -v
. - Clone the code-samples repo.
- Open an editor where you can write and run code. We will be using Visual Studio Code in this guide, but you can use any editor you are comfortable with.
- In VS Code, select File in the menu bar at the top and then select Open Folder.
- Navigate to the directory where you cloned the repo and select
code-samples/node-webhook-listener-track
- Click the Select button
Now that you have the source code available, we will walk through and explain it line by line.
Install Dependencies
We will be using several external NPM packages in our web application, such as Express
. These
are known as dependencies. We could install each package individually by running npm install <package name>
. However, it
is customary to provide a package.json
file in the root of your project that lists all the project's
dependencies as well as other identifying information about the application. This facilitates installation since all dependencies
for all files in the project are listed in a central location and can all be installed at once with a single command.
When you create a new
NodeJS project, you can run npm init
and answer a series of questions to generate a default package.json
file. We have included a complete package.json
file in the repository.
Open a terminal in the node-webhook-listener-track
directory and run the following command: npm install
.
This command
installs the dependencies we listed in thepackage.json
file and creates a package.json.lock
file to nail down the specific versions installed
since the package.json
file allows us to specify minimum versions.
Import Dependencies
We've now installed all the dependencies required for this application, and we are ready to take a look at the code, which resides in the
index.js
file.
We start by importing the tools and frameworks mentioned above, as well as a few others, at the top of our file. The code below
includes all the packages needed by this application. We will be using express
, which is a web framework that provides
the web server we are using. We will configure express
to use the body-parser
package so that we can access the data in the
requests sent to the endpoint. The other packages are used in other endpoints in this application.
Create the Web Application
At this point, we have specified and installed dependencies, and we are ready to create our web application and define endpoints. When you configure webhooks in ShipEngine, you provide a URL to which ShipEngine will send an HTTP POST request with a JSON payload whenever a particular event occurs. We recommend that you create an individual endpoint for each type of webhook you wish to subscribe to and limit traffic on those endpoints to ShipEngine webhook traffic.
The code below creates an instance of an express
web server and assigns it to the app
variable. We then configure our express
application to use the body-parser
package. Since we called the variable bodyParser
in the import statement above, that's how
we reference it in the code below. The last line of code starts the server, listening on port 3000
for incoming requests.
This line is customarily the last one in the script. We will be filling in our endpoint implementation in the space between.
Create the /track
Endpoint
We now have a very simple web application called app,
but we have not defined any endpoints for our application.
In this example, we are going to create a /track
endpoint to use for tracking event webhooks.
One of the benefits of developing and hosting your own web application is that you can programmatically trigger
other events to occur once you receive the webhook, which we'll demonstrate in our example endpoints.
Before we attempt to implement the /track
endpoint, let's take a look at the structure of the message we expect to
receive. This is an example of the payload the /track
endpoint will receive whenever a tracking event webhook is fired.
Sample Track Webhook Payload
You can see that the example payload above contains a status_code
property, which you can use to find out where the package is in the delivery process.
You can use the status_description
for an explanation of the status_code
. For example, the status_code
'DE' has a status_description
of 'Delivered'.
This payload also contains a tracking_number
, which you should be able
to use to locate the customer and their contact data from within your application - not your webhook listener application but the application you used to create the label you want to receive tracking events for.
The code below is an example implementation of an endpoint that listens for HTTP POST requests. We do this by making a call to the app.post
method of our express
server instance. The first parameter we pass to the app.post
method
is the path we want to use for the endpoint, in this case /track
. The second parameter is a callback function.
If you need more context on asynchronous programming and callback functions, check out this reference. The app.post
method is asynchronous, meaning that the program
does not wait for this call to return before moving to the next line of code in the file. Instead, we pass a callback function as the second parameter to tell the app.post
method what to do when it completes. In this case, we define the callback
function directly in the call to app.post
. This is known as an anonymous function
.
Once the endpoint receives a request, it invokes the callback function. In this case, we extract useful data
from the payload that is sent from the webhook. We can look at the status_code
to determine that the package has been delivered.
We can use the tracking_number
to look up the customer's contact information and send an email informing them that their
package has been delivered, adding a personal touch to your service. We have access to this data on the request object because we configured the application to use the body-parser
package.
Finally, we send a 200
HTTP status code to terminate the call and return program control to the main application. Whenever ShipEngine sends a tracking event webhook to your /track
endpoint, this code will be called.
Putting It All Together
We have now performed the following:
- Cloned the repo.
- Installed the packages using
npm install
. - Created import statements for the packages we want to use in our application.
- Created an
express
web application that listens for requests on port3000
. - Created an endpoint to use for tracking events.
The complete script for the /track
endpoint is included below. If you cloned our code-samples repository,
you will find this example application, in the node-webhook-listener-track
directory.
Running the Webhook Listener
We have now written a web application that exposes a single endpoint. Let's run it locally to test it out. If you are developing in Visual Studio Code, follow these steps to run your application:
- Make sure
index.js
is open in Visual Studio Code. - Set the
API_KEY
variable to a valid API key for your account. - Click
Run
in the top menu. - Select
Start Debugging
. - Selected
Node.js
in the environment drop-down list that is displayed. - You should see a debug window at the bottom of the screen. Your VS Code should look similar to this.
Testing the Webhook Listener
Your application is now running! But let's test it out before we try to use it to receive webhooks. Follow these steps to test that your application is working.
- Download and install Postman
- Open Postman
- Click the orange
New
button - Select
Request
- Give your request a name and click
Save
- Change the method type from
GET
toPOST
in the drop-down - Enter
http://localhost:3000/track
for the URL - Select the
Body
tab - Change the type from
none
toraw
in the drop-down box - Change the type from
Text
toJSON
in the drop-down box - Copy the sample payload above and paste it into the request body
- Paste it into the body area
- Click the
Send
button. You should get a200
HTTP status code and seeOK
in the body. Your screen will look similar to this.
Validation
We copied and pasted the sample payload to use in the test request to our web application because we wrote the endpoint to expect certain
properties in the request and we didn't provide any error handling. Before using the application in production, you will need check that the
message is what you expect and only attempt to access those properties if you receive the correct message. Furthermore, you can check that requests
received on your endpoint are coming from ShipEngine by inspecting the headers from within your endpoint. All requests coming from
ShipEngine will have the user-agent
header set to ShipEngine/v1
.
Authentication
You may also wish to add security to your webhooks by using Basic Authentication. This would require you to supply the username and password directly in the URL as specified in the example below. It would prevent any traffic from reaching your endpoint that did not include the valid username and password in the URL.
Getting to Production
At this point, we have created a simple web application that listens for webhook requests on the /track
endpoint. We tested it locally
by sending a sample webhook payload using Postman. There are additional steps you will need to take before you can configure
ShipEngine to use the endpoints exposed by this application. Namely, you will need to host your application and make it publicly
accessible so that ShipEngine can reach it.
If you have an existing web application that integrates with ShipEngine, then you should be familiar with the steps required to host your webhook listener application. If not, you'll probably need to start by registering a domain name for your application. You will then need to select a cloud provider, such as AWS, Azure, or GCP to host your application and provide DNS services for your application.
You might also use a web hosting service that handles domain registration, hosting, security, and other facets of web hosting for you.