How to setup mandatory webhooks for a public Shopify app in your Django application

HeySander
1 min readMar 16, 2022

When you want to publish a public Shopify app, you need to setup three mandatory webhooks. shopify.dev provides good documentation and a few code examples, which you’ll all find on this page.

What kind of logic to write at the # Process webhook payload comment depends on your approach. In my case I get a “ShopifyConnect” model based on the “shop_id” from the retrieved body and send an email to the shop owner aka. my user with the needed information. You can read more about the purpose per view on this page.

For local test environments I prefer using Ngrok, which is very easy to use following their documentation.

views.py

from django.views.decorators.csrf import csrf_exempt
import hmac
import hashlib
import base64

API_SECRET_KEY = 'shpss_xxx'

def _verify_webhook(data, hmac_header):
digest = hmac.new(API_SECRET_KEY.encode('utf-8'), data, digestmod=hashlib.sha256).digest()
computed_hmac = base64.b64encode(digest)

return hmac.compare_digest(computed_hmac, hmac_header.encode('utf-8'))


@csrf_exempt
def customer_data_request(request):
verified = _verify_webhook(request.body, request.headers['X-Shopify-Hmac-SHA256'])
if not verified:
return HttpResponse('Unauthorized', status=401)
# Process webhook payload
# ...
return HttpResponse('Authorized', status=200)


@csrf_exempt
def customer_data_erasure(request):
verified = _verify_webhook(request.body, request.headers['X-Shopify-Hmac-SHA256'])
if not verified:
return HttpResponse('Unauthorized', status=401)
# Process webhook payload
# ...
return HttpResponse('Authorized', status=200)


@csrf_exempt
def shop_data_erasure(request):
verified = _verify_webhook(request.body, request.headers['X-Shopify-Hmac-SHA256'])
if not verified:
return HttpResponse('Unauthorized', status=401)
# Process webhook payload
# ...
return HttpResponse('Authorized', status=200)

urls.py

from django.urls import repath
from . import views

urlpatterns = [
re_path(r'^webhook/customers/data-request$', views.customer_data_request, name='customer_data_request'),
re_path(r'^webhook/customers/redact$', views.customer_data_erasure, name='customer_data_erasure'),
re_path(r'^webhook/shop/redact$', views.shop_data_erasure, name='shop_data_erasure')
]

--

--

HeySander
0 Followers

I am an entrepreneur and web developer , currently living in the Netherlands. My tools of choice are Python with Django and some good old vanilla JavaScript.