# Analytics V2 API Examples ## Overview All endpoints are prefixed with `/api/analytics/v2` ### Filtering Options **Time Windows:** - `?window=7d` - Last 7 days - `?window=30d` - Last 30 days (default) - `?window=90d` - Last 90 days **Legal Type Filtering:** - `?legalType=recreational` - Recreational states only - `?legalType=medical_only` - Medical-only states (not recreational) - `?legalType=no_program` - States with no cannabis program --- ## 1. Price Analytics ### GET /price/product/:id Get price trends for a specific store product. **Request:** ```bash GET /api/analytics/v2/price/product/12345?window=30d ``` **Response:** ```json { "store_product_id": 12345, "product_name": "Blue Dream 3.5g", "brand_name": "Cookies", "category": "Flower", "dispensary_id": 101, "dispensary_name": "Green Leaf Dispensary", "state_code": "AZ", "data_points": [ { "date": "2024-11-06", "price_rec": 45.00, "price_med": 40.00, "price_rec_special": null, "price_med_special": null, "is_on_special": false }, { "date": "2024-11-07", "price_rec": 42.00, "price_med": 38.00, "price_rec_special": null, "price_med_special": null, "is_on_special": false } ], "summary": { "current_price": 42.00, "min_price": 40.00, "max_price": 48.00, "avg_price": 43.50, "price_change_count": 3, "volatility_percent": 8.2 } } ``` ### GET /price/rec-vs-med Get recreational vs medical-only price comparison by category. **Request:** ```bash GET /api/analytics/v2/price/rec-vs-med?category=Flower ``` **Response:** ```json [ { "category": "Flower", "rec_avg": 38.50, "rec_median": 35.00, "med_avg": 42.00, "med_median": 40.00 }, { "category": "Concentrates", "rec_avg": 45.00, "rec_median": 42.00, "med_avg": 48.00, "med_median": 45.00 } ] ``` --- ## 2. Brand Analytics ### GET /brand/:name/penetration Get brand penetration metrics with state breakdown. **Request:** ```bash GET /api/analytics/v2/brand/Cookies/penetration?window=30d ``` **Response:** ```json { "brand_name": "Cookies", "total_dispensaries": 125, "total_skus": 450, "avg_skus_per_dispensary": 3.6, "states_present": ["AZ", "CA", "CO", "NV", "MI"], "state_breakdown": [ { "state_code": "CA", "state_name": "California", "legal_type": "recreational", "dispensary_count": 45, "sku_count": 180, "avg_skus_per_dispensary": 4.0, "market_share_percent": 12.5 }, { "state_code": "AZ", "state_name": "Arizona", "legal_type": "recreational", "dispensary_count": 32, "sku_count": 128, "avg_skus_per_dispensary": 4.0, "market_share_percent": 15.2 } ], "penetration_trend": [ { "date": "2024-11-01", "dispensary_count": 120, "new_dispensaries": 0, "dropped_dispensaries": 0 }, { "date": "2024-11-08", "dispensary_count": 123, "new_dispensaries": 3, "dropped_dispensaries": 0 }, { "date": "2024-11-15", "dispensary_count": 125, "new_dispensaries": 2, "dropped_dispensaries": 0 } ] } ``` ### GET /brand/:name/rec-vs-med Get brand presence in recreational vs medical-only states. **Request:** ```bash GET /api/analytics/v2/brand/Cookies/rec-vs-med ``` **Response:** ```json { "brand_name": "Cookies", "rec_states_count": 4, "rec_states": ["AZ", "CA", "CO", "NV"], "rec_dispensary_count": 110, "rec_avg_skus": 3.8, "med_only_states_count": 2, "med_only_states": ["FL", "OH"], "med_only_dispensary_count": 15, "med_only_avg_skus": 2.5 } ``` --- ## 3. Category Analytics ### GET /category/:name/growth Get category growth metrics with state breakdown. **Request:** ```bash GET /api/analytics/v2/category/Flower/growth?window=30d ``` **Response:** ```json { "category": "Flower", "current_sku_count": 5200, "current_dispensary_count": 320, "avg_price": 38.50, "growth_data": [ { "date": "2024-11-01", "sku_count": 4800, "dispensary_count": 310, "avg_price": 39.00 }, { "date": "2024-11-15", "sku_count": 5000, "dispensary_count": 315, "avg_price": 38.75 }, { "date": "2024-12-01", "sku_count": 5200, "dispensary_count": 320, "avg_price": 38.50 } ], "state_breakdown": [ { "state_code": "CA", "state_name": "California", "legal_type": "recreational", "sku_count": 2100, "dispensary_count": 145, "avg_price": 36.00 }, { "state_code": "AZ", "state_name": "Arizona", "legal_type": "recreational", "sku_count": 950, "dispensary_count": 85, "avg_price": 40.00 } ] } ``` ### GET /category/rec-vs-med Get category comparison between recreational and medical-only states. **Request:** ```bash GET /api/analytics/v2/category/rec-vs-med ``` **Response:** ```json [ { "category": "Flower", "recreational": { "state_count": 15, "dispensary_count": 650, "sku_count": 12500, "avg_price": 35.50, "median_price": 32.00 }, "medical_only": { "state_count": 8, "dispensary_count": 220, "sku_count": 4200, "avg_price": 42.00, "median_price": 40.00 }, "price_diff_percent": -15.48 }, { "category": "Concentrates", "recreational": { "state_count": 15, "dispensary_count": 600, "sku_count": 8500, "avg_price": 42.00, "median_price": 40.00 }, "medical_only": { "state_count": 8, "dispensary_count": 200, "sku_count": 3100, "avg_price": 48.00, "median_price": 45.00 }, "price_diff_percent": -12.50 } ] ``` --- ## 4. Store Analytics ### GET /store/:id/summary Get change summary for a store over a time window. **Request:** ```bash GET /api/analytics/v2/store/101/summary?window=30d ``` **Response:** ```json { "dispensary_id": 101, "dispensary_name": "Green Leaf Dispensary", "state_code": "AZ", "window": "30d", "products_added": 45, "products_dropped": 12, "brands_added": ["Alien Labs", "Connected"], "brands_dropped": ["House Brand"], "price_changes": 156, "avg_price_change_percent": 3.2, "stock_in_events": 89, "stock_out_events": 34, "current_product_count": 512, "current_in_stock_count": 478 } ``` ### GET /store/:id/events Get recent product change events for a store. **Request:** ```bash GET /api/analytics/v2/store/101/events?window=7d&limit=50 ``` **Response:** ```json [ { "store_product_id": 12345, "product_name": "Blue Dream 3.5g", "brand_name": "Cookies", "category": "Flower", "event_type": "price_change", "event_date": "2024-12-05T14:30:00.000Z", "old_value": "45.00", "new_value": "42.00" }, { "store_product_id": 12346, "product_name": "OG Kush 1g", "brand_name": "Alien Labs", "category": "Flower", "event_type": "added", "event_date": "2024-12-04T10:00:00.000Z", "old_value": null, "new_value": null }, { "store_product_id": 12300, "product_name": "Sour Diesel Cart", "brand_name": "Select", "category": "Vaporizers", "event_type": "stock_out", "event_date": "2024-12-03T16:45:00.000Z", "old_value": "true", "new_value": "false" } ] ``` --- ## 5. State Analytics ### GET /state/:code/summary Get market summary for a specific state with rec/med breakdown. **Request:** ```bash GET /api/analytics/v2/state/AZ/summary ``` **Response:** ```json { "state_code": "AZ", "state_name": "Arizona", "legal_status": { "recreational_legal": true, "rec_year": 2020, "medical_legal": true, "med_year": 2010 }, "coverage": { "dispensary_count": 145, "product_count": 18500, "brand_count": 320, "category_count": 12, "snapshot_count": 2450000, "last_crawl_at": "2024-12-06T02:30:00.000Z" }, "pricing": { "avg_price": 42.50, "median_price": 38.00, "min_price": 5.00, "max_price": 250.00 }, "top_categories": [ { "category": "Flower", "count": 5200 }, { "category": "Concentrates", "count": 3800 }, { "category": "Vaporizers", "count": 2950 }, { "category": "Edibles", "count": 2400 }, { "category": "Pre-Rolls", "count": 1850 } ], "top_brands": [ { "brand": "Cookies", "count": 450 }, { "brand": "Alien Labs", "count": 380 }, { "brand": "Connected", "count": 320 }, { "brand": "Stiiizy", "count": 290 }, { "brand": "Raw Garden", "count": 275 } ] } ``` ### GET /state/legal-breakdown Get breakdown by legal status (recreational, medical-only, no program). **Request:** ```bash GET /api/analytics/v2/state/legal-breakdown ``` **Response:** ```json { "recreational_states": { "count": 24, "dispensary_count": 850, "product_count": 125000, "snapshot_count": 15000000, "states": [ { "code": "CA", "name": "California", "dispensary_count": 250 }, { "code": "CO", "name": "Colorado", "dispensary_count": 150 }, { "code": "AZ", "name": "Arizona", "dispensary_count": 145 }, { "code": "MI", "name": "Michigan", "dispensary_count": 120 } ] }, "medical_only_states": { "count": 18, "dispensary_count": 320, "product_count": 45000, "snapshot_count": 5000000, "states": [ { "code": "FL", "name": "Florida", "dispensary_count": 120 }, { "code": "OH", "name": "Ohio", "dispensary_count": 85 }, { "code": "PA", "name": "Pennsylvania", "dispensary_count": 75 } ] }, "no_program_states": { "count": 9, "states": [ { "code": "ID", "name": "Idaho" }, { "code": "WY", "name": "Wyoming" }, { "code": "KS", "name": "Kansas" } ] } } ``` ### GET /state/recreational Get list of recreational state codes. **Request:** ```bash GET /api/analytics/v2/state/recreational ``` **Response:** ```json { "legal_type": "recreational", "states": ["AK", "AZ", "CA", "CO", "CT", "DE", "IL", "MA", "MD", "ME", "MI", "MN", "MO", "MT", "NJ", "NM", "NV", "NY", "OH", "OR", "RI", "VA", "VT", "WA"], "count": 24 } ``` ### GET /state/medical-only Get list of medical-only state codes (not recreational). **Request:** ```bash GET /api/analytics/v2/state/medical-only ``` **Response:** ```json { "legal_type": "medical_only", "states": ["AR", "FL", "HI", "LA", "MS", "ND", "NH", "OK", "PA", "SD", "UT", "WV"], "count": 12 } ``` ### GET /state/rec-vs-med-pricing Get rec vs med price comparison by category. **Request:** ```bash GET /api/analytics/v2/state/rec-vs-med-pricing?category=Flower ``` **Response:** ```json [ { "category": "Flower", "recreational": { "state_count": 15, "product_count": 12500, "avg_price": 35.50, "median_price": 32.00 }, "medical_only": { "state_count": 8, "product_count": 5200, "avg_price": 42.00, "median_price": 40.00 }, "price_diff_percent": -15.48 } ] ``` --- ## How These Endpoints Support Portals ### Brand Portal Use Cases 1. **Track brand penetration**: Use `/brand/:name/penetration` to see how many stores carry the brand 2. **Compare rec vs med markets**: Use `/brand/:name/rec-vs-med` to understand footprint by legal status 3. **Identify expansion opportunities**: Use `/state/coverage-gaps` to find underserved markets 4. **Monitor pricing**: Use `/price/brand/:brand` to track pricing by state ### Buyer Portal Use Cases 1. **Compare stores**: Use `/store/:id/summary` to see activity levels 2. **Track price changes**: Use `/store/:id/events` to monitor competitor pricing 3. **Analyze categories**: Use `/category/:name/growth` to identify trending products 4. **State-level insights**: Use `/state/:code/summary` for market overview --- ## Time Window Filtering All time-based endpoints support the `window` query parameter: | Value | Description | |-------|-------------| | `7d` | Last 7 days | | `30d` | Last 30 days (default) | | `90d` | Last 90 days | The window affects: - `store_product_snapshots.captured_at` for historical data - `store_products.first_seen_at` / `last_seen_at` for product lifecycle - `crawl_runs.started_at` for crawl-based metrics --- ## Rec/Med Segmentation All state-level endpoints automatically segment by: - **Recreational**: `states.recreational_legal = TRUE` - **Medical-only**: `states.medical_legal = TRUE AND states.recreational_legal = FALSE` - **No program**: Both flags are FALSE or NULL This segmentation appears in: - `legal_type` field in responses - State breakdown arrays - Price comparison endpoints