Your app must respond to [mandatory webhook topics](/docs/apps/webhooks/configuration/mandatory-webhooks). In addition, your app can register [optional webhook topics](/docs/api/admin-rest/current/resources/webhook#event-topics). There are app-specific and shop-specific webhooks. We recommend app-specific webhooks for most apps, but there are reasons to register shop-specific webhooks. For more information, please read [App-specific vs shop-specific webhooks](https://shopify.dev/docs/apps/build/webhooks/subscribe#app-specific-vs-shop-specific-subscriptions).
The easiest way to configure webhooks is to use app-specific webhooks in `shopify.app.toml`. You can find more info in the [webhooks documentation](/docs/apps/webhooks/getting-started-declarative). To set up a simple HTTPS webhook subscription, you can follow these steps: 1. Add the topic to subscribe to in `shopify.app.toml`. In this example we subscribe to the `APP_UNINSTALLED` topic. 1. Review the required scopes for the webhook topics, and update your [app scopes](/docs/apps/tools/cli/configuration#access_scopes) as necessary. 1. Run `shopify app deploy` from the CLI to save your webhooks configuration.
[webhooks]
api_version = "2024-04"
[[webhooks.subscriptions]]
topics = [ "app/uninstalled" ]
uri = "/webhooks"
compliance_topics = [ "customers/data_request", "customers/redact", "shop/redact" ]
Shop-specific webhooks are useful when you need to subscribe to different webhook topics for different shops, or when a topic is not supported by app-specific webhooks.Configure `shopifyApp` and to setup shop-specific webhook subscriptions with the following steps: 1. The webhooks you want to subscribe to. In this example we subscribe to the `APP_UNINSTALLED` topic. 1. The code to register the `APP_UNINSTALLED` topic after a merchant installs you app. Here `shopifyApp` provides an `afterAuth` hook. 1. Review the required scopes for the webhook topics, and update your [app scopes](/docs/apps/tools/cli/configuration#access_scopes) as necessary. > Note: You can't register mandatory topics using this package, you must [configure those in the Partner Dashboard](/docs/apps/webhooks/configuration/mandatory-webhooks) instead.
import {shopifyApp, DeliveryMethod} from '@shopify/shopify-app-remix/server';
const shopify = shopifyApp({
apiKey: 'abcde1234567890',
// ...etc
webhooks: {
APP_UNINSTALLED: {
deliveryMethod: DeliveryMethod.Http,
callbackUrl: '/webhooks',
},
},
hooks: {
afterAuth: async ({session}) => {
// Register webhooks for the shop
// In this example, every shop will have these webhooks
// You could wrap this in some custom shop specific conditional logic if needed
shopify.registerWebhooks({session});
},
},
});
export const authenticate = shopify.authenticate;
Create a route in your app to handle incoming webhook requests for each `callbackUrl` you set in your configuration.Legitimate webhook requests are always `POST` requests signed by Shopify, so you must authenticate them before taking any action. To do this you must set up an `action` that uses the `authenticate.webhook` function to authenticate the request. Please keep in mind that webhook endpoints should respond as quickly as possible. If you need to run a long-running job, then consider using background tasks. > Caution: Webhook endpoints **must** respond with an `HTTP 200` code, or Shopify will retry.
import {ActionFunctionArgs} from '@remix-run/node';
import db from '../db.server';
import {authenticate} from '~/shopify.server';
export const action = async ({request}: ActionFunctionArgs) => {
const {topic, shop, session} = await authenticate.webhook(request);
switch (topic) {
case 'APP_UNINSTALLED':
// Webhook requests can trigger after an app is uninstalled
// If the app is already uninstalled, the session may be undefined.
if (session) {
await db.session.deleteMany({where: {shop}});
}
break;
case 'CUSTOMERS_DATA_REQUEST':
case 'CUSTOMERS_REDACT':
case 'SHOP_REDACT':
default:
throw new Response('Unhandled webhook topic', {status: 404});
}
throw new Response();
};