How to Create Shopify Webhooks With the Shopify API Tutorial
Shopify webhooks help build integrations with external applications that need to respond in real-time to events taking place in a Shopify store. You can create and manage Shopify webhooks using the Shopify admin dashboard. Although easy to use, the admin interface does not allow developers to perform automated tasks on their webhooks. Instead, users have to log into the admin interface and manually perform webhook-related tasks.
As a solution to this drawback, Shopify opened up its webhook API. This allows programmatic interaction with Shopify webhooks, thereby expanding the scope of what is possible with the technology.
In this article, I will walk you through how to set up authentication with the Shopify API, and then use the Shopify webhooks API to create and view your webhooks. You will also use a locally running API to receive and log your webhooks.
Let's get right into it!
Tutorial Prerequisites
To follow along with this tutorial, you will need a couple of things:
- A Shopify store
- The ability to create Shopify private apps (you may not have this permission if you're not the direct owner of the store you're working with)
- Node.js installed on your system (if you already have a local API that you prefer to use, that is fine as long as you make sure it exposes a
POST
endpoint and listens on a known port) - Hookdeck CLI installed (you can find details on installing the tool here)
Creating a Shopify store app
The first step to accessing and using the Shopify webhooks API is to create a Shopify store app. There are 3 types of Shopify apps: public, custom, and private. To learn more about the different types of Shopify apps and how to create them, read the documentation pages here.
To access the Shopify API, we are going to create a private app. Private apps are built to work exclusively for your Shopify store (unlike public apps that can be used by any Shopify store and are listed on the Shopify App store). Private apps also allow you to access your store's data directly using the Shopify API.
To create a Shopify app, click Apps
on the side menu of the admin interface. Just below the main section on the Apps page, click the Manage Private Apps
link and then click the Create private app
button.
On the app creation page, enter the name for the application you are about to create (in this example, Purchase Log API
) and enter your email. Next, in the Admin API
section, expand the Show Inactive Admin API
and give Read and write
access to the following resources...
- Order editing
- Orders
...as shown below:
Once the permissions are set, scroll down and select the latest API version (at the time of this writing, the latest version is 2021-10).
Click Save
to complete this process. You will be prompted with a pre-save message informing you that an API key will be generated to provide access to the store's data.
Click Create app
on this prompt and you will be taken to the app page. On this page, you will find the following credentials in the Admin API
section:
- API key (this is your username when using Basic authentication)
- Password (this is your API access token)
- Example URL (a sample URL format for performing basic authentication using a username and password)
- Shared Secret (used for verifying webhooks, more on this later)
With these credentials, you have all you need to authenticate with the Shopify API.
Authenticating with the Shopify API
Now that you have your authentication credentials, let's discuss how you will go about making authenticated calls to the Shopify API. It is important to note that the different types of Shopify apps do not use the same authentication strategy.
While public and custom apps use OAuth and session tokens, private apps use basic authentication. In this section, I will only be discussing authentication for private apps.
There are 3 ways you can authenticate with the Shopify API using credentials from your private app.
1) Username and password combo
If your client supports basic authentication, you can include authentication credentials in your URL. This is done by prepending username:password@
to the hostname in the URL as shown below:
https://{username}:{password}@{shop}.myshopify.com/admin/api/{version}/webhooks.json
username
: Your API key.password
: Your private app password.shop
: Your Shopify store subdomain string, e.g.hookdeck-store
.version
: The version of the API you're using, e.g.2021-10
.
Any request made to the Shopify API using this URL is automatically authenticated.
2) Using an authorization token
Some clients do not support basic authentication as used in the above method. You can go around this issue by using the Basic {token}
value in the Authorization
header. The token
value is derived by joining your store app's API key and password with a colon (:
) and encoding the resulting string in base64. The Authorization
header can then be sent, as shown below:
Authorization: Basic NDQ3OGViN2FjMTM4YTEzNjg1MmJhYmQ4NjE5NTZjMTk6M2U1YTZlZGVjNzFlYWIwMzk0MjJjNjQ0NGQwMjY1OWQ=
3) Using the X-Shopify-Access-Token header
The last strategy for authenticating private apps is to send the X-Shopify-Access-Token
header, along with your request, to the Shopify API. The value of this header is your private app's password, which is your access token. The header is sent as follows:
X-Shopify-Access-Token: {my_app_password}
This is the strategy we will be using for all our API calls in this tutorial.
Now that you know how to authenticate with the Shopify API, let's start creating and receiving Shopify webhooks.
Setting up and receiving Shopify webhooks using the Shopify API
As described earlier, we will create a webhook using the Shopify API. Then, we'll spin up a local API to receive and log part of the webhook payload.
Before we begin, let's walk you through the steps necessary to achieve this webhook logging setup.
- Clone the demo API and run it locally
- Use the Hookdeck CLI to generate a webhook URL that points to the API endpoint
- Create a webhook using the API
- Test your webhook by triggering the subscription event
- Inspect your webhook and webhook logs
- Verify the webhook payload
Now that you're caught up, let's begin.
Clone the demo API
Clone the application repository for the API by running the following command:
git clone --single-branch --branch shopify-webhooks https://github.com/hookdeck/nodejs-webhook-server-example.git
Navigate to the root of the project and install the required dependencies by running the following commands:
cd nodejs-webhook-server-example
npm install
When the installation completes, you can then run the Node.js server with the following command:
npm start
This will boot up the API application and print a message to the screen indicating that the API is now running and listening for connections on port 1337
.
We are using two endpoints in this project.
/log-shopify-webhook
: This is the endpoint that will be receiving the Shopify webhook and logging it into an in-memory database. It logs a simple object containing a subset of the information from the webhook payload./fetch-webhooks-logs
: This endpoint can be called to retrieve a collection of the logged webhook data.
Generate the webhook URL using the Hookdeck CLI
The next step is to use the CLI to generate a webhook URL that points to the running API application. To do this, run the following command (note: replace the port 1337
value with the port number on which your API is running if you're not using the sample project):
hookdeck listen 1337
This command starts an interactive session where the CLI collects information about the endpoint you're about to create. Below are the questions and the answers you should supply to each question. Ensure to hit the Enter
key after each answer.
Prompt | Answer |
---|---|
What source should you select? | Create new source (this prompt does not show up if you have not created any previous connections) |
What should your new source label be? | Shopify |
What path should the webhooks be forwarded to (i.e.: /webhooks)? | /log-shopify-webhook (if you're using your own custom server, replace this value with your endpoint) |
What's the connection label (i.e.: My API)? | Purchase Log API |
With this information, the CLI will begin the process of generating the URL and once it's done, you will see the URL printed to the screen and the CLI indicating that it is ready to receive requests.
Note: If you're running the CLI in guest mode, you will need to use the guest Login URL
link in the console to access the dashboard. Copy and paste this into your browser to begin a guest login session.
Create a Shopify webhook using the API
Now that you have your webhook URL, let's create the webhook. Shopify's webhook API can be accessed at https://{shop}.myshopify.com/admin/{version}/webhooks.json
(remember to replace the values in {}
with yours).
To create a webhook, you need to send a POST
request to this endpoint containing data. You can use any HTTP client of your choice (Postman, Curl, etc.). In this tutorial, I am using ReqBin because it is accessible and easy to use.
For the webhook you are creating in this tutorial, you must subscribe to the orders/create
. This event is fired when a new order is created in your store.
The data to send along with your webhook creation request should be structured as follows:
{
"webhook": {
"topic": "orders/create",
"address": "{webhook_url}",
"format": "json"
}
}
As seen in the above snippet, the format to receive the webhook is set as json
, so remember to replace {webhook_url}
with the webhook URL generated on the Hookdeck CLI session.
Open https://reqbin.com and paste the API URL in the address field, then set the request method to POST
. For authentication, add the X-Shopify-Access-Token
field in the Headers
section as shown below (replace MY_ACCESS_TOKEN
with your Shopify app password):
The header will now be reflected in the details under the Raw
section. Lastly, click the Content
section and paste in your request object. See below a screenshot of the request setup:
Now hit the Send
button to create your new webhook. You should get back a successful response, like you can see below:
This indicates that you have successfully created a webhook for the orders/create
topic on your Shopify store.
Other actions that can be performed on your Shopify webhooks using the API include updating a webhook, fetching a single webhook, and deleting an existing webhook. For more information on how to perform these operations, visit the Shopify webhooks API documentation.
Test your webhook
With a locally running log API set up to receive webhooks, and a webhook subscription created via the API, the time has come to test your setup.
To receive a webhook for the subscribed topic, you need to trigger the topic's event by creating a new order. You can create a new order easily on your Shopify admin interface. Below, I am placing an order for a Ben Simmons 76er's jersey:
Once the order is created, Shopify will trigger a webhook for the orders/create
event.
This will be received in your Hookdeck CLI session as shown below:
Inspect your webhook and webhook logs
The Hookdeck CLI helps us easily inspect the details contained in a Shopify webhook by providing a URL to an event page that breaks down the webhook data. This URL is the last item on the webhook entry, as shown in the CLI output above. Copy this URL and load it in your browser, and you will see an event page where you can view details like the webhook headers in the Headers
section below:
You also have a browsable representation of the webhook payload in the Body
section:
Finally, let's check to confirm that the locally running API is indeed logging the webhook payload. Still on your browser, navigate to the /fetch-webhooks-logs
endpoint of the locally running API, and you will see a display similar to the one below (ignore the first object):
As seen, you have been able to log the webhook ID, the total number of items in your order, and the time the webhook was delivered.
Verify your Shopify webhooks
Shopify sends you an X-Shopify-Hmac-Sha256
header that can be used to verify that the payload contained in the webhook is from Shopify and has not been spoofed or tampered with.
This header is an encrypted version of the payload and is computed using the private app's shared secret, the webhook payload, and the HMAC cryptographic algorithm.
To verify your webhook on your external API, you compute the same encrypted version of the webhook payload using the shared key and HMAC, then compare the result with the value sent in the X-Shopify-Hmac-Sha256
header. If there is a match, then the payload is valid and it originated from Shopify. If not, then it's suspicious and should be ignored.
You can find this verification logic in the server.js
file as a commented middleware function validatePayload
, shown below:
const sigHeaderName = 'x-shopify-hmac-sha256';
const sigHashAlg = 'sha256';
const secret = "xx-xx-x";
.....
/* function validatePayload(req, res, next) {
if(req.method == "POST"){
if (!req.rawBody) {
return next('Request body empty')
}
const body = req.rawBody;
const hmacHeader = req.get(sigHeaderName);
//Create a hash based on the parsed body
const hash = crypto
.createHmac(sigHashAlg, secret)
.update(body, "utf8", "hex")
.digest("base64");
// Compare the created hash with the value of the X-Shopify-Hmac-Sha256 Header
if (hash !== hmacHeader) {
return next(`Request body digest (${hash}) did not match ${sigHeaderName} (${hmacHeader})`)
}
}
return next()
}
app.use(validatePayload); */
For more information on security considerations for your webhooks, check out our security checklist.
Conclusion
In this article, you have learned and demonstrated how to perform Shopify webhook operations using the webhook API. Being a programmatic interface, the Shopify API allows you to run automated tasks that can, for example, update and fetch webhooks on the fly. You can perform these tasks directly in your code or within CI/CD pipelines to tailor Shopify webhooks towards your application/infrastructure needs.
Happy coding!