Our Partner & Developer boards on the community are moving to a brand new home: the .dev community forums! While you can still access past discussions here, for all your future app and storefront building questions, head over to the new forums.

Re: Webhooks not firing

Solved

Webhooks not firing

Johnny-Slip
Shopify Partner
4 0 0

Hi,

 

We're developing an app where orders and refunds should be logged when the webhooks are triggered.

 

We've set the scopes properly in the toml file, and our code for the shopify.server.js and webhooks.jsx are below:

 

shopify.server.js:

import "@shopify/shopify-app-remix/adapters/node";
import {
  AppDistribution,
  DeliveryMethod,
  shopifyApp,
  LATEST_API_VERSION,
} from "@shopify/shopify-app-remix/server";
import { PrismaSessionStorage } from "@shopify/shopify-app-session-storage-prisma";
import { restResources } from "@shopify/shopify-api/rest/admin/2024-01";
import prisma from "./db.server";

const shopify = shopifyApp({
  apiKey: process.env.SHOPIFY_API_KEY,
  apiSecretKey: process.env.SHOPIFY_API_SECRET || "",
  apiVersion: LATEST_API_VERSION,
  scopes: process.env.SCOPES?.split(","),
  appUrl: process.env.SHOPIFY_APP_URL || "",
  authPathPrefix: "/auth",
  sessionStorage: new PrismaSessionStorage(prisma),
  distribution: AppDistribution.AppStore,
  restResources,
  webhooks: {
    APP_UNINSTALLED: {
      deliveryMethod: DeliveryMethod.Http,
      callbackUrl: "/webhooks",
    },
    ORDERS_CREATE: {
      deliveryMethod: DeliveryMethod.Http,
      callbackUrl: "/webhooks",
    },
    TENDER_TRANSACTIONS_CREATE: {
      deliveryMethod: DeliveryMethod.Http,
      callbackUrl: "/webhooks",
    },
  },
  hooks: {
    afterAuth: async ({ session }) => {
      shopify.registerWebhooks({ session });
    },
  },
  future: {
    v3_webhookAdminContext: true,
    v3_authenticatePublic: true,
    unstable_newEmbeddedAuthStrategy: true,
  },
  ...(process.env.SHOP_CUSTOM_DOMAIN
    ? { customShopDomains: [process.env.SHOP_CUSTOM_DOMAIN] }
    : {}),
});

export default shopify;
export const apiVersion = LATEST_API_VERSION;
export const addDocumentResponseHeaders = shopify.addDocumentResponseHeaders;
export const authenticate = shopify.authenticate;
export const unauthenticated = shopify.unauthenticated;
export const login = shopify.login;
export const registerWebhooks = shopify.registerWebhooks;
export const sessionStorage = shopify.sessionStorage;

 

webhooks.jsx:

 

import { authenticate } from "../shopify.server";
import db from "../db.server";

export const action = async ({ request }) => {
  const { topic, shop, session, admin, payload } =
    await authenticate.webhook(request);

  if (!admin) {
    // The admin context isn't returned if the webhook fired after a shop was uninstalled.
    throw new Response();
  }

  switch (topic) {
    case "ORDERS_CREATE":
      if (session) {
        console.log('Order webhook fired: ', JSON.parse(payload));
        try {
          return new Response("Order created and sent", {status:200});
        } catch (error) {
          console.log(
            "Something went wrong with the orders webhook:",
            error
          );
          return new Response("Error creating order", {status:500});
        }
      }
    case "REFUNDS_CREATE":
      if (session) {
        try {
          console.log('Refund webhook fired: ', JSON.parse(payload));
          return new Response("Refund created and sent", {status:200});
        } catch (error) {
          console.log('Something went wrong with the refund webhook: ',
            error
          );
          return new Response("Error creating refund", {status:500});
        }
      }
    case "TENDER_TRANSACTIONS_CREATE":
      if (session) {
        try {
          return new Response("Transaction created and sent", {status:200});
        } catch (error) {
          console.log('Something went wrong with the transactions webhook: ',
            error
          );
          return new Response("Error creating transaction", {status:500});
        }
      }
    case "APP_UNINSTALLED":
      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();
};

 

We've tried creating a new app, uninstalling it and reinstalling it on several stores, as well as trawling documentation, without success.

Accepted Solution (1)

Oldfire
Shopify Partner
21 2 1

This is an accepted solution.

Hello, you didn't quite say what the problem was, but I can assume!

 

To troubleshoot, I would first check that the webhooks are actually created when you expect them to be created (that is - on new install) via graphQL. Secondly, check that the callbackURL is actually correct - that should point to your backend! Once webhooks are set properly, and it should trigger, start by logging the whole payload to see whether it is actually something you expect before going into the switch statement.

POST http://localhost:3457/graphiql/graphql.json?key=&api_version=2024-01

query webhooks {
  webhookSubscriptions(first: 100) {
    edges {
      node {
        id
        topic
        endpoint {
          __typename
          ... on WebhookHttpEndpoint {
            callbackUrl
          }
          ... on WebhookEventBridgeEndpoint {
            arn
          }
          ... on WebhookPubSubEndpoint {
            pubSubProject
            pubSubTopic
          }
        }
      }
    }
  }
}





View solution in original post

Replies 6 (6)

Liam
Community Manager
3108 344 910

Hi Johnny - the code you've shared looks very much like the examples in our docs, so it's difficult to see why this might be happening. Are you 100% sure the scopes are configured correctly?

Liam | Developer Advocate @ Shopify 
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit Shopify.dev or the Shopify Web Design and Development Blog

Johnny-Slip
Shopify Partner
4 0 0

Hi Liam,

 

Our scopes are defined as part of the toml file as below:

 

# Learn more about configuring your app at https://shopify.dev/docs/apps/tools/cli/configuration

client_id = // Removed for forum post
name = // Removed for forum post
application_url = // Removed for forum post
embedded = true

[build]
automatically_update_urls_on_dev = true
dev_store_url = // Removed for forum post

[access_scopes]
# Learn more at https://shopify.dev/docs/apps/tools/cli/configuration#access_scopes
scopes = "read_orders"

[auth]
redirect_urls = [
// Removed for forum post
]

[webhooks]
api_version = "2024-01"

[pos]
embedded = true

 

When installing the app to a store, it asks for read_orders permission, so I assume it's setup correctly, but perhaps not.

Oldfire
Shopify Partner
21 2 1

This is an accepted solution.

Hello, you didn't quite say what the problem was, but I can assume!

 

To troubleshoot, I would first check that the webhooks are actually created when you expect them to be created (that is - on new install) via graphQL. Secondly, check that the callbackURL is actually correct - that should point to your backend! Once webhooks are set properly, and it should trigger, start by logging the whole payload to see whether it is actually something you expect before going into the switch statement.

POST http://localhost:3457/graphiql/graphql.json?key=&api_version=2024-01

query webhooks {
  webhookSubscriptions(first: 100) {
    edges {
      node {
        id
        topic
        endpoint {
          __typename
          ... on WebhookHttpEndpoint {
            callbackUrl
          }
          ... on WebhookEventBridgeEndpoint {
            arn
          }
          ... on WebhookPubSubEndpoint {
            pubSubProject
            pubSubTopic
          }
        }
      }
    }
  }
}





Johnny-Slip
Shopify Partner
4 0 0

Hi,

 

Thanks for the reply! We've added lots of logs at every stage of the webhook process but none of them fire, and the callback URLs are all correct.

 

So, we've run the query you suggested, and as suspected, the only one that is registered is APP_UNINSTALLED. It is quite confusing! We've tried uninstalling and reinstalling the app to several stores, with no change.

Johnny-Slip
Shopify Partner
4 0 0

Accepted this as the solution as that query did lead to the problem in the end. Thanks.

tempranova
Shopify Partner
1 0 1

It would be really awesome if you could share with us what the problem was?