# XML Format Guide

Feeds must conform to the [Google Product Feed](https://support.google.com/merchants/answer/7052112) XML format. The file is an RSS 2.0 document with product data inside `<item>` elements under a `<channel>`. Google-specific fields use the `g:` namespace prefix (`http://base.google.com/ns/1.0`).

## Basic Structure

```xml
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:g="http://base.google.com/ns/1.0">
  <channel>
    <title>My Product Catalog</title>
    <link>https://www.example.com</link>
    <description>Product feed</description>

    <item>
      <!-- Product fields go here -->
    </item>

    <item>
      <!-- Another product -->
    </item>

  </channel>
</rss>
```

Each `<item>` represents a single product variant (SKU). The service parses every item, groups them by `item_group_id` into offers, and transforms them into standardized Violet platform products.

## Supported Fields

All Google-namespaced fields use the `g:` prefix. The `<title>` and `<description>` elements can appear with or without the prefix.

### Product Identity

| XML Element         | Required | Type   | Description                                                                                                                                                                                                                      |
| ------------------- | -------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `<g:id>`            | **Yes**  | string | Unique identifier for this product variant (SKU). Each item in the feed must have a distinct ID. This becomes the SKU's `external_id` in the Violet platform.                                                                    |
| `<title>`           | **Yes**  | string | Product title. Used as both the offer name and SKU name. Keep it descriptive but concise (e.g., `"Nike Air Max 90 - Black/White - Size 10"`).                                                                                    |
| `<g:item_group_id>` | No       | string | Groups multiple items into a single parent product (offer). All items sharing the same `item_group_id` become SKU variants under one offer. See [Grouping Items Under a Parent Product](#grouping-items-under-a-parent-product). |

### Description & Links

| XML Element      | Required | Type         | Description                                                                                          |
| ---------------- | -------- | ------------ | ---------------------------------------------------------------------------------------------------- |
| `<description>`  | No       | string       | Detailed product description. Mapped to the offer's description field.                               |
| `<link>`         | No       | string (URL) | URL to the product page on your website. Mapped to the offer's `external_url`.                       |
| `<g:image_link>` | No       | string (URL) | URL of the main product image. Should be a high-quality image (at least 800x800 pixels recommended). |

### Pricing

Prices are specified as a decimal value followed by a space and a 3-letter ISO 4217 currency code (e.g., `79.99 USD`). European decimal format is also supported (e.g., `79,99 EUR`). Prices are converted to integer cents internally (e.g., `79.99 USD` becomes `7999`).

| XML Element       | Required | Type   | Description                                                                                                                                                                                   |
| ----------------- | -------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `<g:price>`       | **Yes**  | string | The current selling price. Format: `{amount} {currency}` (e.g., `"29.99 USD"`, `"1,234.56 CAD"`). If no `sale_price` is provided, this value is used as both the retail price and sale price. |
| `<g:sale_price>`  | No       | string | A discounted price. When present, this becomes the SKU's sale price and the `price` field becomes the retail (original/MSRP) price. Same format as `price`.                                   |
| `<g:offer_price>` | No       | string | An alternative offer price. Parsed but reserved for future use.                                                                                                                               |

**Supported currency codes:** `USD`, `EUR`, `GBP`, `CAD`. Currency symbols (`$`, `€`, `£`) are also recognized. If no currency is specified, `USD` is assumed.

**Pricing examples:**

```xml
<!-- Simple pricing: one price for everything -->
<g:price>49.99 USD</g:price>

<!-- Sale pricing: show original price crossed out -->
<g:price>49.99 USD</g:price>
<g:sale_price>34.99 USD</g:sale_price>
<!-- Result: retail_price = 4999, sale_price = 3499 -->
```

### Availability & Inventory

| XML Element        | Required | Type    | Description                                                                                                                                                                              |
| ------------------ | -------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `<g:availability>` | **Yes**  | string  | Stock status. Accepted values: `in stock`, `in_stock`, `out of stock`, `out_of_stock`, `preorder`. Items with `in stock` or `in_stock` are marked as available.                          |
| `<g:inventory>`    | No       | integer | Exact quantity available. When provided, enables inventory tracking with precise stock counts. Takes priority over `<stock>` and `<g:availability>` for quantity.                        |
| `<stock>`          | No       | string  | Custom stock quantity field. Supports formats like `"5"`, `"3+"`, `"10+"`. Used as a fallback when `<g:inventory>` is not present. Note: this field does **not** use the `g:` namespace. |

**Inventory resolution order:** The service determines stock quantity using the first available source:

1. `<g:inventory>` — Exact quantity, enables inventory tracking
2. `<stock>` — Parsed quantity (the `+` suffix is stripped), enables inventory tracking
3. `<g:availability>` — Binary in-stock/out-of-stock only, no quantity tracking

### Product Identifiers

| XML Element | Required | Type   | Description                                                                          |
| ----------- | -------- | ------ | ------------------------------------------------------------------------------------ |
| `<g:gtin>`  | No       | string | Global Trade Item Number (UPC, EAN, ISBN, or JAN). Mapped to the SKU's `gtin` field. |
| `<g:mpn>`   | No       | string | Manufacturer Part Number. Mapped to the SKU's `upc` field.                           |
| `<g:brand>` | No       | string | Product brand or manufacturer name. Mapped to the offer's `vendor` field.            |

### Condition

| XML Element     | Required | Type   | Description                                                                                           |
| --------------- | -------- | ------ | ----------------------------------------------------------------------------------------------------- |
| `<g:condition>` | No       | string | Product condition. Accepted values: `new`, `refurbished`, `used`. Parsed and stored on the feed item. |

### Categorization

| XML Element                   | Required | Type   | Description                                                                                                                                           |
| ----------------------------- | -------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `<g:google_product_category>` | No       | string | Google product taxonomy category. Takes priority over `product_type` for categorization. Example: `"Apparel & Accessories > Shoes > Athletic Shoes"`. |
| `<g:product_type>`            | No       | string | Your own product categorization. Used as a fallback when `google_product_category` is not set. Example: `"Men's Footwear > Running Shoes"`.           |

### Variant Attributes

These fields define how product variants differ from each other. When items are grouped by `item_group_id`, these attributes become selectable variant options on the offer (e.g., a color picker or size dropdown).

| XML Element    | Required | Type   | Description                                                                                          |
| -------------- | -------- | ------ | ---------------------------------------------------------------------------------------------------- |
| `<g:color>`    | No       | string | Product color. Creates a "Color" variant on the offer. Example: `"Navy Blue"`.                       |
| `<g:size>`     | No       | string | Product size. Creates a "Size" variant on the offer. Example: `"10"`, `"Medium"`, `"32W x 30L"`.     |
| `<g:material>` | No       | string | Primary material. Creates a "Material" variant on the offer. Example: `"Leather"`, `"Cotton Blend"`. |
| `<g:pattern>`  | No       | string | Product pattern or print. Creates a "Pattern" variant on the offer. Example: `"Striped"`, `"Plaid"`. |

### Demographic Attributes

These fields are stored as offer-level metadata rather than variant attributes.

| XML Element     | Required | Type   | Description                                                                                                                        |
| --------------- | -------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------- |
| `<g:age_group>` | No       | string | Target age group. Accepted values: `newborn`, `infant`, `toddler`, `kids`, `adult`. Stored as offer metadata with key `age_group`. |
| `<g:gender>`    | No       | string | Target gender. Accepted values: `male`, `female`, `unisex`. Stored as offer metadata with key `gender`.                            |

## Grouping Items Under a Parent Product

Use `<g:item_group_id>` to group multiple items (SKUs) into a single offer. This is how you represent a product that comes in multiple sizes, colors, or other variants.

**How it works:**

1. All items with the same `item_group_id` are grouped into one offer
2. Each item becomes a separate SKU under that offer
3. Variant attributes (`color`, `size`, `material`, `pattern`) on each item become selectable options
4. The first item in the group provides the offer-level details (title, description, link, brand, category)
5. Pricing is aggregated across all SKUs — the offer tracks the min and max price

**Items without an `item_group_id`** are treated as standalone offers with a single SKU. The item's `<g:id>` is used as the group key.

### Example: T-Shirt with Color and Size Variants

```xml
<!-- White T-Shirt, Small -->
<item>
  <g:id>TSHIRT-WHT-S</g:id>
  <g:item_group_id>TSHIRT-001</g:item_group_id>
  <title>Classic Cotton T-Shirt</title>
  <description>Comfortable everyday cotton tee</description>
  <link>https://www.example.com/products/classic-tshirt</link>
  <g:image_link>https://www.example.com/images/tshirt-white.jpg</g:image_link>
  <g:price>24.99 USD</g:price>
  <g:availability>in stock</g:availability>
  <g:inventory>50</g:inventory>
  <g:brand>ExampleBrand</g:brand>
  <g:condition>new</g:condition>
  <g:color>White</g:color>
  <g:size>S</g:size>
  <g:material>Cotton</g:material>
  <g:gender>unisex</g:gender>
  <g:age_group>adult</g:age_group>
  <g:google_product_category>Apparel &amp; Accessories > Clothing > Shirts &amp; Tops</g:google_product_category>
  <g:gtin>012345678901</g:gtin>
</item>

<!-- White T-Shirt, Medium -->
<item>
  <g:id>TSHIRT-WHT-M</g:id>
  <g:item_group_id>TSHIRT-001</g:item_group_id>
  <title>Classic Cotton T-Shirt</title>
  <description>Comfortable everyday cotton tee</description>
  <link>https://www.example.com/products/classic-tshirt</link>
  <g:image_link>https://www.example.com/images/tshirt-white.jpg</g:image_link>
  <g:price>24.99 USD</g:price>
  <g:availability>in stock</g:availability>
  <g:inventory>35</g:inventory>
  <g:brand>ExampleBrand</g:brand>
  <g:condition>new</g:condition>
  <g:color>White</g:color>
  <g:size>M</g:size>
  <g:material>Cotton</g:material>
  <g:gtin>012345678902</g:gtin>
</item>

<!-- Black T-Shirt, Small -->
<item>
  <g:id>TSHIRT-BLK-S</g:id>
  <g:item_group_id>TSHIRT-001</g:item_group_id>
  <title>Classic Cotton T-Shirt</title>
  <description>Comfortable everyday cotton tee</description>
  <link>https://www.example.com/products/classic-tshirt</link>
  <g:image_link>https://www.example.com/images/tshirt-black.jpg</g:image_link>
  <g:price>24.99 USD</g:price>
  <g:availability>out of stock</g:availability>
  <g:inventory>0</g:inventory>
  <g:brand>ExampleBrand</g:brand>
  <g:condition>new</g:condition>
  <g:color>Black</g:color>
  <g:size>S</g:size>
  <g:material>Cotton</g:material>
  <g:gtin>012345678903</g:gtin>
</item>
```

This produces **one offer** (`TSHIRT-001`) with:

* **3 SKUs**: `TSHIRT-WHT-S`, `TSHIRT-WHT-M`, `TSHIRT-BLK-S`
* **Variant "Color"**: White, Black
* **Variant "Size"**: S, M
* **Variant "Material"**: Cotton
* **Price range**: min = 2499, max = 2499

## Handling Images

Each item supports a single `<g:image_link>` for its main product image. To associate different images with different variants, provide a unique `image_link` per item.

```xml
<!-- Red variant has its own image -->
<item>
  <g:id>SHOE-RED-10</g:id>
  <g:item_group_id>SHOE-001</g:item_group_id>
  <g:image_link>https://www.example.com/images/shoe-red.jpg</g:image_link>
  <g:color>Red</g:color>
  <!-- ... -->
</item>

<!-- Blue variant has its own image -->
<item>
  <g:id>SHOE-BLU-10</g:id>
  <g:item_group_id>SHOE-001</g:item_group_id>
  <g:image_link>https://www.example.com/images/shoe-blue.jpg</g:image_link>
  <g:color>Blue</g:color>
  <!-- ... -->
</item>
```

> **Note:** The `<g:additional_image_link>` element from the Google Product Feed specification is not currently supported. Only the primary `<g:image_link>` is processed per item.

## Standalone Products (No Variants)

Products that don't come in multiple variants can omit `<g:item_group_id>`. Each item becomes its own offer with a single SKU.

```xml
<item>
  <g:id>GADGET-042</g:id>
  <title>Wireless Bluetooth Speaker</title>
  <description>Portable speaker with 12-hour battery life</description>
  <link>https://www.example.com/products/bt-speaker</link>
  <g:image_link>https://www.example.com/images/speaker.jpg</g:image_link>
  <g:price>59.99 USD</g:price>
  <g:availability>in stock</g:availability>
  <g:inventory>120</g:inventory>
  <g:brand>SoundTech</g:brand>
  <g:condition>new</g:condition>
  <g:gtin>098765432109</g:gtin>
  <g:google_product_category>Electronics > Audio > Speakers</g:google_product_category>
</item>
```

This produces **one offer** with **one SKU**, both using `GADGET-042` as their external ID.

## Sale Pricing Example

To show a discounted price alongside the original price, provide both `<g:price>` (the original/MSRP) and `<g:sale_price>` (the current discounted price).

```xml
<item>
  <g:id>JACKET-SALE-01</g:id>
  <title>Winter Puffer Jacket</title>
  <g:price>199.99 USD</g:price>
  <g:sale_price>129.99 USD</g:sale_price>
  <g:availability>in stock</g:availability>
  <!-- ... -->
</item>
```

**Result:** `retail_price = 19999` (cents), `sale_price = 12999` (cents).

When only `<g:price>` is provided (no `<g:sale_price>`), the same value is used for both `retail_price` and `sale_price`.

## Minimal Valid Feed

The smallest valid feed requires at minimum `<g:id>`, `<title>`, `<g:price>`, and `<g:availability>` on each item:

```xml
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:g="http://base.google.com/ns/1.0">
  <channel>
    <title>My Store</title>
    <link>https://www.example.com</link>
    <description>Product feed</description>
    <item>
      <g:id>PROD-001</g:id>
      <title>Example Product</title>
      <g:price>19.99 USD</g:price>
      <g:availability>in stock</g:availability>
    </item>
  </channel>
</rss>
```

## Complete Feed Example

A full-featured feed with grouped variants, sale pricing, inventory tracking, and all supported fields:

```xml
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:g="http://base.google.com/ns/1.0">
  <channel>
    <title>Acme Electronics - Summer 2024</title>
    <link>https://www.acme-electronics.com</link>
    <description>Complete product catalog</description>

    <!-- Standalone product -->
    <item>
      <g:id>CHARGER-USB-C</g:id>
      <title>65W USB-C Fast Charger</title>
      <description>GaN technology fast charger compatible with laptops and phones</description>
      <link>https://www.acme-electronics.com/products/usb-c-charger</link>
      <g:image_link>https://cdn.acme-electronics.com/images/charger-usbc.jpg</g:image_link>
      <g:price>39.99 USD</g:price>
      <g:sale_price>29.99 USD</g:sale_price>
      <g:availability>in stock</g:availability>
      <g:inventory>500</g:inventory>
      <g:condition>new</g:condition>
      <g:brand>Acme</g:brand>
      <g:gtin>012345678905</g:gtin>
      <g:mpn>ACME-CHG-65W</g:mpn>
      <g:google_product_category>Electronics > Electronics Accessories > Power</g:google_product_category>
      <g:product_type>Chargers > USB-C</g:product_type>
    </item>

    <!-- Grouped product: Phone Case in 3 variants -->
    <item>
      <g:id>CASE-BLK-14</g:id>
      <g:item_group_id>CASE-PRO</g:item_group_id>
      <title>ProShield Phone Case</title>
      <description>Military-grade drop protection phone case</description>
      <link>https://www.acme-electronics.com/products/proshield-case</link>
      <g:image_link>https://cdn.acme-electronics.com/images/case-black.jpg</g:image_link>
      <g:price>29.99 USD</g:price>
      <g:availability>in stock</g:availability>
      <g:inventory>200</g:inventory>
      <g:condition>new</g:condition>
      <g:brand>Acme</g:brand>
      <g:color>Black</g:color>
      <g:material>Polycarbonate</g:material>
      <g:gender>unisex</g:gender>
      <g:age_group>adult</g:age_group>
      <g:google_product_category>Electronics > Communications > Telephony > Mobile Phone Accessories > Mobile Phone Cases</g:google_product_category>
    </item>

    <item>
      <g:id>CASE-NAV-14</g:id>
      <g:item_group_id>CASE-PRO</g:item_group_id>
      <title>ProShield Phone Case</title>
      <description>Military-grade drop protection phone case</description>
      <link>https://www.acme-electronics.com/products/proshield-case</link>
      <g:image_link>https://cdn.acme-electronics.com/images/case-navy.jpg</g:image_link>
      <g:price>29.99 USD</g:price>
      <g:availability>in stock</g:availability>
      <g:inventory>150</g:inventory>
      <g:condition>new</g:condition>
      <g:brand>Acme</g:brand>
      <g:color>Navy</g:color>
      <g:material>Polycarbonate</g:material>
    </item>

    <item>
      <g:id>CASE-CLR-14</g:id>
      <g:item_group_id>CASE-PRO</g:item_group_id>
      <title>ProShield Phone Case</title>
      <description>Military-grade drop protection phone case</description>
      <link>https://www.acme-electronics.com/products/proshield-case</link>
      <g:image_link>https://cdn.acme-electronics.com/images/case-clear.jpg</g:image_link>
      <g:price>34.99 USD</g:price>
      <g:availability>in stock</g:availability>
      <g:inventory>75</g:inventory>
      <g:condition>new</g:condition>
      <g:brand>Acme</g:brand>
      <g:color>Clear</g:color>
      <g:material>TPU</g:material>
    </item>

  </channel>
</rss>
```

This feed produces:

* **Offer 1** (`CHARGER-USB-C`): Standalone charger, 1 SKU, sale price $29.99 (retail $39.99)
* **Offer 2** (`CASE-PRO`): Phone case group, 3 SKUs, variant "Color" (Black, Navy, Clear), variant "Material" (Polycarbonate, TPU), price range $29.99–$34.99

## Field-to-Platform Mapping Reference

This table shows how each XML field maps to the Violet platform's Offer and SKU models.

**Offer-level fields** (set from the first item in a group):

| XML Element                     | Offer Field              | Notes                                              |
| ------------------------------- | ------------------------ | -------------------------------------------------- |
| `<g:item_group_id>` or `<g:id>` | `external_id`            | Group ID if present, otherwise item ID             |
| `<title>`                       | `name`                   |                                                    |
| `<description>`                 | `description`            |                                                    |
| `<link>`                        | `external_url`           |                                                    |
| `<g:brand>`                     | `vendor`                 |                                                    |
| `<g:google_product_category>`   | `source_category_name`   | Priority over `product_type`                       |
| `<g:product_type>`              | `source_category_name`   | Fallback if no Google category                     |
| `<g:availability>`              | `available`              | `true` if "in stock" or "in\_stock"                |
| `<g:price>`                     | `min_price`, `max_price` | Aggregated across all SKUs in the group (in cents) |
| `<g:age_group>`                 | metadata `age_group`     | Stored as offer metadata                           |
| `<g:gender>`                    | metadata `gender`        | Stored as offer metadata                           |

**SKU-level fields** (set per item):

| XML Element        | SKU Field                    | Notes                                                                      |
| ------------------ | ---------------------------- | -------------------------------------------------------------------------- |
| `<g:id>`           | `external_id`                |                                                                            |
| `<title>`          | `name`                       |                                                                            |
| `<g:price>`        | `sale_price`, `retail_price` | Converted to cents. Both set to same value unless `sale_price` is provided |
| `<g:sale_price>`   | `sale_price`                 | Overrides `price` as sale\_price; `price` then becomes `retail_price` only |
| `<g:gtin>`         | `gtin`                       |                                                                            |
| `<g:mpn>`          | `upc`                        | Mapped to UPC field                                                        |
| `<g:inventory>`    | `qty_available`              | Enables `inventory_tracked = true`                                         |
| `<g:availability>` | `in_stock`                   | Fallback when no `inventory` or `stock` field                              |
| `<g:color>`        | variant value "Color"        |                                                                            |
| `<g:size>`         | variant value "Size"         |                                                                            |
| `<g:material>`     | variant value "Material"     |                                                                            |
| `<g:pattern>`      | variant value "Pattern"      |                                                                            |

## Unmapped Fields and SKU Metadata

The Google Product Feed specification includes fields beyond those listed above. Any additional Google Product Feed fields that do not have a one-to-one mapping to existing properties on the Violet Offer or SKU models are captured as metadata on each SKU.

For example, fields like `<g:shipping_weight>`, `<g:custom_label_0>`, or `<g:energy_efficiency_class>` do not map directly to a dedicated Offer or SKU property. Instead, they are stored as key-value metadata entries on the SKU, preserving the original field name as the key and the element's text content as the value.

This means you can include any valid Google Product Feed field in your XML and the data will not be lost — it will be accessible through the SKU's metadata collection even if it doesn't appear in the mapping tables above.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://merchant-help.violet.io/feeds/feeds-overview/xml-format-guide.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
