Understanding SKUs

Products in the CannMenus API are organized by SKU (Stock Keeping Unit) to consolidate listings from multiple sources. This structure makes it easy to compare prices and availability for the same product across platforms.


Data Structure

The API organizes product data in a three-level hierarchy:

Response
├── Retailer (dispensary)
│   ├── SKU Group (unique product variant)
│   │   ├── Product listing (from Dutchie)
│   │   ├── Product listing (from Leafly)
│   │   └── Product listing (from Weedmaps)
│   └── SKU Group
│       └── Product listing
└── Retailer
    └── SKU Group
        └── Product listing
LevelDescription
RetailerA unique dispensary, identified by retailer_id
SKU GroupA unique product variant at that retailer, identified by sku
Product ListingIndividual listing from a menu provider

What is a SKU?

A SKU uniquely identifies a specific product variant within a dispensary. For example, if a dispensary sells "Blue Dream" flower in 1g, 3.5g, and 7g sizes, each size is a separate SKU.

Same Product, Different Platforms

Many dispensaries list products on multiple platforms (Dutchie, Leafly, Weedmaps, etc.). The API groups these listings under a single SKU:

{
  "retailer_id": "10600",
  "sku": "07A0Sbb8OieeaR8rIW6MVHRw",
  "products": [
    {
      "cann_sku_id": "07A0Sbb8OieeaR8rIW6MVHRw",
      "product_name": "Blue Dream",
      "display_weight": "3.5g",
      "latest_price": 45.00,
      "menu_provider": "Dutchie"
    },
    {
      "cann_sku_id": "07A0Sbb8OieeaR8rIW6MVHRw",
      "product_name": "Blue Dream",
      "display_weight": "3.5g",
      "latest_price": 48.00,
      "menu_provider": "Leafly"
    }
  ]
}

This lets you compare pricing across platforms for the exact same product at the exact same retailer.


Benefits of SKU Grouping

1. Price Comparison

Compare the same product across menu providers:

for sku_group in response["data"]:
    prices = [p["latest_price"] for p in sku_group["products"]]
    product_name = sku_group["products"][0]["product_name"]
    print(f"{product_name}: ${min(prices)} - ${max(prices)}")

2. No Duplicates

Without SKU grouping, the same product would appear multiple times (once per platform). SKUs consolidate these into a single entry.

3. Accurate Inventory View

The products array shows every platform where the product is listed, giving you a complete picture of its availability.

4. Consistent Identification

Even when platforms use different naming (e.g., "Blue Dream 3.5g" vs "Blue Dream - Flower - 1/8 oz"), the SKU ensures you're looking at the same product.


Full Response Example

{
  "data": [
    {
      "retailer_id": "10600",
      "sku": "07A0Sbb8OieeaR8rIW6MVHRw",
      "products": [
        {
          "cann_sku_id": "07A0Sbb8OieeaR8rIW6MVHRw",
          "brand_name": "93 Boyz",
          "brand_id": 25407,
          "raw_product_name": "Aeriz - 93 Boyz Kept Secret 3.5g",
          "product_name": "Aeriz Kept Secret",
          "raw_weight_string": "3.5g",
          "display_weight": "3.5g",
          "raw_product_category": "Flower",
          "category": "Flower",
          "raw_subcategory": "Flower",
          "subcategory": null,
          "product_tags": null,
          "percentage_thc": null,
          "percentage_cbd": null,
          "mg_thc": null,
          "mg_cbd": null,
          "quantity_per_package": 1,
          "medical": false,
          "recreational": true,
          "latest_price": 59.04,
          "menu_provider": "Leafly"
        }
      ]
    },
    {
      "retailer_id": "14583",
      "sku": "07sDygynAUjkxftzxSnk8Cq8",
      "products": [
        {
          "cann_sku_id": "07sDygynAUjkxftzxSnk8Cq8",
          "brand_name": "RYTHM",
          "brand_id": 5163,
          "raw_product_name": "Rythm Jet Fuel OG 3.5g | Flower",
          "product_name": "Jet Fuel Og",
          "raw_weight_string": "3.5g",
          "display_weight": "3.5g",
          "raw_product_category": "Flower",
          "category": "Flower",
          "raw_subcategory": "small-buds",
          "subcategory": "Popcorn",
          "product_tags": null,
          "percentage_thc": null,
          "percentage_cbd": null,
          "mg_thc": null,
          "mg_cbd": null,
          "quantity_per_package": null,
          "medical": false,
          "recreational": true,
          "latest_price": 55.0,
          "menu_provider": "Dutchie"
        }
      ]
    }
  ],
  "pagination": {
    "total_records": 2,
    "current_page": 1,
    "total_pages": 1,
    "next_page": null,
    "prev_page": null
  }
}

Working with SKUs

Flatten Products for Analysis

# Convert nested structure to flat list
all_products = []
for sku_group in response["data"]:
    for product in sku_group["products"]:
        product["retailer_id"] = sku_group["retailer_id"]
        product["sku"] = sku_group["sku"]
        all_products.append(product)

# Now analyze as flat DataFrame
import pandas as pd
df = pd.DataFrame(all_products)

Find Best Price per SKU

for sku_group in response["data"]:
    best = min(sku_group["products"], key=lambda p: p["latest_price"])
    print(f"{best['product_name']}: ${best['latest_price']} on {best['menu_provider']}")

Current Limitations

This means:

  • Use SKUs to compare listings within a single retailer
  • To find the same product across retailers, use brand_name + product_name filters