Manova Developers

Product sync

Connect the store, send the whole catalog, then keep it current with small updates.

All calls go to https://manova.ir/api/v1/external/store with the connection key as a bearer token. Full request and response schemas are in the API reference.

1. Connect

Tell Manova where the shop is and where to send order lookups. Call it once when the integration is set up, and again whenever any of these values changes.

curl -X POST https://manova.ir/api/v1/external/store/connect \
  -H "Authorization: Bearer $MANOVA_STORE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "siteUrl": "https://shop.example.com",
    "apiUrl": "https://shop.example.com/api/manova",
    "currency": "IRT",
    "pluginVersion": "my-cms-1.0"
  }'
  • apiUrl must be on the same domain as siteUrl (with or without www.) and reachable from the internet. Manova appends /order to it for order lookups.
  • The shop's domain is added to the assistant's allowed domains, so the widget works there right away.
  • Connecting a different shop with the same key deletes the products of the previous one.

The response tells you what to embed:

{
  "publicKey": "pk_8Wc1...",
  "botName": "دستیار فروشگاه",
  "active": true,
  "widgetUrl": "https://manova.ir/widget.js",
  "ordersEnabled": true,
  "panelUrl": "https://manova.ir/workspace/site/3c0d.../store",
  "products": 0,
  "inStock": 0,
  "lastSyncAt": null
}

GET /store returns the same object at any time, which makes it a good connection check.

2. Full sync

A full sync sends every published product and lets Manova delete the ones you no longer have.

Start

Pick a random syncId (8 to 40 characters: letters, digits, _ and -).

POST /store/sync
{ "syncId": "sync_20261030_a81f", "phase": "start" }

Send batches

Send products in batches of up to 100, each with the same syncId:

POST /store/products
{
  "syncId": "sync_20261030_a81f",
  "products": [
    {
      "id": 1042,
      "name": "کفش رانینگ مردانه مدل آریا",
      "url": "https://shop.example.com/product/aria-running",
      "image": "https://shop.example.com/media/aria.jpg",
      "sku": "ARIA-42",
      "type": "variable",
      "price": 2450000,
      "price_text": "۲٬۴۵۰٬۰۰۰ تومان",
      "regular_price_text": "۲٬۹۰۰٬۰۰۰ تومان",
      "in_stock": true,
      "stock_quantity": 7,
      "categories": ["کفش", "ورزشی"],
      "tags": ["رانینگ", "سبک"],
      "summary": "<p>رویه مش تنفس‌پذیر، زیره EVA.</p>",
      "cart_url": "https://shop.example.com/cart?add=1042",
      "total_sales": 318
    }
  ]
}
Response
{ "ok": true, "saved": 1, "removed": 0 }

Finish

POST /store/sync
{ "syncId": "sync_20261030_a81f", "phase": "finish" }
Response
{ "ok": true, "removed": 12, "products": 1840, "inStock": 1610 }

Every product that was not sent in this sync is removed.

Starting a new sync replaces the previous one. A batch or a finish carrying an older syncId gets 409 CONFLICT: stop that sync, because a newer one is running.

3. Incremental updates

When a product changes, send just that product, without syncId. Send the ids of deleted products in deleted:

POST /store/products
{
  "products": [{ "id": 1042, "name": "کفش رانینگ مردانه مدل آریا", "url": "https://shop.example.com/product/aria-running", "price_text": "۲٬۲۰۰٬۰۰۰ تومان", "in_stock": true }],
  "deleted": [977, 978]
}

A product with "visible": false is removed too, which is handy for drafts and hidden products. Run a full sync now and then (for example nightly) to catch anything an update missed.

Product fields

id, name and url are required; a product without a name or a URL on the shop's own domain is skipped. Each update replaces the stored product, so always send every field you have.

Prop

Type

Links on product cards get utm_source=manova&utm_medium=assistant, so sales from the chat show up in your analytics.

Errors

StatusCodeMeaning
401UNAUTHENTICATEDThe key is wrong or was replaced by a new one in the panel.
409CONFLICTProducts were sent before connect, or a newer full sync has started.
422VALIDATION_ERRORA field is invalid; details names it. Also when apiUrl is not on the shop's domain or is not public.

On this page