Received incorrect secret key or hmac

Topic summary

A developer is experiencing HMAC verification failures when validating Shopify CarrierService API requests for custom shipping rates in a Node.js app.

Current Issue:

  • The verification code works correctly on a dummy/development store (Free plan)
  • Same code fails on the production store (Advanced Shopify plan)
  • Uses standard HMAC-SHA256 verification with x-shopify-hmac-sha256 header and API secret key

Troubleshooting Steps:

  • Developer retrieves secret keys from both stores’ configuration pages
  • Upon re-testing, discovered x-request-id header doesn’t exist in requests

Recommended Solution:
Shopify support suggested contacting the Partner Support team through the Partner Dashboard (not App support, since this is an unpublished custom app). Support can verify correct scopes are applied and check detailed logs using the x-request-id, though its absence may complicate debugging.

Status: Unresolved - developer plans to contact Partner Support for further investigation into why identical verification logic behaves differently across store plans.

Summarized with AI on November 19. AI used: claude-sonnet-4-5-20250929.

I have an app in Node.js to provide custom shipping rates using Shopify CarrierService API. Below is my code to verify the request to check if it is coming from Shopify

...
const verifyWebhook = (payload, hmac, apiSecret) => {
  const message = JSON.stringify(payload);
  const genHash = crypto
    .createHmac('sha256', apiSecret || '')
    .update(message)
    .digest('base64');

  return genHash === hmac;
};

const router = express.Router();

router.post('/customshippingrates', async (req, res) => {
  const hmac = req.header('x-shopify-hmac-sha256');
  const storeUrl = req.header('x-shopify-shop-domain');
  const payload = req.body;

  const { store: storeRepo } = repositories;
  const stores = await storeRepo.find({
    where: { apiUrl: ILike(`https://${storeUrl}%`) },
  });

  let store;
  for (let i = 0; i < stores.length; i++) {
    let tmpStore = stores[i];
    if (tmpStore.apiSecret && verifyWebhook(payload, hmac, tmpStore.apiSecret)) {
      store = tmpStore;
      break;
    }
  }
...

The verification works for a dummy store I use for development.

But the same code failed the verification for our production store (not sure if it will make any difference, but I am using Advanced Shopify Plan here, unlike the dummy store, which is on the Free plan)

I get the secret keys from this page in both stores:

It is weird and confusing.

1 Like

Hi @ezdev you might like to reach out to our support team with the x-request-id for the failed response on the production store. Our support can check if the correct scopes are applied or if the logs show any detailed errors. Hope this helps.

hi @ShopifyDevSup , can you please confirm the right channel for the support team?

I can see there is “App” support, but this is our custom app that has not been published yet. Hence, I am unable to select an app on the next screen after clicking on “Apps”

Hey @ezdev ,

The best solution would be to contact our partner team directly from your Partner Dashboard under ‘Support’ while logged in. This will then give you the option to communicate via email or chat.

Hope that helps!

1 Like

In re-testing it, x-request-id does not exist in the request header. Not sure if this is expected.

But anyway, I will contact Partner Support then. Thanks.