Last updated: 4 November 2026
Supported feed URLs
IVO can read product feeds from a public URL in JSON, XML, Google Shopping RSS/XML or CSV format. The URL must return the feed content directly and must be reachable by the IVO.md crawler.
JSON structure
The feed can be an array of products or an object that contains a product list, for example {"products": [...]}, {"product": [...]}, {"offers": [...]} or another nested product array. IVO searches for the largest product list when the structure is nested.
{
"products": [
{
"sku": "LAP-14",
"name": "Laptop 14",
"price": "12999 MDL",
"description": "Compact laptop",
"images": ["https://example.com/1.jpg", "https://example.com/2.jpg"]
}
]
}XML structure
IVO supports common XML feeds, including Google Shopping RSS items and simple product catalogs.
<products>
<product>
<sku>LAP-14</sku>
<name>Laptop 14</name>
<price>12999</price>
<currency>MDL</currency>
<image>https://example.com/1.jpg</image>
</product>
</products>CSV structure
CSV feeds must use the first row as headers. Comma, semicolon, tab and pipe delimiters are detected automatically.
sku,name,price,currency,image,availability
LAP-14,Laptop 14,12999,MDL,https://example.com/1.jpg,5Required fields
The minimum required fields are the Internal ID, name and price. Currency can be included in the price, mapped as a separate currency field, or configured as a default value.
The Internal ID is your own stable product code (for example sku or id), ticked on one column in the mapping. It is how every sync recognises the same product. Rows without an ID are skipped. Products that share an ID on different rows are skipped and taken off sale until each has its own. If more rows are skipped than have a valid ID, the feed is stopped.
A row with an ID and stock but no name or price only updates the stock of the existing product.
Mapping fields
In the integration preview, IVO shows every source key from the feed. Assign each source key to the IVO field it represents. Multiple source keys can be assigned to the same field. For text fields such as name or description, values are concatenated. For image, all valid image URLs are collected.
Images
Use one target field: image. You can map keys like image, images, image_1, image_2, image_link or gallery to it. Arrays of image URLs are supported.
If your feed lists images by path (for example /catalog/image.jpg) instead of the full address, fill in Image base URL in the integration setup, and the images are downloaded from there.
Defaults
If the feed does not contain a value such as currency, brand, category, availability, image or description, you can set a fixed default value in the integration setup.
Stock
Send the quantity in availability (or stock, quantity, qty). 0, false, out of stock and unavailable mean no stock. Stock per merchant point and products that disappear from the feed are set up in the integration; the feed guide explains the options.
Sale price and recommended price
A feed that marks promotions the Google way — g:price with g:sale_price and, optionally, g:sale_price_effective_date — sells at the sale price while it is on and shows the regular price as the recommended retail price (PRP). A recommended price in a field of its own (retail_price, rrp, msrp, old_price) is used as it is, whenever it is higher than the selling price.
Promotional prices (Black Friday, Cyber Monday)
Each promotion has its own prices, separate from your normal price. While a promotion is taking prices, two fields for it appear in the mapping, for example Promotional price – Black Friday and Promotional quantity – Black Friday. Add a column to your feed for each, under any name, and assign it to its field. You can use one column or both.
sku,name,price,availability,bf_price,bf_stock
LAP-14,Laptop 14,12999,5,9999,3
LAP-15,Laptop 15,15999,2,13999,
LAP-16,Laptop 16,17999,4,,| Field | Value | Effect |
|---|---|---|
| Promotional price | a number | The product sells at this price during the promotion. It must be lower than the normal price. |
| Promotional price | empty | The product leaves the promotion. |
| Promotional quantity | a number | That many units sell at the promotional price, and the rest at the normal price. |
| Promotional quantity | 0 | No units sell at the promotional price. The price stays saved for when stock comes back. |
| Promotional quantity | empty | All stock sells at the promotional price. |
- Each column works on its own, also in a feed that sends only the ID and stock. A field you do not map stays as it is: a price column keeps the quantity set in the dashboard, and a quantity column keeps the price set in the dashboard. A quantity with no price set has no effect.
- The quantity is the total for the promotion and part of your normal stock. Units sold come off it, so send the total, not what is left. A product with a normal stock of 0 does not sell, whatever its promotional quantity.
- When it applies. The feed is read every six hours, and prices change only while the promotion is shown in your Merchant Dashboard. Outside that period the columns are ignored and prices already set stay.
- What does not show as an error. A price that is not lower than the normal price is not applied and you get no message, so check your prices on the product's offers page. A new product gets its price on a later sync, once its offer exists.
- Each promotion is mapped separately. Cyber Monday has its own columns, and a new promotion needs a new mapping.
The price modifier applies to the promotional price too. sale_price is not a promotional price: it works as described in the section above. The same fields appear when mapping an uploaded file, where a new product gets its price the next time the file is uploaded.
Weight and boxes
Send the packed weight with its unit (weight: 1.8 kg) and the box size (length, width, height, or dimensions: 60x40x20 cm). A product that ships in several boxes sends packages instead, in the same format as the merchant API: one entry per box, each with its own weight and dimensions. In XML that is one element per box inside <packages>; in JSON, a list; in CSV, the same list as JSON text in the cell. Other layouts are read too (attributes, Google's g: prefix, the text form, package_count); the feed guide lists them. Whatever is missing is estimated automatically.
<packages>
<package><weight>25000</weight><dimensions>200x90x12 cm</dimensions></package>
<package><weight>25000</weight><dimensions>200x90x12 cm</dimensions></package>
<package><weight>12000</weight><dimensions>120x20x10 cm</dimensions></package>
</packages>Variants
For variant details, map only explicit dimensions such as color, size, memory or display to variant_option. Multiple source keys may map to variant_option.
{
"name": "Laptop 14 Ultra / 32GB / Silver",
"price": 15999,
"variant_option": ["memory:32GB", "color:Silver"]
}If your feed already contains a trusted item_group_id, IVO can read it internally, but it is not inferred automatically because incorrect grouping could merge unrelated products as variants.
Crawler identification
Feed requests use this User-Agent:
IVO.md (+https://ivo.md/help/merchant-integration/ivo-md-crawler)