Trouble with hmac verification for multiple bulk actions: any solutions?

Topic summary

Developers are struggling to verify HMAC signatures for Shopify bulk actions when multiple product IDs are selected. The standard HMAC verification code works for single IDs but fails with multiple IDs.

The Solution:

  • Parse the incoming URL query (e.g., ids%5B%5D=1&ids%5B%5D=2&ids%5B%5D=3)
  • Extract ID values into an array
  • Convert the array to a specific string format: ids=["1", "2"]
  • Key formatting requirements: double quotes around each ID, single whitespace between values, square brackets
  • Insert this formatted string into the alphabetically sorted query parameters before generating the HMAC hash

Critical Details:

  • URL query parameters must be sorted alphabetically
  • The ids parameter must be a formatted string, not an actual array data type
  • Precise formatting is essential for verification to succeed

Community Reaction:
Multiple developers expressed frustration that this undocumented requirement caused them to abandon or delay implementing bulk action features. Some participants report the solution works after testing, though at least one user still encounters issues even after applying the fix. There’s consensus that Shopify should document this requirement properly.

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

Alright man, I just need to make sure I’m following what you’re saying …

When you get a bulk product request, you will receive a URL query like this: shop=random.myshopify.com&ids%5B%5D=1&ids%5B%5D=2&ids%5B%5D=3> > What you must do is parse this URL query. What I did is I created an array, and for each ids%5B%5D within the query I add the value (object ID) to the array.> So, on the backend where you actually verify the Hmac, this is what Shopify expects… They expect you to add this array into the sorted query for the hmac calculated signature.> > What this means is in your sorted query string, you must add ids to be in this (string) format: ids=[“1”, “2”] … Note, this is not an array data type, this is a string that you must print out using the array sent from the client. Also note, the formatting needs to be precise, you must have double quotations ("), and you must add a single character of white space in between values.

Alright, I’m going to pseudo code this, just to keep it language agnostic … but this is what I’m getting from what you’re saying…

**// `shop=random.myshopify.com&ids%5B%5D=1&ids%5B%5D=2&ids%5B%5D=3`**

**getArray = SRV[GET]**
**getIds = SRV[GET]['ids']**

**hmac = getArray.pop('hmac')**
**getArray.pop('ids')**
**getArray.sort(_LEX_)**

**urlQuery = HTTP_UTIL.build_query(getArray)**
<strong>urlQuery.substr_replace('/%5B%5D[*.]$/','')</strong>

**urlQuery.append('=["'+getIds[0]+`",\s"`+getIds[1]+'"]')**

**// so my string should now look like this ... correct? note, the \s is really just for show**
**// i'm just curious if this is what you mean by whitespace between values**
**// `shop=random.myshopify.com&ids=["2295083958321",\s"2612413792305"]`**

**// then from there, I do the usual?**

**hashed = HMAC.hash( algo:'sha256', data:urlQuery, key:__API_SECRET_KEY__ )**

**if(HMAC.compare(hmac == hashed)){**
 **return TRUE**
**}else{**
 **return FALSE**
**}**

Did I get that right? Is this what you’re saying?