Normalization API

Send raw POS product data from any dispensary menu system and receive enriched, standardized product records using CANN's normalization pipeline.


What It Does

You send raw product data from any POS or menu system, and we return:

Category & Subcategory

Raw product types mapped to CANN's canonical taxonomy — 9 categories, 100+ subcategories.

Brand Matching

Fuzzy-matched against CANN's database of 10,000+ cannabis brands with confidence scores.

Potency & Weight

THC/CBD percentages and milligrams extracted. Weights normalized to grams from any format.

UUID/SKU Matching

Cross-referenced against CANN's existing product database for identity resolution.


Two Ways to Use It

Batch API (synchronous)

Send up to 500 products per request and get results immediately:

POST /v1/normalize/batch

Best for: Real-time integrations, small-to-medium datasets, testing.

File Upload (asynchronous)

Upload a CSV or JSON file (up to 50MB) and poll for results:

POST /v1/files/upload
GET  /v1/files/{job_id}/status
GET  /v1/files/{job_id}/results

Best for: Large menu exports, bulk processing, one-time migrations.


Quick Example

Normalize a single Dutchie product:

curl -X POST "https://api.cannmenus.com/v1/normalize/batch" \
  -H "X-Token: YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "dutchie",
    "products": [
      {
        "data": {
          "Name": "Happy Valley - Dog Patch - 3.5g",
          "type": "Flower",
          "THCContent": {"unit": "PERCENTAGE", "range": [24.0, 24.0]},
          "Prices": [52.00],
          "brand": "Happy Valley",
          "strainType": "Hybrid"
        },
        "state": "MA",
        "recreational": true
      }
    ],
    "match_existing": true
  }'

Example Response

{
  "provider": "dutchie",
  "total_input": 1,
  "total_output": 1,
  "total_matched": 1,
  "total_errors": 0,
  "processing_time_ms": 142.5,
  "products": [
    {
      "uuid": "a1b2c3d4-...",
      "sku": "XkR9mN2pQw7vL4bT",
      "match_tier": "secondary",
      "display_product_name": "Dog Patch",
      "raw_product_name": "Happy Valley - Dog Patch - 3.5g",
      "cann_product_category": "Flower",
      "display_strain_type": "Hybrid",
      "display_weight": "3.5g",
      "display_potency_list": ["24% THC"],
      "brand_name": "Happy Valley",
      "brand_fuzzy_match_score": 0.95,
      "total_weight_in_grams": 3.5,
      "current_price": 52.0,
      "state": "MA",
      "in_stock": true,
      "recreational": true
    }
  ],
  "errors": []
}

Supported POS Providers

We have dedicated normalizers for specific providers with full field mapping. For all other POS systems, use "provider": "generic".

ProviderIdentifierType
DutchiedutchieDedicated normalizer
Generic (any POS)genericHeuristic-based

Use the Providers endpoint to get the current list programmatically.


Authentication

All requests require the X-Token header — the same token you use for the CannMenus Partner API. See Authentication for details.

curl -X POST "https://api.cannmenus.com/v1/normalize/batch" \
  -H "X-Token: YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ ... }'

Getting Started

  1. Use your existing CannMenus API token (or contact us to get one)
  2. Start small — send 10-20 products to verify the output matches your expectations
  3. Enable matching — use "match_existing": true to get UUID/SKU cross-references
  4. Scale up — move to file uploads for larger datasets

API Reference

Full interactive API documentation is available at the Normalization API Redoc.


Next Steps