Skip to main content

Products API

All endpoints are under /api/v1/{platform}/products where platform is shopify or bigcommerce.

List products

GET /api/v1/shopify/products?limit=50&offset=0&storeId=...
Authorization: Bearer sk_live_...
X-Tenant-Id: <tenant-id>

Response:

{
"products": [
{
"id": "...",
"title": "...",
"vendor": "...",
"price": 29.99,
"currency": "EUR",
"identity": "...",
"enrichment_status": "enriched",
"manually_edited": false,
"last_enriched_at": "2026-04-14T...",
"url": "/api/shopify/products/...",
"llm_url": "/api/shopify/products/...llm"
}
],
"total": 281,
"pagination": { "limit": 50, "offset": 0, "count": 50, "has_more": true }
}

Get one product (full semantic payload)

GET /api/v1/shopify/products/:id

Returns the full SemanticProduct with core_identity, reasoning, synthetic_properties, technical_details, metadata.

LLM-optimized variant

GET /api/v1/shopify/products/:id.llm

Returns a condensed JSON tuned for LLM consumption — identity, reasoning, quality_scores, pricing, market_context, plus a pre-computed summary_for_ai string.

JSON-LD (schema.org/Product)

GET /api/v1/shopify/products/:id.jsonld

Returns application/ld+json with @type: Product, offers, brand, and scores mapped to additionalProperty[] as PropertyValue. If FAQ entries exist for the product, bundles Product + FAQPage into a single @graph array. Crawler-ready.

Markdown (text/markdown)

GET /api/v1/shopify/products/:id.md

Returns text/markdown; charset=utf-8 with a structured Markdown document: title, core identity, product details, quality scores table, buying guide, market context, search keywords, and images. Addresses the Cloudflare agent-readiness metric for LLM discoverability.

SEO meta signals

GET /api/v1/shopify/products/:id.meta

Returns SEO signals in 3 description lengths (≤160 chars, ≤300, unlimited) + canonical URL + keywords + links object pointing to all other signal formats (.jsonld, .llm, .md, self).


Signal endpoints for ALL entity types

Every entity type (products, collections, categories, pages) exposes the same four signal format endpoints. The contract is identical — only the base path changes.

Base paths

PlatformEntityBase path
ShopifyProducts/api/v1/shopify/products
ShopifyCollections/api/v1/shopify/collections
ShopifyPages/api/v1/shopify/pages
BigCommerceProducts/api/v1/bigcommerce/products
BigCommerceCategories/api/v1/bigcommerce/categories
BigCommercePages/api/v1/bigcommerce/pages

Signal formats (available on ALL entities)

SuffixContent-TypeDescription
/:id.jsonldapplication/ld+jsonSchema.org JSON-LD. Bundles entity schema + FAQPage in @graph if FAQ entries exist.
/:id.llmapplication/jsonLLM-optimized representation with identity, context, keywords, enrichment data.
/:id.mdtext/markdown; charset=utf-8Structured Markdown for LLM crawlers. Cloudflare agent-readiness metric.
/:id.metaapplication/jsonAll SEO signals: meta title, description, keywords, OG tags, + links to all other formats.

Examples

# Collection JSON-LD (Shopify)
GET /api/v1/shopify/collections/summer-2026.jsonld

# Category Markdown (BigCommerce)
GET /api/v1/bigcommerce/categories/spray-bottles.md

# Page meta signals (both platforms)
GET /api/v1/shopify/pages/about-us.meta
GET /api/v1/bigcommerce/pages/shipping-policy.meta

.meta response shape (all entities)

{
"collection_id": "summer-2026",
"meta_title": "Summer 2026 | Store Name",
"meta_description": "AI-enriched description...",
"keywords": ["summer", "collection", "2026"],
"og": {
"og_title": "...",
"og_description": "...",
"og_type": "website",
"og_image": { "url": "...", "alt": "..." },
"og_url": "...",
"og_site_name": "..."
},
"links": {
"jsonld": "/api/v1/shopify/collections/summer-2026.jsonld",
"llm": "/api/v1/shopify/collections/summer-2026.llm",
"md": "/api/v1/shopify/collections/summer-2026.md",
"self": "/api/v1/shopify/collections/summer-2026"
}
}

Re-enrich a single product

POST /api/v1/shopify/enrich/:id
Authorization: Bearer <JWT>
Content-Type: application/json

{
"hints": {
"target_audience": "...",
"material_composition": "..."
}
}

Hints are optional; they're the same fields the Enrichment Wizard collects.

Bulk re-enrich

POST /api/v1/shopify/enrich/all?pending=true&storeId=<storeId>

pending=true only re-enriches products flagged enrichment_pending. Without it, re-enriches every product in the tenant (dangerous — use the dashboard's two-step confirm).

Versions + rollback

GET  /api/v1/shopify/enrich/:id/versions                 → list past versions
POST /api/v1/shopify/enrich/:id/rollback?version=N → restore version N

The rollback itself creates a new version snapshot so it's reversible.

Update a product's enrichment manually

PATCH /api/v1/shopify/products/:id        # also available on /bigcommerce/
{
"core_identity": "...",
"reasoning": { ... },
"synthetic_properties": {
"durability_score": 8,
"competitors_owner_provided": [
{ "brand": "Nike", "model": "Air Max 90", "ref_price": "€120", "notes": "direct competitor" }
]
}
}

Whitelisted top-level fields: core_identity, reasoning, synthetic_properties. Flags the product with:

  • metadata.manually_edited = true — future re-enrichments show an OVERWRITE two-step confirm in the dashboard
  • metadata.competitors_source = 'owner' — only when synthetic_properties.competitors_owner_provided is a non-empty array. Sets authority on the competitors list so re-enrichment won't regenerate it.

Update category / collection metadata

PATCH /api/v1/shopify/collections/:id      # Shopify → "collections"
PATCH /api/v1/bigcommerce/categories/:id # BigCommerce → "categories"

Whitelisted fields for bulk-editing SEO metadata:

{
"name": "...",
"description": "...",
"slug": "...",
"imageUrl": "https://...",
"metaTitle": "...",
"metaDescription": "..."
}

Tenant-scoped — the request's tenant must own the entity or the endpoint returns 404. Empty string values are coerced to null. Returns the updated row.

Verify storefront — per-product diff

GET /api/v1/shopify/diff/:id?store_url=https://yourstore.com

Fetches your live storefront and compares every signal Clione propagated (meta_description, meta_title, jsonld, canonical, meta_keywords) against what the HTML actually contains right now.

Per-signal statuses: identical | different | missing_in_storefront | never_propagated | propagation_failed | parse_error.

Response includes a summary (match_rate excludes never_propagated), a per-signal diff, and — for JSON-LD — a structural breakdown of added/removed/changed keys.

Side effect: refreshes verifiedAt + verifiedPresent on the underlying PropagationRecords.

Verify storefront — batch

GET /api/v1/shopify/diff?store_url=https://yourstore.com&product_ids=id1,id2,id3

Same contract as /diff/:id but across an array of products. Aggregates totals across all products + returns per-product results under results[]. One slow product won't kill the batch — failures come back as { entity_id, error, summary: null }.

Used by the dashboard's Verify storefront button on the store overview page. Hard-capped to ~50 products per call in the UI to keep response time manageable.