LIVE
Cloudline entered Cactus Co Phoenix +12 SKUs / Cedarline lost Red Rock Tempe −8 SKUs / Emberton entered Prairie Buds Calgary +9 doors / Northstar price drop Bell Road Phoenix $45→$38 / Maplecross entered Lakeshore Toronto +14 SKUs / Voltleaf lost Mesa Verde Mesa −4 SKUs / Wildcraft entered Northern Leaf Edmonton +7 SKUs / Ninebar BOGO activated Desert Bloom Promo live / Wildroot entered Washington market +22 doors / Nova Labs Engine Win — Saguaro Wellness PHX +18 doors / Cloudline entered Cactus Co Phoenix +12 SKUs / Cedarline lost Red Rock Tempe −8 SKUs / Emberton entered Prairie Buds Calgary +9 doors / Northstar price drop Bell Road Phoenix $45→$38 / Maplecross entered Lakeshore Toronto +14 SKUs / Voltleaf lost Mesa Verde Mesa −4 SKUs / Wildcraft entered Northern Leaf Edmonton +7 SKUs / Ninebar BOGO activated Desert Bloom Promo live / Wildroot entered Washington market +22 doors / Nova Labs Engine Win — Saguaro Wellness PHX +18 doors /

Shelf Data API

Every dispensary shelf, as structured data.

Query who carries what, where, at what price, in stock or not — and what changed — across the cannabis retail market. A clean, read-only REST API over the same shelf intelligence that powers the CannaiQ dashboards. Build it into your own app, model, or warehouse.

10,000+dispensaries observed
56markets · US · CA · PR
18,000+brands tracked
7M+SKUs observed
< 1 hrrefresh on live stores

Six things you can pull

Six resources, each at a defined grain. Filter, combine, and expand them into the exact slice you need.

Brands

brand × market

Distribution, doors carried, coverage, category mix, and the SKUs a brand has on shelf.

Stores

dispensary

Store directory, location, platform, and the brands and full menu each store carries right now.

Products

product family

Canonical product families deduped across stores — one identity per real product.

SKUs

sellable variant

Variant-level catalog — weight, dose, strain, format — and every store carrying each SKU.

Inventory

SKU × store, latest read

In-stock / out-of-stock and quantity from the most recent shelf read. Plus what just left the shelf.

Signals

change event, windowed

New placements, lost placements, price moves, category trends, and movement direction over time.

Every number carries its receipts

No bare numbers. Each value ships with where it came from and when we last saw it — so you always know whether you're reading a measured fact or a modeled estimate.

observed

Read directly from a shelf: presence, price, promotions, stock, door counts. A measured fact.

inferred

Computed from change between shelf reads: movement, velocity, trends. Always directional, always a lower bound — labeled as such.

confirmed

Observed data upgraded by a brand's own catalog verification. The highest-confidence tier.

The endpoints

A deliberately lean REST surface — depth comes from query flexibility, not endpoint sprawl.

Brands
  • GET /data/v1/brands
  • GET /data/v1/brands/{id}
  • GET /data/v1/brands/{id}/stores
  • GET /data/v1/brands/{id}/skus
  • GET /data/v1/brands/{id}/coverage
  • GET /data/v1/brands/{id}/categories
Stores
  • GET /data/v1/stores
  • GET /data/v1/stores/{id}
  • GET /data/v1/stores/{id}/brands
  • GET /data/v1/stores/{id}/menu
  • GET /data/v1/stores/{id}/categories
Products & SKUs
  • GET /data/v1/products
  • GET /data/v1/products/{id}
  • GET /data/v1/skus
  • GET /data/v1/skus/{id}
  • GET /data/v1/skus/{id}/shelf
Inventory
  • GET /data/v1/inventory/stock
  • GET /data/v1/inventory/oos
  • GET /data/v1/inventory/delisted
Pricing
  • GET /data/v1/pricing/skus
  • GET /data/v1/pricing/ladder
  • GET /data/v1/pricing/market
Signals
  • GET /data/v1/signals/new-placements
  • GET /data/v1/signals/lost-placements
  • GET /data/v1/signals/price-changes
  • GET /data/v1/signals/velocity
  • GET /data/v1/signals/category-trends

One predictable shape

Every response returns data, a meta block with provenance, timestamp, grain, and coverage, and a page block for pagination. Inventory is always the latest shelf read; trends are windowed and labeled.

  • SKU counts are distinct SKUs — never inflated by store-by-store listings.
  • Inventory is point-in-time — the most recent read, not a rolling average.
  • Trends grow with history — windowed signals are honest lower bounds.
{
  "data": [
    {
      "sku_id": "…",
      "name": "Green Apple Pocket Spritz 100mg",
      "brand": "Boho Euphorics",
      "format": "beverage",
      "store_id": 2498,
      "store_name": "Authorized Dealer (Willingboro)",
      "city": "Willingboro",
      "state": "NJ",
      "in_stock": false,
      "list_price": 24.00,
      "last_seen_at": "2026-06-23T14:02:00Z"
    }
  ],
  "meta": {
    "as_of": "2026-06-23T14:02:00Z",
    "provenance": "observed",
    "grain": "placement",
    "window": "snapshot",
    "coverage": { "states": ["NJ"], "confidence": "high" }
  },
  "page": { "limit": 100, "offset": 0, "total": 1 }
}

Slice it your way

Every list endpoint speaks one query grammar — so you compose the view you need without us pre-building it.

Filter

Combine market, brand, category, platform, price range, stock status, and "changed since" — e.g. ?state=NJ&category=flower&price[gte]=20&price[lte]=40&in_stock=true.

Select fields

Return only the fields you want with ?fields= — smaller, faster, cheaper payloads.

Sort & page

Sort on any indexed field (?sort=-doors), page with limit/offset or cursors for large pulls.

Expand

Walk relationships inline — a SKU to every store carrying it, a brand to its full catalog — in one request with ?expand=.

Bulk export

Enterprise plans can export any resource as Parquet or JSONL, scoped to your markets, to load into your own warehouse.

Scoped & metered

Keys are scoped to your markets and resources, rate-limited, and metered per call — predictable and auditable.

We never sell a number we can't see.

Everything in the API is derived from observed dispensary shelves — not modeled point-of-sale figures, not foot-traffic estimates, not survey panels. We don't fabricate retail sales, basket data, or anything we can't actually observe. Where a value is an estimate, it says so, in the data. That honesty is the product.

Build on the shelf.

Tell us your markets and use case and we'll scope an API plan to fit. Already using CannaiQ for brands or retailers? The API is the same data, programmatic.