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.

We're moving the community! Starting July 7, the current community will be read-only for approx. 2 weeks. You can browse content, but posting will be temporarily unavailable. Learn more

Need help with setting up webhooks in remix, admin object not existing, and webhooks not being made

Need help with setting up webhooks in remix, admin object not existing, and webhooks not being made

nebneb8
Shopify Partner
1 0 0

Hi I am trying to create a webhook for ORDERS/CREATE, but nothing seems to be working.  When i test on the local Ngrok with shopify webhook trigger, it always ends up not having an admin object, so the if statement (line 28) enters.  I am not sure if the webhooks are being set up correctly, but i believe i have done everything right. 

 

The APP_UNINSTALLED webhook seems to do its job when it do unistall the app, everything in the db gets cleared, but when i test APP_UNISTALLED in my testing enviorment the admin object is null and the default response 200 is sent.  

 

Here are all my files, please help.

Screenshot 2024-02-14 134158.jpg

Screenshot 2024-02-14 134253.jpg

Screenshot 2024-02-14 134004.jpg

 

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

const updateOrders = async (payload) => {
  console.log('Received payload:', payload);

  const orderId = payload.id; // assuming the payload contains an 'id' field for the order
  const orderNumber = payload.order_number; // assuming the payload contains an 'order_number' field

  console.log(`Updating order with ID: ${orderId} and order number: ${orderNumber}`);

  try {
    const order = await db.order.update({
      where: { id: orderId },
      data: { orderNumber: orderNumber },
    });

    console.log('Order updated successfully:', order);
  } catch (error) {
    console.error('Error updating order:', error);
  }
};

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.
    console.log("No admin context", { topic, shop, session, payload });
    throw new Response();
  }

  switch (topic) {
    case "APP_UNINSTALLED":
      if (session) {
        console.log("App uninstalled", { shop });
        await db.session.deleteMany({ where: { shop } });
      }

      break;
    case "ORDERS_CREATE":
      if (session) {
        console.log("Order created", payload);
        updateOrders(payload);
        return new Response(`Recieved new order for ${shop}`, {status:200});
      }
      break;
    case "CUSTOMERS_DATA_REQUEST":
    case "CUSTOMERS_REDACT":
    case "SHOP_REDACT":
    default:
      throw new Response("Unhandled webhook topic", { status: 404 });
  }

  throw new Response();
};
 
 
// 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",
    },
  },
  hooks: {
    afterAuth: async ({ session }) => {
      await 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;
 
 
 

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

client_id = "118a9d50cdbd89a6baf3cf0d0bf02bf4"
name = "update-order-numbers"
application_url = "https://exist-ordering-nokia-agencies.trycloudflare.com"
embedded = true

[build]
automatically_update_urls_on_dev = true
dev_store_url = "peacefuldev.myshopify.com"
include_config_on_deploy = true

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

[auth]
redirect_urls = [
"https://exist-ordering-nokia-agencies.trycloudflare.com/auth/callback",
"https://exist-ordering-nokia-agencies.trycloudflare.com/auth/shopify/callback",
"https://exist-ordering-nokia-agencies.trycloudflare.com/api/auth/callback"
]

[webhooks]
api_version = "2024-01"

[pos]
embedded = false

Replies 2 (2)

SBD_
Shopify Staff
1831 273 423

Hey @nebneb8 

 

Please post this here: https://github.com/Shopify/shopify-app-template-remix/issues

Scott | Developer Advocate @ Shopify 

KlaudSol_Apps
Shopify Partner
5 0 0

Hello,

 

I encountered the same thing. Apparently Shopify CLI (`shopify app webhook trigger`) leaves `admin` and `session` as null. The trigger mocks a sample shop, and thus have no way of actually creating real `admin` and `session` objects.

 

You need use an actual development site to actually get `admin` and `session` objects. E.g I actually went to the development site and edited my shop details to fire a `shop/update` trigger with a proper `admin` object.

 

This is the trigger that I sent

 

```

shopify app webhook trigger --client-id XXXX --client-secret XXXX --api-version 2024-07 --topic shop/update --address https://constitutes-airports-liked-defects.trycloudflare.com/webhooks

``` 

 

In the webhook, I did

```

console.error({ topic, shop, session, admin, payload });
```
 
It responded with some random shop information:
 
```
12:54:20 │ remix │ {
12:54:20 │ remix │ topic: 'SHOP_UPDATE',
12:54:20 │ remix │ shop: 'shop.myshopify.com',
12:54:20 │ remix │ session: undefined,
12:54:20 │ remix │ admin: undefined,
12:54:20 │ remix │ payload: {
12:54:20 │ remix │ id: 548380009,
12:54:20 │ remix │ name: 'Super Toys',
12:54:20 │ remix │ email: 'super@supertoys.com',
12:54:20 │ remix │ domain: null,
12:54:20 │ remix │ province: 'Tennessee',
12:54:20 │ remix │ country: 'US',
12:54:20 │ remix │ address1: '190 MacLaren Street',
12:54:20 │ remix │ zip: '37178',
12:54:20 │ remix │ city: 'Houston',
12:54:20 │ remix │ source: null,
12:54:20 │ remix │ phone: '3213213210',
12:54:20 │ remix │ latitude: null,
12:54:20 │ remix │ longitude: null,
12:54:20 │ remix │ primary_locale: 'en',
12:54:20 │ remix │ address2: null,
12:54:20 │ remix │ created_at: null,
12:54:20 │ remix │ updated_at: null,
12:54:20 │ remix │ country_code: 'US',
12:54:20 │ remix │ country_name: 'United States',
12:54:20 │ remix │ currency: 'USD',
12:54:20 │ remix │ customer_email: 'super@supertoys.com',
12:54:20 │ remix │ timezone: '(GMT-05:00) Eastern Time (US & Canada)',
12:54:20 │ remix │ iana_timezone: null,
12:54:20 │ remix │ shop_owner: 'John Smith',
12:54:20 │ remix │ money_format: '${{amount}}',
12:54:20 │ remix │ money_with_currency_format: '${{amount}} USD',
12:54:20 │ remix │ weight_unit: 'kg',
12:54:20 │ remix │ province_code: 'TN',
12:54:20 │ remix │ taxes_included: null,
12:54:20 │ remix │ auto_configure_tax_inclusivity: null,
12:54:20 │ remix │ tax_shipping: null,
12:54:20 │ remix │ county_taxes: null,
12:54:20 │ remix │ plan_display_name: 'Shopify Plus',
12:54:20 │ remix │ plan_name: 'enterprise',
12:54:20 │ remix │ has_discounts: false,
12:54:20 │ remix │ has_gift_cards: true,
12:54:20 │ remix │ myshopify_domain: null,
12:54:20 │ remix │ google_apps_domain: null,
12:54:20 │ remix │ google_apps_login_enabled: null,
12:54:20 │ remix │ money_in_emails_format: '${{amount}}',
12:54:20 │ remix │ money_with_currency_in_emails_format: '${{amount}} USD',
12:54:20 │ remix │ eligible_for_payments: true,
12:54:20 │ remix │ requires_extra_payments_agreement: false,
12:54:20 │ remix │ password_enabled: null,
12:54:20 │ remix │ has_storefront: true,
12:54:20 │ remix │ finances: true,
12:54:20 │ remix │ primary_location_id: 655441491,
12:54:20 │ remix │ checkout_api_supported: true,
12:54:20 │ remix │ multi_location_enabled: true,
12:54:20 │ remix │ setup_required: false,
12:54:20 │ remix │ pre_launch_enabled: false,
12:54:20 │ remix │ enabled_presentment_currencies: [ 'USD' ],
12:54:20 │ remix │ marketing_sms_consent_enabled_at_checkout: false,
12:54:20 │ remix │ transactional_sms_disabled: false
12:54:20 │ remix │ }
12:54:20 │ remix │ }
```
https://klaudsol.com
KlaudSol Apps