The products webhook is called by VIZOCHOK when the AI needs current prices and availability for a set of products. Your endpoint receives a list of SKUs and returns pricing data for each.
Method : POST
Headers :
Header Value Content-Typeapplication/jsonX-VIZOCHOK-Signaturesha256=<hex_digest>X-VIZOCHOK-TimestampUnix timestamp (seconds)
Body :
{
"skus" : [ "milk-001" , "milk-002" , "milk-003" ],
"store_id" : "store-1"
}
List of product SKUs to look up. Typically 1-10 SKUs per request, matching what the AI found in the catalog search.
Store identifier. Use this to return location-specific pricing if your stores have different prices.
Return a JSON object with a products array. Each product must include at minimum sku, price, and in_stock:
{
"products" : [
{
"sku" : "milk-001" ,
"price" : 45.90 ,
"in_stock" : true
},
{
"sku" : "milk-002" ,
"price" : 52.00 ,
"in_stock" : true ,
"promo_price" : 42.00 ,
"promo_label" : "-19%"
},
{
"sku" : "milk-003" ,
"price" : 38.50 ,
"in_stock" : false
}
]
}
Response Fields
Array of product pricing objects. Product SKU (must match a requested SKU).
Whether the product is currently available. Products with in_stock: false are filtered out and not shown to the customer.
Promotional/discounted price. When present, the AI highlights the discount to the customer.
Promotional label displayed alongside the price (e.g., "-19%", "SALE", "2 for 1").
Important Behavior
Missing SKUs : If a requested SKU is not included in your response, VIZOCHOK treats it as unavailable and excludes it from results.
Out of stock : Products with in_stock: false are filtered out — the customer will not see them.
Promotions : When promo_price is present, the AI automatically mentions the discount (e.g., “This milk is on sale: 42.00 instead of 52.00”).
Handler Examples
Python (FastAPI)
Node.js (Express)
from fastapi import FastAPI, Request, HTTPException
from pydantic import BaseModel
import hmac
import hashlib
import time
app = FastAPI()
WEBHOOK_SECRET = "your_webhook_secret"
def verify_signature ( request : Request, body : bytes ):
sig_header = request.headers.get( "x-vizochok-signature" , "" )
timestamp = request.headers.get( "x-vizochok-timestamp" , "" )
if not sig_header.startswith( "sha256=" ):
raise HTTPException( 401 , "Missing signature" )
# Check timestamp (5-minute tolerance)
if timestamp:
if abs (time.time() - int (timestamp)) > 300 :
raise HTTPException( 401 , "Timestamp expired" )
signed_payload = f " { timestamp } ." .encode() + body
else :
signed_payload = body
expected = hmac.new(
WEBHOOK_SECRET .encode(), signed_payload, hashlib.sha256
).hexdigest()
if not hmac.compare_digest(sig_header[ 7 :], expected):
raise HTTPException( 401 , "Invalid signature" )
class CheckProductsRequest ( BaseModel ):
skus: list[ str ]
store_id: str
@app.post ( "/api/vizochok/check-products" )
async def check_products ( req : CheckProductsRequest, request : Request):
body = await request.body()
verify_signature(request, body)
# Look up products in your database
products = []
for sku in req.skus:
product = await db.get_product(sku, store_id = req.store_id)
if product:
item = {
"sku" : sku,
"price" : product.price,
"in_stock" : product.stock > 0 ,
}
if product.promo_price:
item[ "promo_price" ] = product.promo_price
item[ "promo_label" ] = product.promo_label
products.append(item)
return { "products" : products}
Testing
You can test your products webhook from the VIZOCHOK admin panel or via the API:
curl -X POST https://api.vizochok.com/api/v1/admin/webhooks/test \
-H "Authorization: Bearer sk_your_secret_key"
This sends a test request with sample SKUs to your configured products_url and reports the result.
You can also test locally using curl:
curl -X POST http://localhost:8081/api/vizochok/check-products \
-H "Content-Type: application/json" \
-d '{
"skus": ["milk-001", "bread-042"],
"store_id": "store-1"
}'
Keep your products webhook fast (under 2 seconds). The customer is waiting for search results while this call happens. The default timeout is 5 seconds, but faster responses mean a better experience.
Batch efficiently : You will receive 1-10 SKUs per request. Use a single database query with IN clause rather than individual lookups.
Cache prices : If your pricing system is slow, consider a short-lived cache (30-60 seconds) for price lookups.
Return early : Only include promo_price and promo_label when there is actually a promotion. Omitting optional fields is fine.