Reference
Catalog Push API
Keep the assistant’s catalog in sync from your backend: upsert products in batches of up to 500 and remove the ones you no longer sell.
Authorization: Bearer sk_live_… and Content-Type: application/json. Products pushed here live in a dedicated “Push API” source; pushes are incremental (products you don’t send are left untouched).Verify a key
Returns the shop the key belongs to. Connectors call it during setup.
{ "ok": true, "shopId": "3bbb53e1-5814-4251-95a6-ad1ada36f015", "shopName": "Lumière Beauty" }Upsert products
Creates or updates up to 500 products per request, matched by external_id (+ locale). Each item is validated on its own: invalid items are reported in errors while the rest is saved. Body limit: 10 MB.
Request body
| Field | Type | Description |
|---|---|---|
productsrequired | Product[] | 1–500 products (see below). |
locale | string | Default locale for items without one: en ro it fr de es. Defaults to the shop’s default language. |
Product object
| Field | Type | Description |
|---|---|---|
external_idrequired | string ≤255 | Your stable id. Product pages and add-to-cart events use it. |
namerequired | string ≤500 | Product name. |
sku | string | SKU / MPN. |
parent_external_id | string | Groups variants of the same product. |
description | string ≤20000 | Plain text or HTML (converted to text). |
url | http(s) URL | Product page. |
image_urls | URL[] ≤20 | First image is shown on product cards. |
price | number | Regular price (rounded to 2 decimals). |
sale_price | number | Discounted price, if any. |
currency | ISO 4217 | e.g. EUR, RON. Defaults to the shop currency. |
in_stock | boolean | Default true. Out-of-stock products are never recommended. |
stock_qty | integer ≥0 | Optional quantity. |
categories | string[] ≤50 | Category paths, e.g. "Face > Serums". |
brand | string | Brand or manufacturer. |
attributes | object | Free-form facts used for search and answers: string, number, boolean or string[] values. |
locale | string | Language of this item’s texts. |
source_updated_at | ISO 8601 | When the product last changed in your system (optional). |
curl -X POST "https://api.askmerra.com/v1/catalog/products:batchUpsert" \
-H "Authorization: Bearer $ASKMERRA_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"locale": "en",
"products": [{
"external_id": "LUM-SE-01",
"sku": "LUM-SE-01",
"name": "Hydra Glow Serum 30 ml",
"description": "Multi-weight hyaluronic acid serum for dehydrated skin.",
"url": "https://lumiere-beauty.ro/p/lum-se-01",
"image_urls": ["https://lumiere-beauty.ro/img/LUM-SE-01.jpg"],
"price": 39, "sale_price": 32, "currency": "EUR",
"in_stock": true, "stock_qty": 64,
"categories": ["Face > Serums"], "brand": "Lumière",
"attributes": { "skin_type": ["dry", "sensitive"], "vegan": true }
}]
}'{
"received": 1,
"created": 1,
"updated": 0,
"unchanged": 0,
"failed": 0,
"errors": []
}updated counts content and price/stock changes. Content changes (name, description, attributes…) trigger re-enrichment for those products only; price and stock changes are live immediately. Each error has index, external_id and message.
Remove products
Deactivates up to 1,000 products by external_id. They stop being recommended immediately; sending them again reactivates them.
| Field | Type | Description |
|---|---|---|
external_idsrequired | string[] | 1–1000 ids. |
locale | string | Only deactivate this language version. Omit to deactivate all languages. |
{ "deleted": 2 }Example: sync from Node.js
const API = 'https://api.askmerra.com/v1';
const headers = { Authorization: `Bearer ${process.env.ASKMERRA_SECRET_KEY}`, 'Content-Type': 'application/json' };
export async function pushProducts(products: object[]) {
for (let i = 0; i < products.length; i += 500) {
const res = await fetch(`${API}/catalog/products:batchUpsert`, {
method: 'POST',
headers,
body: JSON.stringify({ products: products.slice(i, i + 500) }),
});
if (res.status === 429) {
await new Promise((r) => setTimeout(r, Number(res.headers.get('retry-after') ?? 5) * 1000));
i -= 500; // retry this batch
continue;
}
const result = await res.json();
if (result.failed) console.warn('rejected items', result.errors);
}
}Always send the full product