#store/products ignores SC

1 messages · Page 1 of 1 (latest)

muted scaffold
#

i am back 🙂 i was playing with v2.13.1, looks pormissing.

i come to a weird behaviour and even bloom is undecisive on this topic.

  1. storefront needs a pk to talk to the backend
  2. pk is linked to a SC
  3. there is 4 demo product none of is assigned to the SC

storefront

  1. sdk.store.product.list() returns all products
  2. sdk.store.product.list(region_id: region.id) returns all products

in medusa/packages/medusa/src/api/store/products/route.ts getProductsWithIndexEngine as explicit filtering if it is passed getProducts has none.

Seen the pk is tight to a SC i would expect the product list be filtered on SC based on the pk.

Did I misunderstood something?

#

bloom:

The documentation doesn’t clearly say whether /store/products must implicitly filter by the sales channels of the publishable API key when you don’t pass sales_channel_id, so I can’t definitively label the behavior as a bug based on docs alone.

What is documented:

Storefront requests to /store/* must include a publishable API key, and that key “specif[ies] the sales channel scope” and is “used to retrieve products available in that sales channel.” [Storefront chapter; PAK + SC; PAK SC error]
/store/products supports an explicit sales_channel_id query parameter to “retrieve products in [a sales channel].” [Store GetProducts params]
But the docs do not explicitly state:

That the PK’s sales channels are always applied as an implicit filter on /store/products when sales_channel_id is omitted.
Or that you must pass sales_channel_id yourself if you want strict SC filtering.
So:

If your expectation is “with a PK scoped to SC A that has no products, /store/products with no sales_channel_id should return zero products,” the docs don’t clearly confirm or deny that behavior.
The only guaranteed way (per docs) to filter by SC is to pass sales_channel_id in the request.
Given the available sources, I can’t confidently say “yes, it’s a bug” or “no, it’s intended”; the behavior in that exact edge case isn’t specified. To be safe in your implementation, explicitly pass sales_channel_id when you need strict sales-channel filtering.
muted scaffold
#

some more debugging

2026-02-17 21:17:28.753 UTC [52868] - medusa - LOG:  statement: select "a0"."id", "a0"."token", "a0"."revoked_at" from "api_key" as "a0" where "a0"."deleted_at" is null and "a0"."token" = 'pk_xxxx' and "a0"."type" = 'publishable' order by "a0"."id" asc
2026-02-17 21:17:28.867 UTC [52868] - medusa - LOG:  statement: select "l0"."sales_channel_id", "l0"."publishable_key_id" from "publishable_api_key_sales_channel" as "l0" where "l0"."deleted_at" is null and "l0"."publishable_key_id" in ('apk_01KHPGJ8GE55F2R11WJ3WNZMMD')
2026-02-17 21:17:28.920 UTC [52868] - medusa - LOG:  statement: select count(*) as "count" from "sales_channel" as "s0" where "s0"."deleted_at" is null
2026-02-17 21:17:28.921 UTC [52561] - medusa - LOG:  statement: select "s0"."id" from "sales_channel" as "s0" where "s0"."deleted_at" is null order by "s0"."id" asc limit 1
2026-02-17 21:17:28.977 UTC [52868] - medusa - LOG:  statement: select "p0"."id", "p0"."title", "p0"."subtitle", "p0"."description", "p0"."handle", "p0"."is_giftcard", "p0"."discountable", "p0"."thumbnail", "p0"."collection_id", "p0"."type_id", "p0"."weight", "p0"."length", "p0"."height", "p0"."width", "p0"."hs_code", "p0"."origin_country", "p0"."mid_code", "p0"."material", "p0"."created_at", "p0"."updated_at", "p0"."type_id" as "type_id", "p0"."collection_id" as "collection_id" from "product" as "p0" left join "image" as "p1" on "p0"."id" = "p1"."product_id" where "p0"."id" in (select "p0"."id" from (select "p0"."id" from "product" as "p0" left join "image" as "p1" on "p0"."id" = "p1"."product_id" where "p0"."deleted_at" is null and "p0"."status" = 'published' group by "p0"."id" order by min("p0"."id") asc, min("p1"."rank") asc limit 1) as "p0") order by "p0"."id" asc, "p1"."rank" asc

i believe this proves this is a bug as select "s0"."id" from "sales_channel" as "s0" where "s0"."deleted_at" is null order by "s0"."id" asc limit 1 select the first SC but is not passed to the subsequent query.