Skip to main content
The cart webhook is called when the AI assistant performs a cart operation on behalf of the customer. Your endpoint receives the operation details and returns a success/failure response.

Request Format

Method: POST Headers:
HeaderValue
Content-Typeapplication/json
X-VIZOCHOK-Signaturesha256=<hex_digest>
X-VIZOCHOK-TimestampUnix timestamp (seconds)
Body:
{
  "action": "add",
  "store_id": "store-1",
  "session_id": "user-123",
  "sku": "milk-001",
  "name": "Молоко Lactel 2.5%",
  "quantity": 1,
  "price": 45.90
}

Common Fields

action
string
required
The cart operation: "add", "remove", "update_quantity", or "clear".
store_id
string
required
Store identifier.
session_id
string
required
Session/user identifier. Matches the userId from the widget config, or an auto-generated ID if none was provided. Use this to look up the correct cart.

Actions

Add

Add a product to the cart.
{
  "action": "add",
  "store_id": "store-1",
  "session_id": "user-123",
  "sku": "milk-001",
  "name": "Молоко Lactel 2.5%",
  "quantity": 1,
  "price": 45.90
}
sku
string
required
Product SKU to add.
name
string
Product name (for convenience — you can ignore this and look up by SKU).
quantity
number
Quantity to add. Defaults to 1 if not provided.
price
number
Price as known by the AI (from the last products webhook call). You may use this or look up the current price yourself.

Remove

Remove a product from the cart.
{
  "action": "remove",
  "store_id": "store-1",
  "session_id": "user-123",
  "sku": "milk-001"
}
sku
string
required
Product SKU to remove.

Update Quantity

Change the quantity of an existing cart item.
{
  "action": "update_quantity",
  "store_id": "store-1",
  "session_id": "user-123",
  "sku": "milk-001",
  "quantity": 3
}
sku
string
required
Product SKU to update.
quantity
number
required
New quantity for the product.

Clear

Remove all items from the cart.
{
  "action": "clear",
  "store_id": "store-1",
  "session_id": "user-123"
}
No additional fields required.

Response Format

Return a JSON object with ok (boolean) and an optional reason on failure:

Success

{"ok": true}

Failure

{"ok": false, "reason": "out_of_stock"}
ok
boolean
required
Whether the operation succeeded.
reason
string
Human-readable reason for failure. The AI uses this to inform the customer and may suggest alternatives.

Common Rejection Reasons

ReasonWhen to ReturnAI Behavior
out_of_stockProduct is unavailableSuggests alternative products
product_not_foundSKU does not existInforms customer, offers to search again
quantity_exceededNot enough stock for requested quantitySuggests a lower quantity
not_in_cartTrying to remove/update an item not in cartInforms customer
missing_skuNo SKU providedReports error
missing_paramsRequired parameters missingReports error
You can use any string as the reason value. The AI reads the reason and responds contextually. Common, descriptive reasons work best — for example, "max_3_per_customer" would lead the AI to say something like “There’s a limit of 3 per customer for this product.”

Cart GET Endpoint

In addition to the POST webhook for operations, you can implement a GET endpoint to provide the initial cart state when a new conversation starts. Method: GET Query Parameters:
ParameterDescription
store_idStore identifier
session_idSession/user identifier
Response:
{
  "items": [
    {
      "sku": "bread-01",
      "name": "Хліб Столичний",
      "price": 32.00,
      "quantity": 1,
      "unit": "pcs"
    },
    {
      "sku": "butter-05",
      "name": "Масло Президент 200г",
      "price": 89.50,
      "quantity": 1,
      "unit": "pcs",
      "promo_price": 79.90
    }
  ]
}
items
array
required
Array of cart items.
sku
string
required
Product SKU.
name
string
required
Product name.
price
number
required
Unit price.
quantity
number
required
Quantity in cart.
unit
string
Unit of measure (e.g., "pcs", "kg"). Defaults to "PCS".
promo_price
number
Promotional price, if applicable.

Handler Examples

from fastapi import FastAPI, Request, HTTPException
from pydantic import BaseModel

app = FastAPI()

class CartWebhookRequest(BaseModel):
    action: str
    store_id: str
    session_id: str
    sku: str | None = None
    name: str | None = None
    quantity: int | None = None
    price: float | None = None


@app.post("/api/vizochok/cart")
async def handle_cart(req: CartWebhookRequest, request: Request):
    body = await request.body()
    verify_signature(request, body)  # See signature verification docs

    cart = get_cart(req.session_id)

    if req.action == "add":
        if not req.sku:
            return {"ok": False, "reason": "missing_sku"}

        product = db.get_product(req.sku)
        if not product or product.stock <= 0:
            return {"ok": False, "reason": "out_of_stock"}

        cart.add_item(
            sku=req.sku,
            name=req.name or product.name,
            price=product.price,  # Use YOUR price, not the one from the request
            quantity=req.quantity or 1,
        )
        return {"ok": True}

    elif req.action == "remove":
        if not req.sku:
            return {"ok": False, "reason": "missing_sku"}
        cart.remove_item(req.sku)
        return {"ok": True}

    elif req.action == "update_quantity":
        if not req.sku or not req.quantity:
            return {"ok": False, "reason": "missing_params"}

        product = db.get_product(req.sku)
        if product and product.stock < req.quantity:
            return {"ok": False, "reason": "quantity_exceeded"}

        cart.update_quantity(req.sku, req.quantity)
        return {"ok": True}

    elif req.action == "clear":
        cart.clear()
        return {"ok": True}

    return {"ok": False, "reason": "unknown_action"}


@app.get("/api/vizochok/cart/items")
async def get_cart_items(store_id: str = "", session_id: str = ""):
    cart = get_cart(session_id)
    return {"items": cart.get_items()}

Best Practices

Always validate stock on add operations. The AI has price data from the last products webhook call, but stock may have changed since then.
Use your own authoritative price when adding items to the cart, not the price field from the webhook request. The price in the request is what VIZOCHOK received from your last products webhook call and may be slightly stale.
  • Idempotency: If the same add request arrives twice (due to retries), your handler should handle it gracefully — either add the quantity again or deduplicate.
  • Session mapping: The session_id maps to the userId from the SDK. If no userId was provided, VIZOCHOK generates one per WebSocket connection. Plan your cart storage accordingly.
  • Response time: Keep responses under 5 seconds (the default timeout). Cart operations should be fast since they are blocking the AI’s response to the customer.