/
Shopify Webhook Subscription through Cloud PubSub

Shopify Webhook Subscription through Cloud PubSub

Objective: To subscribe to Shopify Webhooks without performing HMAC Authentication and receive Products, Orders, and App installation/uninstallation Events.

Further Information: https://shopify.dev/apps/webhooks/configuration/google-cloud

Requirements:

  • Shopify App should be either Custom or Public

  • Google Cloud Project

  • Create a topic in Cloud PubSub

Steps: Follow the steps given below to achieve the webhook subscription:

Step 1. Add the following Shopify Service Account Address in the Cloud Project, for ex:

delivery@shopify-pubsub-webhooks.iam.gserviceaccount.com

Step 2. Now we would need respective PubSub topics for each flow such as Orders, Products, and App Installation/Uninstallation.

i. We would need to prepare JSON Request body as shared below:

{ "webhook": { "topic": "products/update", "address": "pubsub://{project-id}:{topic-id}", "format": "json" } }

ii. Then we need to call POST API as follows to Create a Webhook:

https://{shop_id}.myshopify.com/admin/api/{version-api}}/webhooks.json

Sample Request Body:

{ "webhook": { "topic": "orders/create", "address": "pubsub://shopify-integration-staging:shopify-webhook", "format": "json" } }

Sample Response:

{ "webhook": { "id": 1119995986176, "address": "pubsub://shopify-integration-staging:shopify-webhook", "topic": "orders/create", "created_at": "2022-01-17T18:38:09+05:30", "updated_at": "2022-01-17T18:38:09+05:30", "format": "json", "fields": [], "metafield_namespaces": [], "api_version": "2021-01", "private_metafield_namespaces": [] } }

Note: We would need a separate PubSub topic for each flow because we will be identifying the type of event we have received from Shopify through PubSub and then proceed further accordingly. If we are going to use common PubSub for all the flows, it will create overhead as there will be many events coming up.

PubSub Topics:

  1. “Shopify-Webhook-Orders”: This PubSub topic can work for Orders Created, Orders Cancelled, Fulfillments Update.

  2. “Shopify-Webhook-Products”: This PubSub topic can be created for Products Listings

  3. “Shopify-Webhook-App”: All the events related to App installation or uninstallation or any changes can be subscribed to this PubSub topic

Step 3. Now, once the Webhooks are subscribed, we would need to subscribe endpoints to the PubSub topic created. The endpoint will receive the Event from Shopify as shared below:

Sample Event from Shopify before Decrypting:

{ "message": { "attributes": { "Content-Type": "application/json", "X-Shopify-API-Version": "2021-04", "X-Shopify-Hmac-SHA256": "K/gIgjfdADmEfpHXSolfDpZF/kkXM9yHyxp5LLREjNE\u003d", "X-Shopify-Order-Id": "4629239300352", "X-Shopify-Shop-Domain": "testing-ajeet.myshopify.com", "X-Shopify-Test": "false", "X-Shopify-Topic": "orders/create", "X-Shopify-Webhook-Id": "597d4f73-19e1-4d47-a4da-88616a782253" }, "data": "eyJpZCI6NDYyOTIzOTMwMDM1MiwiYWRtaW5fZ3JhcGhxbF9hcGlfaWQiOiJnaWQ6XC9cL3Nob3BpZnlcL09yZGVyXC80NjI5MjM5MzAwMzUyIiwiYXBwX2lkIjoxMzU0NzQ1LCJicm93c2VyX2lwIjpudWxsLCJidXllcl9hY2NlcHRzX21hcmtldGluZyI6ZmFsc2UsImNhbmNlbF9yZWFzb24iOm51bGwsImNhbmNlbGxlZF9hdCI6bnVsbCwiY2FydF90b2tlbiI6bnVsbCwiY2hlY2tvdXRfaWQiOjMyNDQxOTc4ODE0NzIwLCJjaGVja291dF90b2tlbiI6ImFjOTA1MzNlMTVmM2FhMTJkOWNlYjE3NzVkY2E5NzI0IiwiY2xpZW50X2RldGFpbHMiOnsiYWNjZXB0X2xhbmd1YWdlIjpudWxsLCJicm93c2VyX2hlaWdodCI6bnVsbCwiYnJvd3Nlcl9pcCI6bnVsbCwiYnJvd3Nlcl93aWR0aCI6bnVsbCwic2Vzc2lvbl9oYXNoIjpudWxsLCJ1c2VyX2FnZW50IjpudWxsfSwiY2xvc2VkX2F0IjpudWxsLCJjb25maXJtZWQiOnRydWUsImNvbnRhY3RfZW1haWwiOiJwcmF0ZWVrLmthdXNoaWtAZXNob3Bib3guY29tIiwiY3JlYXRlZF9hdCI6IjIwMjItMDEtMThUMTI6MzI6MDArMDU6MzAiLCJjdXJyZW5jeSI6IklOUiIsImN1cnJlbnRfc3VidG90YWxfcHJpY2UiOiIzMDAuMDAiLCJjdXJyZW50X3N1YnRvdGFsX3ByaWNlX3NldCI6eyJzaG9wX21vbmV5Ijp7ImFtb3VudCI6IjMwMC4wMCIsImN1cnJlbmN5X2NvZGUiOiJJTlIifSwicHJlc2VudG1lbnRfbW9uZXkiOnsiYW1vdW50IjoiMzAwLjAwIiwiY3VycmVuY3lfY29kZSI6IklOUiJ9fSwiY3VycmVudF90b3RhbF9kaXNjb3VudHMiOiIwLjAwIiwiY3VycmVudF90b3RhbF9kaXNjb3VudHNfc2V0Ijp7InNob3BfbW9uZXkiOnsiYW1vdW50IjoiMC4wMCIsImN1cnJlbmN5X2NvZGUiOiJJTlIifSwicHJlc2VudG1lbnRfbW9uZXkiOnsiYW1vdW50IjoiMC4wMCIsImN1cnJlbmN5X2NvZGUiOiJJTlIifX0sImN1cnJlbnRfdG90YWxfZHV0aWVzX3NldCI6bnVsbCwiY3VycmVudF90b3RhbF9wcmljZSI6IjM1NC4wMCIsImN1cnJlbnRfdG90YWxfcHJpY2Vfc2V0Ijp7InNob3BfbW9uZXkiOnsiYW1vdW50IjoiMzU0LjAwIiwiY3VycmVuY3lfY29kZSI6IklOUiJ9LCJwcmVzZW50bWVudF9tb25leSI6eyJhbW91bnQiOiIzNTQuMDAiLCJjdXJyZW5jeV9jb2RlIjoiSU5SIn19LCJjdXJyZW50X3RvdGFsX3RheCI6IjU0LjAwIiwiY3VycmVudF90b3RhbF90YXhfc2V0Ijp7InNob3BfbW9uZXkiOnsiYW1vdW50IjoiNTQuMDAiLCJjdXJyZW5jeV9jb2RlIjoiSU5SIn0sInByZXNlbnRtZW50X21vbmV5Ijp7ImFtb3VudCI6IjU0LjAwIiwiY3VycmVuY3lfY29kZSI6IklOUiJ9fSwiY3VzdG9tZXJfbG9jYWxlIjoiZW4iLCJkZXZpY2VfaWQiOm51bGwsImRpc2NvdW50X2NvZGVzIjpbXSwiZW1haWwiOiJwcmF0ZWVrLmthdXNoaWtAZXNob3Bib3guY29tIiwiZmluYW5jaWFsX3N0YXR1cyI6InBhaWQiLCJmdWxmaWxsbWVudF9zdGF0dXMiOm51bGwsImdhdGV3YXkiOiJtYW51YWwiLCJsYW5kaW5nX3NpdGUiOm51bGwsImxhbmRpbmdfc2l0ZV9yZWYiOm51bGwsImxvY2F0aW9uX2lkIjpudWxsLCJuYW1lIjoiIzEwMDQiLCJub3RlIjpudWxsLCJub3RlX2F0dHJpYnV0ZXMiOltdLCJudW1iZXIiOjQsIm9yZGVyX251bWJlciI6MTAwNCwib3JkZXJfc3RhdHVzX3VybCI6Imh0dHBzOlwvXC90ZXN0aW5nLWFqZWV0Lm15c2hvcGlmeS5jb21cLzYxNzEzOTA3OTY4XC9vcmRlcnNcL2ViZWI5MDg0ZjczYWFkNDg4YzdmNzg1NDc4NjVhMzc0XC9hdXRoZW50aWNhdGU/a2V5PTBjYWQzOThlYTE2MjExNjk1Mjg1YTc5Y2NkZDEwYzZlIiwib3JpZ2luYWxfdG90YWxfZHV0aWVzX3NldCI6bnVsbCwicGF5bWVudF9nYXRld2F5X25hbWVzIjpbIm1hbnVhbCJdLCJwaG9uZSI6bnVsbCwicHJlc2VudG1lbnRfY3VycmVuY3kiOiJJTlIiLCJwcm9jZXNzZWRfYXQiOiIyMDIyLTAxLTE4VDEyOjMyOjAwKzA1OjMwIiwicHJvY2Vzc2luZ19tZXRob2QiOiJtYW51YWwiLCJyZWZlcmVuY2UiOm51bGwsInJlZmVycmluZ19zaXRlIjpudWxsLCJzb3VyY2VfaWRlbnRpZmllciI6bnVsbCwic291cmNlX25hbWUiOiJzaG9waWZ5X2RyYWZ0X29yZGVyIiwic291cmNlX3VybCI6bnVsbCwic3VidG90YWxfcHJpY2UiOiIzMDAuMDAiLCJzdWJ0b3RhbF9wcmljZV9zZXQiOnsic2hvcF9tb25leSI6eyJhbW91bnQiOiIzMDAuMDAiLCJjdXJyZW5jeV9jb2RlIjoiSU5SIn0sInByZXNlbnRtZW50X21vbmV5Ijp7ImFtb3VudCI6IjMwMC4wMCIsImN1cnJlbmN5X2NvZGUiOiJJTlIifX0sInRhZ3MiOiIiLCJ0YXhfbGluZXMiOlt7InByaWNlIjoiNTQuMDAiLCJyYXRlIjowLjE4LCJ0aXRsZSI6IklHU1QiLCJwcmljZV9zZXQiOnsic2hvcF9tb25leSI6eyJhbW91bnQiOiI1NC4wMCIsImN1cnJlbmN5X2NvZGUiOiJJTlIifSwicHJlc2VudG1lbnRfbW9uZXkiOnsiYW1vdW50IjoiNTQuMDAiLCJjdXJyZW5jeV9jb2RlIjoiSU5SIn19fV0sInRheGVzX2luY2x1ZGVkIjpmYWxzZSwidGVzdCI6ZmFsc2UsInRva2VuIjoiZWJlYjkwODRmNzNhYWQ0ODhjN2Y3ODU0Nzg2NWEzNzQiLCJ0b3RhbF9kaXNjb3VudHMiOiIwLjAwIiwidG90YWxfZGlzY291bnRzX3NldCI6eyJzaG9wX21vbmV5Ijp7ImFtb3VudCI6IjAuMDAiLCJjdXJyZW5jeV9jb2RlIjoiSU5SIn0sInByZXNlbnRtZW50X21vbmV5Ijp7ImFtb3VudCI6IjAuMDAiLCJjdXJyZW5jeV9jb2RlIjoiSU5SIn19LCJ0b3RhbF9saW5lX2l0ZW1zX3ByaWNlIjoiMzAwLjAwIiwidG90YWxfbGluZV9pdGVtc19wcmljZV9zZXQiOnsic2hvcF9tb25leSI6eyJhbW91bnQiOiIzMDAuMDAiLCJjdXJyZW5jeV9jb2RlIjoiSU5SIn0sInByZXNlbnRtZW50X21vbmV5Ijp7ImFtb3VudCI6IjMwMC4wMCIsImN1cnJlbmN5X2NvZGUiOiJJTlIifX0sInRvdGFsX291dHN0YW5kaW5nIjoiMC4wMCIsInRvdGFsX3ByaWNlIjoiMzU0LjAwIiwidG90YWxfcHJpY2Vfc2V0Ijp7InNob3BfbW9uZXkiOnsiYW1vdW50IjoiMzU0LjAwIiwiY3VycmVuY3lfY29kZSI6IklOUiJ9LCJwcmVzZW50bWVudF9tb25leSI6eyJhbW91bnQiOiIzNTQuMDAiLCJjdXJyZW5jeV9jb2RlIjoiSU5SIn19LCJ0b3RhbF9wcmljZV91c2QiOiI0Ljc3IiwidG90YWxfc2hpcHBpbmdfcHJpY2Vfc2V0Ijp7InNob3BfbW9uZXkiOnsiYW1vdW50IjoiMC4wMCIsImN1cnJlbmN5X2NvZGUiOiJJTlIifSwicHJlc2VudG1lbnRfbW9uZXkiOnsiYW1vdW50IjoiMC4wMCIsImN1cnJlbmN5X2NvZGUiOiJJTlIifX0sInRvdGFsX3RheCI6IjU0LjAwIiwidG90YWxfdGF4X3NldCI6eyJzaG9wX21vbmV5Ijp7ImFtb3VudCI6IjU0LjAwIiwiY3VycmVuY3lfY29kZSI6IklOUiJ9LCJwcmVzZW50bWVudF9tb25leSI6eyJhbW91bnQiOiI1NC4wMCIsImN1cnJlbmN5X2NvZGUiOiJJTlIifX0sInRvdGFsX3RpcF9yZWNlaXZlZCI6IjAuMDAiLCJ0b3RhbF93ZWlnaHQiOjAsInVwZGF0ZWRfYXQiOiIyMDIyLTAxLTE4VDEyOjMyOjAxKzA1OjMwIiwidXNlcl9pZCI6Nzk1NDY2Nzk1NTIsImJpbGxpbmdfYWRkcmVzcyI6eyJmaXJzdF9uYW1lIjoiUHJhdGVlayIsImFkZHJlc3MxIjoiR3VyZ2EiLCJwaG9uZSI6IiIsImNpdHkiOiJHdXJ1Z3JhbSIsInppcCI6IjEyMjAwMSIsInByb3ZpbmNlIjoiSGFyeWFuYSIsImNvdW50cnkiOiJJbmRpYSIsImxhc3RfbmFtZSI6IkthdXNoaWsiLCJhZGRyZXNzMiI6IiIsImNvbXBhbnkiOiJFc2hvcGJveCIsImxhdGl0dWRlIjoyOC40NTU0NzI2LCJsb25naXR1ZGUiOjc3LjAyMTkwMTksIm5hbWUiOiJQcmF0ZWVrIEthdXNoaWsiLCJjb3VudHJ5X2NvZGUiOiJJTiIsInByb3ZpbmNlX2NvZGUiOiJIUiJ9LCJjdXN0b21lciI6eyJpZCI6NTk5MTcyNDE4NzkwNCwiZW1haWwiOiJwcmF0ZWVrLmthdXNoaWtAZXNob3Bib3guY29tIiwiYWNjZXB0c19tYXJrZXRpbmciOmZhbHNlLCJjcmVhdGVkX2F0IjoiMjAyMS0xMi0yN1QxNTo1OTo0MSswNTozMCIsInVwZGF0ZWRfYXQiOiIyMDIyLTAxLTE4VDEyOjMyOjAwKzA1OjMwIiwiZmlyc3RfbmFtZSI6IlByYXRlZWsiLCJsYXN0X25hbWUiOiJLYXVzaGlrIiwib3JkZXJzX2NvdW50Ijo0LCJzdGF0ZSI6ImRpc2FibGVkIiwidG90YWxfc3BlbnQiOiIxNDE2LjAwIiwibGFzdF9vcmRlcl9pZCI6NDYyOTIzOTMwMDM1Miwibm90ZSI6bnVsbCwidmVyaWZpZWRfZW1haWwiOnRydWUsIm11bHRpcGFzc19pZGVudGlmaWVyIjpudWxsLCJ0YXhfZXhlbXB0IjpmYWxzZSwicGhvbmUiOm51bGwsInRhZ3MiOiIiLCJsYXN0X29yZGVyX25hbWUiOiIjMTAwNCIsImN1cnJlbmN5IjoiSU5SIiwiYWNjZXB0c19tYXJrZXRpbmdfdXBkYXRlZF9hdCI6IjIwMjEtMTItMjdUMTU6NTk6NDErMDU6MzAiLCJtYXJrZXRpbmdfb3B0X2luX2xldmVsIjpudWxsLCJ0YXhfZXhlbXB0aW9ucyI6W10sImFkbWluX2dyYXBocWxfYXBpX2lkIjoiZ2lkOlwvXC9zaG9waWZ5XC9DdXN0b21lclwvNTk5MTcyNDE4NzkwNCIsImRlZmF1bHRfYWRkcmVzcyI6eyJpZCI6NzQ4Nzg2MTYyMDk5MiwiY3VzdG9tZXJfaWQiOjU5OTE3MjQxODc5MDQsImZpcnN0X25hbWUiOiJQcmF0ZWVrIiwibGFzdF9uYW1lIjoiS2F1c2hpayIsImNvbXBhbnkiOiJFc2hvcGJveCIsImFkZHJlc3MxIjoiR3VyZ2EiLCJhZGRyZXNzMiI6IiIsImNpdHkiOiJHdXJ1Z3JhbSIsInByb3ZpbmNlIjoiSGFyeWFuYSIsImNvdW50cnkiOiJJbmRpYSIsInppcCI6IjEyMjAwMSIsInBob25lIjoiIiwibmFtZSI6IlByYXRlZWsgS2F1c2hpayIsInByb3ZpbmNlX2NvZGUiOiJIUiIsImNvdW50cnlfY29kZSI6IklOIiwiY291bnRyeV9uYW1lIjoiSW5kaWEiLCJkZWZhdWx0Ijp0cnVlfX0sImRpc2NvdW50X2FwcGxpY2F0aW9ucyI6W10sImZ1bGZpbGxtZW50cyI6W10sImxpbmVfaXRlbXMiOlt7ImlkIjoxMTkyMTAyMDc4MDgwMCwiYWRtaW5fZ3JhcGhxbF9hcGlfaWQiOiJnaWQ6XC9cL3Nob3BpZnlcL0xpbmVJdGVtXC8xMTkyMTAyMDc4MDgwMCIsImRlc3RpbmF0aW9uX2xvY2F0aW9uIjp7ImlkIjozMzY1OTc0NzY5OTIwLCJjb3VudHJ5X2NvZGUiOiJJTiIsInByb3ZpbmNlX2NvZGUiOiJIUiIsIm5hbWUiOiJQcmF0ZWVrIEthdXNoaWsiLCJhZGRyZXNzMSI6Ikd1cmdhIiwiYWRkcmVzczIiOiIiLCJjaXR5IjoiR3VydWdyYW0iLCJ6aXAiOiIxMjIwMDEifSwiZnVsZmlsbGFibGVfcXVhbnRpdHkiOjEsImZ1bGZpbGxtZW50X3NlcnZpY2UiOiJtYW51YWwiLCJmdWxmaWxsbWVudF9zdGF0dXMiOm51bGwsImdpZnRfY2FyZCI6ZmFsc2UsImdyYW1zIjowLCJuYW1lIjoiQUJDIiwib3JpZ2luX2xvY2F0aW9uIjp7ImlkIjozMzY1OTc0NzM3MTUyLCJjb3VudHJ5X2NvZGUiOiJJTiIsInByb3ZpbmNlX2NvZGUiOiJIUiIsIm5hbWUiOiJUZXN0aW5nIEFqZWV0IiwiYWRkcmVzczEiOiIyNzAgLSBHYXJhZ2UgU29jaWV0eSwgQUlIUCBFeGVjdXRpdmUgQ2VudGVyIiwiYWRkcmVzczIiOiIiLCJjaXR5IjoiR3VyZ2FvbiIsInppcCI6IjEyMjAxNiJ9LCJwcmljZSI6IjMwMC4wMCIsInByaWNlX3NldCI6eyJzaG9wX21vbmV5Ijp7ImFtb3VudCI6IjMwMC4wMCIsImN1cnJlbmN5X2NvZGUiOiJJTlIifSwicHJlc2VudG1lbnRfbW9uZXkiOnsiYW1vdW50IjoiMzAwLjAwIiwiY3VycmVuY3lfY29kZSI6IklOUiJ9fSwicHJvZHVjdF9leGlzdHMiOnRydWUsInByb2R1Y3RfaWQiOjc1MjA0MzgxNTc1NjgsInByb3BlcnRpZXMiOltdLCJxdWFudGl0eSI6MSwicmVxdWlyZXNfc2hpcHBpbmciOnRydWUsInNrdSI6IlNLVTEiLCJ0YXhhYmxlIjp0cnVlLCJ0aXRsZSI6IkFCQyIsInRvdGFsX2Rpc2NvdW50IjoiMC4wMCIsInRvdGFsX2Rpc2NvdW50X3NldCI6eyJzaG9wX21vbmV5Ijp7ImFtb3VudCI6IjAuMDAiLCJjdXJyZW5jeV9jb2RlIjoiSU5SIn0sInByZXNlbnRtZW50X21vbmV5Ijp7ImFtb3VudCI6IjAuMDAiLCJjdXJyZW5jeV9jb2RlIjoiSU5SIn19LCJ2YXJpYW50X2lkIjo0MjIzMjYyNjA4NjE0NCwidmFyaWFudF9pbnZlbnRvcnlfbWFuYWdlbWVudCI6InNob3BpZnkiLCJ2YXJpYW50X3RpdGxlIjoiIiwidmVuZG9yIjoiVGVzdGluZyBBamVldCIsInRheF9saW5lcyI6W3sicHJpY2UiOiI1NC4wMCIsInByaWNlX3NldCI6eyJzaG9wX21vbmV5Ijp7ImFtb3VudCI6IjU0LjAwIiwiY3VycmVuY3lfY29kZSI6IklOUiJ9LCJwcmVzZW50bWVudF9tb25leSI6eyJhbW91bnQiOiI1NC4wMCIsImN1cnJlbmN5X2NvZGUiOiJJTlIifX0sInJhdGUiOjAuMTgsInRpdGxlIjoiSUdTVCJ9XSwiZHV0aWVzIjpbXSwiZGlzY291bnRfYWxsb2NhdGlvbnMiOltdfV0sInJlZnVuZHMiOltdLCJzaGlwcGluZ19hZGRyZXNzIjp7ImZpcnN0X25hbWUiOiJQcmF0ZWVrIiwiYWRkcmVzczEiOiJHdXJnYSIsInBob25lIjoiIiwiY2l0eSI6Ikd1cnVncmFtIiwiemlwIjoiMTIyMDAxIiwicHJvdmluY2UiOiJIYXJ5YW5hIiwiY291bnRyeSI6IkluZGlhIiwibGFzdF9uYW1lIjoiS2F1c2hpayIsImFkZHJlc3MyIjoiIiwiY29tcGFueSI6IkVzaG9wYm94IiwibGF0aXR1ZGUiOjI4LjQ1NTQ3MjYsImxvbmdpdHVkZSI6NzcuMDIxOTAxOSwibmFtZSI6IlByYXRlZWsgS2F1c2hpayIsImNvdW50cnlfY29kZSI6IklOIiwicHJvdmluY2VfY29kZSI6IkhSIn0sInNoaXBwaW5nX2xpbmVzIjpbXX0\u003d", "messageId": "3978357054726663", "message_id": "3978357054726663", "publishTime": "2022-01-18T07:02:04.582Z", "publish_time": "2022-01-18T07:02:04.582Z" }, "subscription": "projects/shopify-integration-staging/subscriptions/shopify-webhook-sub" }

Step 3.1: We need to extract "X-Shopify-Shop-Domain" and "X-Shopify-Topic" which will be required to fetch Channel Configuration Data which includes Shopify Store Access Token, Sales Channel Data, etc and Using X-Shopify-Topic, flow can be decided and respective endpoint/service can be called for processing.

Step 4. Using X-Shopify-Shop-Domain, fetch the connectionId from Database or from Cache using the following Cache Key:

  • Cache Key: “shopifyShopDomain_{{shop_id}}“

Using the above Cache Key, we can fetch stored connectionID if the cache is done otherwise we would need to execute the following SQL Query to get the connectionID and then cache it to the above-mentioned Cache Key.

  • SQL QUERY

SELECT id AS connectionId FROM ie_appinstall_connection WHERE inputFields LIKE'%"store_name":"{{shop_id}}"%' AND isActive='active' AND refreshToken IS NOT NULL AND accessToken IS NOT NULL

Step 5. Now we have the connectionId which can be used to fetch Channel Config data which is already done in the existing flow, so the remaining flow will remain unchanged.

 

Related content