New endpoint: GET /api/analytics/v2/brand/:name/intelligence Returns comprehensive brand analytics payload including: - Performance snapshot (active SKUs, revenue, stores, market share) - Alerts (lost stores, delisted SKUs, competitor takeovers) - SKU performance (velocity, status, stock levels) - Retail footprint (penetration by region, whitespace opportunities) - Competitive landscape (price positioning, head-to-head comparisons) - Inventory health (days of stock, risk levels, overstock alerts) - Promotion effectiveness (baseline vs promo velocity, lift, ROI) Supports time windows (7d/30d/90d), state filtering, and category filtering. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
10 KiB
10 KiB
Brand Intelligence API
Endpoint
GET /api/analytics/v2/brand/:name/intelligence
Query Parameters
| Param | Type | Default | Description |
|---|---|---|---|
window |
7d|30d|90d |
30d |
Time window for trend calculations |
state |
string | - | Filter by state code (e.g., AZ) |
category |
string | - | Filter by category (e.g., Flower) |
Response Payload Schema
interface BrandIntelligenceResult {
brand_name: string;
window: '7d' | '30d' | '90d';
generated_at: string; // ISO timestamp when data was computed
performance_snapshot: PerformanceSnapshot;
alerts: Alerts;
sku_performance: SkuPerformance[];
retail_footprint: RetailFootprint;
competitive_landscape: CompetitiveLandscape;
inventory_health: InventoryHealth;
promo_performance: PromoPerformance;
}
Section 1: Performance Snapshot
Summary cards with key brand metrics.
interface PerformanceSnapshot {
active_skus: number; // Total products in catalog
total_revenue_30d: number | null; // Estimated from qty × price
total_stores: number; // Active retail partners
new_stores_30d: number; // New distribution in window
market_share: number | null; // % of category SKUs
avg_wholesale_price: number | null;
price_position: 'premium' | 'value' | 'competitive';
}
UI Label Mapping:
| Field | User-Facing Label | Helper Text |
|---|---|---|
active_skus |
Active Products | X total in catalog |
total_revenue_30d |
Monthly Revenue | Estimated from sales |
total_stores |
Retail Distribution | Active retail partners |
new_stores_30d |
New Opportunities | X new in last 30 days |
market_share |
Category Position | % of category |
avg_wholesale_price |
Avg Wholesale | Per unit |
price_position |
Pricing Tier | Premium/Value/Market Rate |
Section 2: Alerts
Issues requiring attention.
interface Alerts {
lost_stores_30d_count: number;
lost_skus_30d_count: number;
competitor_takeover_count: number;
avg_oos_duration_days: number | null;
avg_reorder_lag_days: number | null;
items: AlertItem[];
}
interface AlertItem {
type: 'lost_store' | 'delisted_sku' | 'shelf_loss' | 'extended_oos';
severity: 'critical' | 'warning';
store_name?: string;
product_name?: string;
competitor_brand?: string;
days_since?: number;
state_code?: string;
}
UI Label Mapping:
| Field | User-Facing Label |
|---|---|
lost_stores_30d_count |
Accounts at Risk |
lost_skus_30d_count |
Delisted SKUs |
competitor_takeover_count |
Shelf Losses |
avg_oos_duration_days |
Avg Stockout Length |
avg_reorder_lag_days |
Avg Restock Time |
severity: critical |
Urgent |
severity: warning |
Watch |
Section 3: SKU Performance (Product Velocity)
How fast each SKU sells.
interface SkuPerformance {
store_product_id: number;
product_name: string;
category: string | null;
daily_velocity: number; // Units/day estimate
velocity_status: 'hot' | 'steady' | 'slow' | 'stale';
retail_price: number | null;
on_sale: boolean;
stores_carrying: number;
stock_status: 'in_stock' | 'low_stock' | 'out_of_stock';
}
UI Label Mapping:
| Field | User-Facing Label |
|---|---|
daily_velocity |
Daily Rate |
velocity_status |
Momentum |
velocity_status: hot |
Hot |
velocity_status: steady |
Steady |
velocity_status: slow |
Slow |
velocity_status: stale |
Stale |
retail_price |
Retail Price |
on_sale |
Promo (badge) |
Velocity Thresholds:
hot: >= 5 units/daysteady: >= 1 unit/dayslow: >= 0.1 units/daystale: < 0.1 units/day
Section 4: Retail Footprint
Store placement and coverage.
interface RetailFootprint {
total_stores: number;
in_stock_count: number;
out_of_stock_count: number;
penetration_by_region: RegionPenetration[];
whitespace_stores: WhitespaceStore[];
}
interface RegionPenetration {
state_code: string;
store_count: number;
percent_reached: number; // % of state's dispensaries
in_stock: number;
out_of_stock: number;
}
interface WhitespaceStore {
store_id: number;
store_name: string;
state_code: string;
city: string | null;
category_fit: number; // How many competing brands they carry
competitor_brands: string[];
}
UI Label Mapping:
| Field | User-Facing Label |
|---|---|
penetration_by_region |
Market Coverage by Region |
percent_reached |
X% reached |
in_stock |
X stocked |
out_of_stock |
X out |
whitespace_stores |
Expansion Opportunities |
category_fit |
X fit |
Section 5: Competitive Landscape
Market positioning vs competitors.
interface CompetitiveLandscape {
brand_price_position: 'premium' | 'value' | 'competitive';
market_share_trend: MarketSharePoint[];
competitors: Competitor[];
head_to_head_skus: HeadToHead[];
}
interface MarketSharePoint {
date: string;
share_percent: number;
}
interface Competitor {
brand_name: string;
store_overlap_percent: number;
price_position: 'premium' | 'value' | 'competitive';
avg_price: number | null;
sku_count: number;
}
interface HeadToHead {
product_name: string;
brand_price: number;
competitor_brand: string;
competitor_price: number;
price_diff_percent: number;
}
UI Label Mapping:
| Field | User-Facing Label |
|---|---|
price_position: premium |
Premium Tier |
price_position: value |
Value Leader |
price_position: competitive |
Market Rate |
market_share_trend |
Share of Shelf Trend |
head_to_head_skus |
Price Comparison |
store_overlap_percent |
X% store overlap |
Section 6: Inventory Health
Stock projections and risk levels.
interface InventoryHealth {
critical_count: number; // <7 days stock
warning_count: number; // 7-14 days stock
healthy_count: number; // 14-90 days stock
overstocked_count: number; // >90 days stock
skus: InventorySku[];
overstock_alert: OverstockItem[];
}
interface InventorySku {
store_product_id: number;
product_name: string;
store_name: string;
days_of_stock: number | null;
risk_level: 'critical' | 'elevated' | 'moderate' | 'healthy';
current_quantity: number | null;
daily_sell_rate: number | null;
}
interface OverstockItem {
product_name: string;
store_name: string;
excess_units: number;
days_of_stock: number;
}
UI Label Mapping:
| Field | User-Facing Label |
|---|---|
risk_level: critical |
Reorder Now |
risk_level: elevated |
Low Stock |
risk_level: moderate |
Monitor |
risk_level: healthy |
Healthy |
critical_count |
Urgent (<7 days) |
warning_count |
Low (7-14 days) |
overstocked_count |
Excess (>90 days) |
days_of_stock |
X days remaining |
overstock_alert |
Overstock Alert |
excess_units |
X excess units |
Section 7: Promotion Effectiveness
How promotions impact sales.
interface PromoPerformance {
avg_baseline_velocity: number | null;
avg_promo_velocity: number | null;
avg_velocity_lift: number | null; // % increase during promo
avg_efficiency_score: number | null; // ROI proxy
promotions: Promotion[];
}
interface Promotion {
product_name: string;
store_name: string;
status: 'active' | 'scheduled' | 'ended';
start_date: string;
end_date: string | null;
regular_price: number;
promo_price: number;
discount_percent: number;
baseline_velocity: number | null;
promo_velocity: number | null;
velocity_lift: number | null;
efficiency_score: number | null;
}
UI Label Mapping:
| Field | User-Facing Label |
|---|---|
avg_baseline_velocity |
Normal Rate |
avg_promo_velocity |
During Promos |
avg_velocity_lift |
Avg Sales Lift |
avg_efficiency_score |
ROI Score |
velocity_lift |
Sales Lift |
efficiency_score |
ROI Score |
status: active |
Live |
status: scheduled |
Scheduled |
status: ended |
Ended |
Example Queries
Get full payload
const response = await fetch('/api/analytics/v2/brand/Wyld/intelligence?window=30d');
const data = await response.json();
Extract summary cards (flattened)
const { performance_snapshot: ps, alerts } = data;
const summaryCards = {
activeProducts: ps.active_skus,
monthlyRevenue: ps.total_revenue_30d,
retailDistribution: ps.total_stores,
newOpportunities: ps.new_stores_30d,
categoryPosition: ps.market_share,
avgWholesale: ps.avg_wholesale_price,
pricingTier: ps.price_position,
accountsAtRisk: alerts.lost_stores_30d_count,
delistedSkus: alerts.lost_skus_30d_count,
shelfLosses: alerts.competitor_takeover_count,
};
Get top 10 fastest selling SKUs
const topSkus = data.sku_performance
.filter(sku => sku.velocity_status === 'hot' || sku.velocity_status === 'steady')
.sort((a, b) => b.daily_velocity - a.daily_velocity)
.slice(0, 10);
Get critical inventory alerts only
const criticalInventory = data.inventory_health.skus
.filter(sku => sku.risk_level === 'critical');
Get states with <50% penetration
const underPenetrated = data.retail_footprint.penetration_by_region
.filter(region => region.percent_reached < 50)
.sort((a, b) => a.percent_reached - b.percent_reached);
Get active promotions with positive lift
const effectivePromos = data.promo_performance.promotions
.filter(p => p.status === 'active' && p.velocity_lift > 0)
.sort((a, b) => b.velocity_lift - a.velocity_lift);
Build chart data for market share trend
const chartData = data.competitive_landscape.market_share_trend.map(point => ({
x: new Date(point.date),
y: point.share_percent,
}));
Notes for Frontend Implementation
- All fields are snake_case - transform to camelCase if needed
- Null values are possible - handle gracefully in UI
- Arrays may be empty - show appropriate empty states
- Timestamps are ISO format - parse with
new Date() - Percentages are already computed - no need to multiply by 100
- The
windowparameter affects trend calculations - 7d/30d/90d