Products

Create, update, list, and delete catalog products plus sale/coupon offers with your Bearer API key only — no ChatYug portal required. For a standard commerce catalog, required fields are productName, price, imageUrl, and productUrl only — address/lat/long are not required. Locality fields apply only to local_service_businesses / offline_commerce verticals. Upload product images via POST /catalogs/upload-image or pass any public HTTPS imageUrl. Categories are product labels (assign/rename/clear APIs). :catalogId accepts Meta or ChatYug IDs.

List offers

GET /api/external/catalogs/:catalogId/offers

Auth: Authorization: Bearer ck_<api_key> (required)

Returns sale / coupon / auto offers for the catalogue (scoped to the API key WABA).

Create offer (sale / coupon / auto)

POST /api/external/catalogs/:catalogId/offers

Auth: Authorization: Bearer ck_<api_key> (required)

applicationType: SALE sets Meta sale_price (WhatsApp product-card strikethrough). Coupon / auto types use Meta Offers API (Commerce Manager / FB&IG checkout), not WhatsApp coupon fields. Platform-wide for every WABA.

FieldRequiredTypeDescription
applicationTypeYesstringSALE | AUTOMATIC_AT_CHECKOUT | BUYER_APPLIED
valueTypeYesstringEXACT_SALE_PRICE | PERCENTAGE | FIXED_AMOUNT (EXACT_SALE_PRICE only with SALE)
salePrice*numberExact sale price in major units when EXACT_SALE_PRICE
percentOff*number1–100 when PERCENTAGE
fixedAmountOff*numberAmount off when FIXED_AMOUNT
targetSelectionNostringSPECIFIC_PRODUCTS (default) or ALL_CATALOG_PRODUCTS
targetRetailerIds*string[]SKU array for SPECIFIC_PRODUCTS
couponCode*stringRequired for BUYER_APPLIED
startAt / endAtNostringISO timestamps
curl -X POST https://chatyug.com/api/external/catalogs/900000000000003/offers \
  -H "Authorization: Bearer ck_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "applicationType": "SALE",
    "valueType": "EXACT_SALE_PRICE",
    "salePrice": 225.90,
    "targetSelection": "SPECIFIC_PRODUCTS",
    "targetRetailerIds": ["SKU-DEMO-001"]
  }'

Deactivate offer

DELETE /api/external/catalogs/offers/:offerId

Auth: Authorization: Bearer ck_<api_key> (required)

For SALE offers, clears Meta sale_price on targeted products.

List categories

GET /api/external/catalogs/:catalogId/categories

Auth: Authorization: Bearer ck_<api_key> (required)

Categories are labels on products (not separate Meta entities). This endpoint aggregates distinct category values.

Query parameters

FieldRequiredTypeDescription
inStockOnlyNostringDefaults to in-stock only. Pass false or 0 to include out-of-stock products.

Response example

{
  "success": true,
  "catalogId": "900000000000003",
  "categories": [
    { "slug": "cat_apparel", "name": "Apparel", "productCount": 5 }
  ],
  "interactiveListSections": [
    {
      "title": "Categories",
      "rows": [
        { "id": "cat_apparel", "title": "Apparel", "description": "5 products" }
      ]
    }
  ]
}

Assign category

POST /api/external/catalogs/:catalogId/categories/assign

Auth: Authorization: Bearer ck_<api_key> (required)

Body: { "name": "Dairy", "retailerIds": ["SKU-1"] }. Empty categories are unsupported.

curl -X POST https://chatyug.com/api/external/catalogs/900000000000003/categories/assign \
  -H "Authorization: Bearer ck_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Dairy", "retailerIds": ["SKU-DEMO-001"] }'

Rename category

PUT /api/external/catalogs/:catalogId/categories

Auth: Authorization: Bearer ck_<api_key> (required)

Body: { "from": "Dairy", "to": "Milk Products" }. Cannot rename Uncategorized.

Clear category

DELETE /api/external/catalogs/:catalogId/categories/:slugOrName

Auth: Authorization: Bearer ck_<api_key> (required)

curl -X DELETE https://chatyug.com/api/external/catalogs/900000000000003/categories/cat_dairy \
  -H "Authorization: Bearer ck_your_api_key_here"

List products

GET /api/external/catalogs/:catalogId/products

Auth: Authorization: Bearer ck_<api_key> (required)

Query parameters

FieldRequiredTypeDescription
pageNonumberPage number (default 1)
limitNonumberItems per page (default 50)
searchNostringFilter by product name, description, or retailer ID
availabilityNostringFilter by availability (e.g. in stock)
categoryNostringWhen set, returns category-scoped results with resolvedCategory and productRetailerIds

Response example

{
  "success": true,
  "products": [
    {
      "Product_Id": "101",
      "Meta_Product_Id": "ext_1720856400000",
      "Product_Name": "Demo Cotton T-Shirt",
      "Description": "Soft cotton, size M",
      "Retailer_ID": "SKU-DEMO-001",
      "Currency": "INR",
      "Price": 499.00,
      "Image_URL": "https://example.com/demo-shirt.jpg",
      "Product_URL": "https://example.com/products/demo-shirt",
      "Availability": "in stock",
      "Category": "Apparel",
      "Brand": "ChatYug Demo",
      "Inventory": 100
    }
  ],
  "pagination": { "page": 1, "limit": 50, "total": 1, "pages": 1 }
}

Upload product image

POST /api/external/catalogs/upload-image

Auth: Authorization: Bearer ck_<api_key> (required)

Multipart field image — JPEG, PNG, or WebP, max 5MB. Returns a public HTTPS imageUrl for create/update. You may also pass any existing public CDN URL as imageUrl without uploading.

curl -X POST https://chatyug.com/api/external/catalogs/upload-image \
  -H "Authorization: Bearer ck_your_api_key_here" \
  -F "image=@/path/to/product.jpg"
{
  "success": true,
  "message": "Image uploaded successfully",
  "data": {
    "imageUrl": "https://chatyug.com/uploads/product-images/product-1720856400000-123.jpg",
    "imagePath": "/uploads/product-images/product-1720856400000-123.jpg",
    "filename": "product-1720856400000-123.jpg",
    "size": 84210,
    "mimeType": "image/jpeg"
  }
}

Create product

POST /api/external/catalogs/:catalogId/products

Auth: Authorization: Bearer ck_<api_key> (required)

Request parameters

FieldRequiredTypeDescription
productNameYesstringProduct title
priceYesnumberPrice in currency units (e.g. 499 for ₹499)
descriptionNostringProduct description
currencyNostringDefault INR
imageUrlYesstringPublic HTTPS image URL (required for Meta). Upload via POST /catalogs/upload-image or use your CDN.
productUrlYesstringFull http(s) product or shop page URL. Becomes Meta link shown under the description in WhatsApp. Never defaults to chatyug.com.
availabilityNostringDefault in stock
retailerIdNostringSKU / retailer ID. Auto-generated as SKU-{timestamp} if omitted.
categoryNostringProduct category
brandNostringBrand name
inventoryNonumberStock count

Response example

{
  "success": true,
  "message": "Product created successfully",
  "data": {
    "productId": "101",
    "metaProductId": "ext_1720856400000",
    "retailerId": "SKU-DEMO-001",
    "productName": "Demo Cotton T-Shirt",
    "price": 499,
    "currency": "INR"
  }
}

Update product

PUT /api/external/catalogs/:catalogId/products/:retailerId

Auth: Authorization: Bearer ck_<api_key> (required)

Request parameters

Same fields as create — all optional in the body. :retailerId in the path identifies the product.

FieldRequiredTypeDescription
productNameNostringUpdated title
descriptionNostringUpdated description
priceNonumberUpdated price
currencyNostringCurrency code
imageUrlNostringUpdated image URL
productUrlNostringUpdated product/shop URL (Meta link). Must be full http(s) if sent.
availabilityNostringAvailability status
categoryNostringCategory
brandNostringBrand
inventoryNonumberStock count

Response example

{
  "success": true,
  "message": "Product updated successfully",
  "data": { "productId": "101", "retailerId": "SKU-DEMO-001" }
}

Delete product

DELETE /api/external/catalogs/:catalogId/products/:retailerId

Auth: Authorization: Bearer ck_<api_key> (required)

Removes the product from Meta and ChatYug by SKU (retailerId). If Meta delete fails, ChatYug still deletes the local row and may return metaWarning.

Example

curl -X DELETE https://chatyug.com/api/external/catalogs/900000000000003/products/SKU-DEMO-001 \
  -H "Authorization: Bearer ck_your_api_key_here"

Response example

{
  "success": true,
  "message": "Product deleted successfully",
  "data": { "productId": 101, "retailerId": "SKU-DEMO-001", "productName": "Demo Cotton T-Shirt" }
}

Code samples — create product

curl -X POST https://chatyug.com/api/external/catalogs/900000000000003/products \
  -H "Authorization: Bearer ck_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "productName": "Demo Cotton T-Shirt",
    "price": 499,
    "currency": "INR",
    "imageUrl": "https://example.com/demo-shirt.jpg",
    "productUrl": "https://example.com/products/demo-shirt",
    "retailerId": "SKU-DEMO-001",
    "availability": "in stock"
  }'
const axios = require('axios');

await axios.post('https://chatyug.com/api/external/catalogs/900000000000003/products', {
  productName: 'Demo Cotton T-Shirt',
  price: 499,
  currency: 'INR',
  imageUrl: 'https://example.com/demo-shirt.jpg',
  productUrl: 'https://example.com/products/demo-shirt',
  retailerId: 'SKU-DEMO-001',
  availability: 'in stock'
}, { headers: { Authorization: 'Bearer ck_your_api_key_here' } });
import requests

requests.post('https://chatyug.com/api/external/catalogs/900000000000003/products', json={
    'productName': 'Demo Cotton T-Shirt',
    'price': 499,
    'currency': 'INR',
    'imageUrl': 'https://example.com/demo-shirt.jpg',
    'productUrl': 'https://example.com/products/demo-shirt',
    'retailerId': 'SKU-DEMO-001',
    'availability': 'in stock'
}, headers={'Authorization': 'Bearer ck_your_api_key_here'})
$client = new GuzzleHttp\Client();
$client->post('https://chatyug.com/api/external/catalogs/900000000000003/products', [
    'headers' => ['Authorization' => 'Bearer ck_your_api_key_here'],
    'json' => [
        'productName' => 'Demo Cotton T-Shirt',
        'price' => 499,
        'currency' => 'INR',
        'imageUrl' => 'https://example.com/demo-shirt.jpg',
        'productUrl' => 'https://example.com/products/demo-shirt',
        'retailerId' => 'SKU-DEMO-001',
        'availability' => 'in stock'
    ]
]);