I am new to shopify app development. As I was trying to deploy an app on the marketplace I came across a requirement to have mandatory privacy webhooks in place. After a bit research I was able to use the template file that comes and send a 200 OK response since we don’t collect or use any customer data.
I got an email that my app was rejected due to
App must verify the authenticity of the request from Shopify.
Expected HTTP 401 (Unauthorized), but got HTTP 302 from https://server/api/webhooks/shop_redact. Your app's HTTPS webhook endpoints must validate the HMAC digest of each request, and return an HTTP 401 (Unauthorized) response code when rejecting a request that has an invalid digest
How do I validate the request? Any example of this with the basic boiler plate code that we get from shopify?
privacy.js
import { DeliveryMethod } from "@shopify/shopify-api";
/**
* @type {{[key: string]: import("@shopify/shopify-api").WebhookHandler}}
*/
export default {
/**
* Customers can request their data from a store owner. When this happens,
* Shopify invokes this privacy webhook.
*
* https://shopify.dev/docs/apps/webhooks/configuration/mandatory-webhooks#customers-data_request
*/
CUSTOMERS_DATA_REQUEST: {
deliveryMethod: DeliveryMethod.Http,
callbackUrl: "/api/webhooks",
callback: async (topic, shop, body, webhookId) => {
const payload = JSON.parse(body);
// Payload has the following shape:
// {
// "shop_id": 954889,
// "shop_domain": "{shop}.myshopify.com",
// "orders_requested": [
// 299938,
// 280263,
// 220458
// ],
// "customer": {
// "id": 191167,
// "email": "[email protected]",
// "phone": "555-625-1199"
// },
// "data_request": {
// "id": 9999
// }
// }
return {
statusCode: 200,
body: JSON.stringify({}),
}
},
},
/**
* Store owners can request that data is deleted on behalf of a customer. When
* this happens, Shopify invokes this privacy webhook.
*
* https://shopify.dev/docs/apps/webhooks/configuration/mandatory-webhooks#customers-redact
*/
CUSTOMERS_REDACT: {
deliveryMethod: DeliveryMethod.Http,
callbackUrl: "/api/webhooks",
callback: async (topic, shop, body, webhookId) => {
const payload = JSON.parse(body);
// Payload has the following shape:
// {
// "shop_id": 954889,
// "shop_domain": "{shop}.myshopify.com",
// "customer": {
// "id": 191167,
// "email": "[email protected]",
// "phone": "555-625-1199"
// },
// "orders_to_redact": [
// 299938,
// 280263,
// 220458
// ]
// }
return {
statusCode: 200,
body: JSON.stringify({}),
}
},
},
/**
* 48 hours after a store owner uninstalls your app, Shopify invokes this
* privacy webhook.
*
* https://shopify.dev/docs/apps/webhooks/configuration/mandatory-webhooks#shop-redact
*/
SHOP_REDACT: {
deliveryMethod: DeliveryMethod.Http,
callbackUrl: "/api/webhooks",
callback: async (topic, shop, body, webhookId) => {
const payload = JSON.parse(body);
// Payload has the following shape:
// {
// "shop_id": 954889,
// "shop_domain": "{shop}.myshopify.com"
// }
return {
statusCode: 200,
body: JSON.stringify({}),
}
},
},
};
2
Answers
These webhooks are the same as any other in Shopify. The only difference is, you don’t ask for them, they are given to you. So you provide your App endpoint to handle webhooks, and then just add in the topics of these privacy webhooks to process. So assuming you coded up the uninstall webhook already, just follow that pattern by putting in the 3 from Shopify privacy, and let your router handle the rest. In other words, this is even simpler than a regular webhook in that you don’t need to ask for it.
As the error message states, it is not enough only to handle the webhook by returning 200, you have to verify the webhook first and if the verification fails, return the appropriate HTTP status code that would be 401 in this case.
You can find more details about verifying the webhook in Shopify Docs
For doing it in Node.js use this guide or something similar from related StackOverflow answers.
Moreover, you have to do this verification for all webhooks that you are using not just the privacy webhooks.