WooCommerce Webhook and AWS Lambda
Tags: woocommerce, wordpress, aws, awslambda
Published: 2021-09-12 02:32:36

WooCommerce is very popular platform for e-commerce, while it's in PHP and usually self-hosted on self-managed servers or shared host, I got some question from my friend to extend WooCommerce functionality. It's possible to write plugin but for my use cases, using WC Webhook and AWS Lambda is more convenient. In this example, I will handle Webhook call when order is updated (order.updated).

More information about WC Webhook
* [API Document](https://woocommerce.github.io/woocommerce-rest-api-docs/?javascript#delivery-payload)
* [Sample payload](https://gist.github.com/teer823/b0670117038250379e2d860368e90f7d)

### Pre-requisites
* Pre installed Wordpress & WooCommerce (And your host IP)
* Basic knowledge of creating lambda function with NodeJS runtime
* Basic knowledge about to create REST API on API Gateway

### Architecture
![Architecture](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yuy08lbnhuxi1278wlot.png)

---
### Workflow
When receiving Webhook event, it's important to check for integrity of Webhook content to prevent malicious request. In order to do so we can calculate HMAC using Webhook content and secret which store in both side. After validated event integrity, we can proceed to process event.

![Workflow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dxn9jti40cpdj47y9q8w.png)

---
### Setup AWS Lambda
First, let create Lambda function that will process our webhook event.

* Create lambda function with Node runtime
![Setup Lambda](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ft5fpjh5b7o8tbfx5m81.png)

* Set up Configuration > Environment Variables > Add WC_SECRET (this same value should be used when configure WooCommerce Webhook later)
![Environment Variable](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c7nqcsk9phtowpqxluea.png)

* Add The following Code to Lambda `index.js` file
{% gist https://gist.github.com/teer823/d4385a154416f01cdb493528f4cd70dd %}

* For Testing, if you set WC_SECRET to "woocommerce", you can use the following test event in Lambda
{% gist https://gist.github.com/teer823/58d24c62595d02b67c80e7e90f6fdab8 %}

* Deploy and testing Lambda function will give you the success screen with event log (`OnOrderCompleted` in screenshot below)
![Lambda Test Result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ui4hlprt7amxd6plgq11.png)

---
### Setup API Gateway
Next step is to create API Gateway to receive webhook. For some unknown reason, WooCommerce Webhook don't fire pre-flight request (OPTION) and always skip [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS), so I will skip detail about enabling CORS here.
* Create REST API
![Create REST API](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a6ao0u0ey02m8dkfd74x.png)

* Create Resource (order)
![Create Order Resource](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9irf79i2576b3hbkimy7.png)

* Create POST method point to the Lambda function created earlier. Note that we need to enable Lambda Proxy Integration in order to forward header to Lambda Function.
![Create POST Method](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9nv1lbrjspoa3mo7fvmo.png)

* In order to only allow API call which initiate from our WooCommerce server. Create Resource Policy with explicit Deny on call from IP outside our own servers.
   ![Resource Policy](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5hxqxnb8ecgku762ezn7.png)
    Using Resource Policy below, replace `REGION`, `ACCOUNT_ID`, `API_ID` and `SOURCE_CIDR` with your own configuration.
    ```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "execute-api:Invoke",
            "Resource": "arn:aws:execute-api:{{REGION}}:{{ACCOUNT_ID}}:{{API_ID}}/*/*/*"
        },
        {
            "Effect": "Deny",
            "Principal": "*",
            "Action": "execute-api:Invoke",
            "Resource": "arn:aws:execute-api:{{REGION}}:{{ACCOUNT_ID}}:{{API_ID}}/*/*/*"
            "Condition": {
                "NotIpAddress": {
                    "aws:SourceIp": "{{SOURCE_CIDR}}"
                }
            }
        }
    ]
}
    ```
* Finally, Deploy API and get your Webhook target URL (don't forget to add your resource name when calling it)
![Deploy](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bw9dmqetojlxn62ydtx4.png)

---
### Setup WooCommerce Webhook
Go to your WooCommerce (in my case i use ngrok to host it locally) and config Webhook
* To config webhook go to `Setting > Advanced > Webhooks` and select `Add Webhook` 
![Webhook Setting](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/26bsugaq1mxxiumd4n5v.png)

* Config new webhook as we plan
    * `Status` : `Active`
    * `Topic` : `Order Updated`
    * `Delivery URL` : API Gateway's `Invoke URL` following by `/order` (or any resource name, created in API Gateway)
    * `Secret` : same value with `WC_SECRET` configured in AWS Lambda's Environment Variable.
![Webhook Configuration](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5db4s3jbxs1qcrz6k06l.png)

* Hit Save, you may likely get error 400, like the picture below, because when we setup webhook, woocommerce try to send POST request to our API but we didn't handle it above. However, our webhook will work anyway, let's go to test our webhook.
![Error 400](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g0cm1m3qn3pbottm4k9f.png)

---
### Test it!
Let's test our webhook, create an order and update it to `processing` or `completed` and let's check the logs.

* WooCommerce Log at `Status > Logs` and select log file starting with `webhook-delivery-` and click `view`. In `Response` value, check http response `Code` and `Body` value to see success webhook.
![WC Log](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0so2uzyvl531k6vv461g.png)

* Alternately, you can check CloudWatch Log groups for AWS Lambda log.
![CloudWatch](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ytx76zvja5koqpr9jz1u.png)

### Conclusion
There're many things we can do with WooCommerce Webhook e.g. Save your information for further processing or trigger automation. I write this article aiming for those who want to start explore and expand your e-commerce business, so if you happen to come across this, I hope you found it useful and help you realize your idea in business!