App reviews, troubleshooting, and recommendations
I'm sure this is an error on my end, but I am having trouble getting my Shopify app to process webhooks for the orders/paid event after the app has not been opened through my Shopify dashboard for a day. I used Shopify's example product-reviews-sample-app as the skeleton for my server.js. The app works exactly as intended and processes my graphql requests as long as the app has recently been opened.
I am getting a 403 response "Failed to process webhook: Error: No webhook is registered for topic orders/paid." I have registered the webhook using 'accessMode: "offline"' and have setup a custom storage method to retrieve the offline access token from a postgresql database so I am not quite sure what the issue is.
import "@babel/polyfill";
import dotenv from "dotenv";
import "isomorphic-fetch";
import createShopifyAuth, { verifyRequest } from "@shopify/koa-shopify-auth";
import Shopify, { ApiVersion } from "@shopify/shopify-api";
import Koa from "koa";
import next from "next";
import Router from "koa-router";
import { enqueueInvLineItemUpdateJob } from "./jobs/inventory-update-by-line-item";
import { SqlSessionStorage } from "./app-session";
dotenv.config();
const port = parseInt(process.env.PORT, 10) || 8081;
const dev = process.env.NODE_ENV !== "production";
const app = next({
dev,
});
const handle = app.getRequestHandler();
Shopify.Context.initialize({
API_KEY: process.env.SHOPIFY_API_KEY,
API_SECRET_KEY: process.env.SHOPIFY_API_SECRET,
SCOPES: process.env.SCOPES
? process.env.SCOPES.split(",")
: "read_orders",
HOST_NAME: process.env.HOST.replace(/https:\/\//, ""),
API_VERSION: ApiVersion.October20,
IS_EMBEDDED_APP: true,
// This should be replaced with your preferred storage strategy
SESSION_STORAGE: SqlSessionStorage,
});
// Storing the currently active shops in memory will force them to re-login when your server restarts. You should
// persist this object in your app.
const ACTIVE_SHOPIFY_SHOPS = {};
app.prepare().then(async () => {
const server = new Koa();
const router = new Router();
server.keys = [Shopify.Context.API_SECRET_KEY];
server.use(
createShopifyAuth({
accessMode: "online",
prefix: "/online",
async afterAuth(ctx) {
// Online access mode access token and shop available in ctx.state.shopify
const { shop } = ctx.state.shopify;
// Redirect to app with shop parameter upon auth
// ctx.redirect(`/?shop=${shop}&host=${host}`);
ctx.redirect(
`https://${shop}/admin/apps/${process.env.SHOPIFY_API_KEY}`
);
},
})
);
server.use(
createShopifyAuth({
accessMode: "offline",
prefix: "/offline",
async afterAuth(ctx) {
// Access token and shop available in ctx.state.shopify
const { shop, accessToken, scope } = ctx.state.shopify;
ACTIVE_SHOPIFY_SHOPS[shop] = shop;
let response = await Shopify.Webhooks.Registry.register({
shop,
accessToken,
path: "/webhooks",
topic: "APP_UNINSTALLED",
webhookHandler: async (topic, shop, body) =>
delete ACTIVE_SHOPIFY_SHOPS[shop],
});
if (!response.success) {
console.log(
`Failed to register APP_UNINSTALLED webhook: ${response.result}`
);
}
response = await Shopify.Webhooks.Registry.register({
shop,
accessToken,
path: "/webhooks",
topic: "ORDERS_PAID",
webhookHandler: async (topic, shop, body) => {
enqueueInvLineItemUpdateJob(shop, JSON.parse(body));
}
});
if (!response.success) {
console.log(
`Failed to register ORDERS_PAID webhook: ${response.result}`
);
}
// Redirect to app with shop parameter upon auth
ctx.redirect(`/online/auth/?shop=${shop}`);
},
})
);
const handleRequest = async (ctx) => {
await handle(ctx.req, ctx.res);
ctx.respond = false;
ctx.res.statusCode = 200;
};
const verifyIfActiveShopifyShop = (ctx, next) => {
const { shop } = ctx.query;
// This shop hasn't been seen yet, go through OAuth to create a session
if (ACTIVE_SHOPIFY_SHOPS[shop] === undefined) {
ctx.redirect(`/offline/auth?shop=${shop}`);
return;
}
return next();
};
router.post("/webhooks", async (ctx) => {
try {
await Shopify.Webhooks.Registry.process(ctx.req, ctx.res);
console.log(`Webhook processed, returned status code 200`);
} catch (error) {
console.log(`Failed to process webhook: ${error}`);
}
});
router.post(
"/graphql",
verifyRequest({ returnHeader: true }),
async (ctx) => {
await Shopify.Utils.graphqlProxy(ctx.req, ctx.res);
}
);
router.get("(/_next/static/.*)", handleRequest); // Static content is clear
router.get("/_next/webpack-hmr", handleRequest); // Webpack content is clear
// Embedded app Next.js entry point
router.get("(.*)", verifyIfActiveShopifyShop, handleRequest);
server.use(router.allowedMethods());
server.use(router.routes());
server.listen(port, () => {
console.log(`> Ready on http://localhost:${port}`);
});
});
Any help is greatly appreciated, and I can provide additional information if needed.
I have the same problem and I can't find a solution. With the Shopify sample webhook application only works the UNINSTALL webhook, if you change it by any other webhook it doesn't work. I
Getting same issue too - my webhooks were working fine before this
My Uninstall webhook works as expected, but I am unable to get
Shopify and our financial partners regularly review and update verification requiremen...
By Jacqui Mar 14, 2025Unlock the potential of marketing on your business growth with Shopify Academy's late...
By Shopify Mar 12, 2025Learn how to increase conversion rates in every stage of the customer journey by enroll...
By Shopify Mar 5, 2025