Any visitor request about a Wix Stores catalog or a purchase. Examples:
| Input | How to get it |
|---|---|
| Visitor token | STEP 1 (GenerateVisitorToken, or reuse one already in the conversation) |
Product id, slug, price range, stock status, options | STEP 2 (POST /stores/v3/products/query or /search) |
Category id (only for "show me the X category") | STEP 3 (POST /categories/v1/categories/query) |
variantId for the chosen size/colour/scent (mandatory for any product with options; use the single variant otherwise) | STEP 4 (POST /stores/v3/products/query-variants) |
Cart line ids (for quantity changes / removal) | STEP 5 response (cart.lineItems[].id) |
checkoutId | STEP 7 (POST /ecom/v1/carts/current/create-checkout) |
name, plainDescription, option names. Offer to add to cart.inventory.availabilityStatus and compareAtPriceRange.variantId) → STEP 5 → STEP 6 (totals).ids from the last cart response./checkout?checkoutId= yourself (see Common errors #7).All calls below run with the visitor token through CallWixSiteAPI / ExecuteWixAPI. Prefer CallWixSiteAPI for any write whose failure you need to explain — ExecuteWixAPI currently hides the real HTTP error (see Common errors #1).
Call GenerateVisitorToken once and reuse the access_token for every step. The cart is owned by the visitor identity: a new token means an empty cart and a 404 OWNED_CART_NOT_FOUND on checkout.
POST https://www.wixapis.com/stores/v3/products/query
Filterable fields on this endpoint: id, slug, visible, handle, options.id, created/updated dates. name is not filterable — fetch up to 50–100 and match client-side. For one product by URL slug: "filter": { "slug": "breathing-cards" }.
actualPriceRange.minValue.formattedAmount (already in the site currency). If min ≠ max say "from …".compareAtPriceRange.minValue.amount > actualPriceRange.minValue.amount.inventory.availabilityStatus === "OUT_OF_STOCK" → say "sold out"; still list it.options[] tells you what the visitor must choose before STEP 5.POST https://www.wixapis.com/stores/v3/products/search — the only product endpoint that can filter by category (query rejects directCategoriesInfo).
Body is wrapped in search (a top-level filter is ignored). Operator is $matchItems with the key id; $hasSome is rejected. Response is { "products": [ … same shape as STEP 2 … ] }.
POST https://www.wixapis.com/categories/v1/categories/query
treeReference is top-level and mandatory. An empty filter is rejected (INVALID_FILTER), hence the $exists condition.{ "categories": [{ "id": "8f01c2bf-…", "name": "Wear", "slug": "wear", "visible": true }] }. Match the visitor's word to name client-side ("clothes" → Wear).POST https://www.wixapis.com/stores/v3/products/query-variants — not /stores/v3/variants/query (404).
Match the visitor's words to optionChoices[].optionChoiceNames.choiceName (case-insensitive, accept synonyms like "grey" for "Charcoal" only if you say so). A product without options has exactly one variant — use it. If the requested choice has inStock: false, offer the choices that are in stock.
POST https://www.wixapis.com/ecom/v1/carts/current/add-to-cart
Same call works for Restaurants dishes with the Orders app id — a visitor can hold shop and café items in one cart (verified: Flat White + planner, ₪105).
estimate-totals → { "cart": {…}, "priceSummary": { "subtotal": { "amount": "70.00", "formattedAmount": "₪70.00" }, "total": {…} } }. Quote formattedAmount; never hardcode a currency symbol.
POST https://www.wixapis.com/ecom/v1/carts/current/create-checkout
→ { "checkoutId": "ca727402-…" }. GET https://www.wixapis.com/ecom/v1/checkouts/<checkoutId> then shows lineItems, priceSummary.total and shippingInfo.carrierServiceOptions[].shippingOptions[] (title, cost.price.formattedAmount, logistics.pickupDetails for pickup) — use it to answer "do you ship or can I pick up?".
Do not use the checkoutUrl returned by POST /ecom/v2/carts/<checkoutId>/get-checkout-url or GET /ecom/v1/checkouts/<id>/checkout-url on a headless site: it is https://<site>/checkout?checkoutId=…, a Wix-editor page that a headless frontend does not have (404). Create a redirect session instead:
POST https://www.wixapis.com/_api/redirects-api/v1/redirect-session
→ redirectSession.fullUrl is the hosted checkout. Say "pay here to complete the order" and stop: payment cannot be completed through the API, and on a site without a payment provider the hosted page will show that payment is unavailable.
ExecuteWixAPI says "Visitor token rejected (HTTP 403)" for every failureThe sandbox reports any non-2xx (400 ticketReservation must not be empty, 403 No payment method configured, 404) as a token problem. Do not mint a new token (you would lose the cart). Re-issue the single failing request through CallWixSiteAPI to read the real status and message.
POST /stores/v3/variants/query → 404The variants endpoint is POST /stores/v3/products/query-variants. Docs search for "product variants" lists it as Query Variants.
400 catalogItemId has size 0You built the cart body before the product query resolved (or read _id off a REST response). Product ids are products[].id in REST.
400 lineItems[0].id is not a valid GUIDQuantity updates need the cart line id from the last cart response, not the product id. Read the cart first if you no longer have it.
404 OWNED_CART_NOT_FOUND on create-checkoutThe cart belongs to a different visitor token (you minted a new one) or nothing was added. Reuse the token from STEP 1 and re-check GET /ecom/v1/carts/current.
400 not declared as filterableUse /products/search with "search": { "filter": { "directCategoriesInfo.categories": { "$matchItems": [{ "id": … }] } } }. query cannot filter by category, and $hasSome is not accepted.
/checkout?checkoutId=That page exists only on Wix-editor sites. Use the redirect session (STEP 8).
variantIdCart V1/V2 rejects the line. Always resolve the variant in STEP 4 first; a "no options" product still has one variant.
checkoutId as an orderA checkout is unpaid. Only the hosted page (or POST /ecom/v1/checkouts/{id}/create-order after payment) produces an order. Never say "your order is placed".
| Constant | Value |
|---|---|
Wix Stores catalog appId (cart catalogReference.appId) | 215238eb-22a5-4c36-9e7b-e7c08025e04e |
| Categories tree reference | { "appNamespace": "@wix/stores", "treeKey": null } |
| Product read fields worth requesting | ["CURRENCY", "PLAIN_DESCRIPTION"] |
Product, variant, category, line and checkout ids are per site and per visitor — discover them during the conversation.
Last updated: 17 September 2026