Product catalog
Applies to @snowcone-app/sdk@0.17.0
Read a product
The catalog is a standard Meilisearch index. Every product has a code — its id field, the same code you put in a mockup or buy URL — so you fetch it directly by code. The read key is the public, read-only search key — safe to ship in client code, like your Shop ID. This is the supported public catalog path, not an implementation detail: the index name, the key, and the product shape below are the same contract the SDK ships types for (CatalogProduct). Products you can’t render yet have an empty mockups — filter them out with "filter": "mockups IS NOT EMPTY" (the SDK’s listProducts() does this for you).
curl https://search.snowcone.app/indexes/snowcone/documents/BEEB77 \
-H "Authorization: Bearer eee819b849798ad9091228c486ec05d0931e5292"const res = await fetch(
"https://search.snowcone.app/indexes/snowcone/documents/BEEB77",
{ headers: { Authorization: "Bearer eee819b849798ad9091228c486ec05d0931e5292" } },
);
const product = await res.json();import { getProduct, listProducts } from "@snowcone-app/sdk";
const product = await getProduct("BEEB77"); // one product by code
const { items } = await listProducts(); // browse the whole catalogimport requests
product = requests.get(
"https://search.snowcone.app/indexes/snowcone/documents/BEEB77",
headers={"Authorization": "Bearer eee819b849798ad9091228c486ec05d0931e5292"},
).json()search.snowcone.app host is a standard Meilisearch instance: an anonymous request returns 401 missing_authorization_header, and a shop API key or an sk_ secret key is not the catalog key — sending one returns 403 invalid_api_key. Use the public read key shown here, or skip keys entirely with the SDK’s getProduct() / listProducts() (it carries the public key for you).What a product holds
One record carries everything the rest of the docs build on: the price your margins start from, the placements you can print on, and the options and variants a shopper picks.
{
"id": "BEEB77", // the product code you put in a mockup or buy URL
"name": "Framed Canvas",
"description": "Gallery-quality framed print…",
"price": 2399, // MSRP in cents — your suggested retail
"mockups": [ // scene renders; mockups[].id is the opaque
{ "id": "FV1qjO", // mockupId for realtime — NOT a placement name
"gvids": ["Pv1sLC"] }, // the variants this scene photographs — a scene
{ "id": "liMnIy", // only renders variants listed in its gvids
"gvids": ["Pv1sLC"] }
],
"placements": [ // printable areas; match one by "label" (exact case)
{ "label": "Front", "key": "front", "type": "image", "width": 800, "height": 1000 }
],
"options": { // size / color / … → see Options
"attributes": {
"Size": { "choices": [{ "label": "5x7" }, { "label": "8x10" }] },
"Frame": { "choices": [{ "label": "Walnut", "hex": "#5b3d1d" }, { "label": "Oak", "hex": "#b0814d" }] }
},
"combinations": [ // each combination → the variantId you render/buy
{ "Size": "5x7", "Frame": "Walnut", "price": 2375, "variantId": "Pv1sLC" }
]
},
"variants": [ // resolved variants you can render or buy
{ "gvid": "Pv1sLC", "placements": [{ "label": "Front", "width": 800, "height": 1000 }] }
]
}label exactly as the catalog returns it — capitalized "Front", not "front" (that lowercase value is the separate key field). A mismatched name silently renders a blank placement. Likewise, mockups[].id values (e.g. FV1qjO) are opaque scene codes — pass those, not placement names, as mockupIds for realtime renders. Each scene also lists gvids — the variants it photographs. The default variant works everywhere, but if you force a specific variant=, pick a scene whose gvids include it (see realtime).price is in cents and is the MSRP — your suggested retail and your default cost. Turning it into profit is the Pricing & margins page.Search, facets, filters
Because it’s real Meilisearch, full-text search, faceting, and filtering come for free — we don’t reinvent them. Any Meilisearch client works, or hit the HTTP API directly.
curl https://search.snowcone.app/indexes/snowcone/search \
-H "Authorization: Bearer eee819b849798ad9091228c486ec05d0931e5292" \
-H "Content-Type: application/json" \
-d '{ "q": "canvas", "filter": "price < 3000", "limit": 12 }'Where it leads
Each field on a product opens onto its own concept:

