Add New Products in a Nested Format

Prev Next

The Catalog API allows you to insert new items into your product catalog in a nested format. It creates new product records. If a product with the same item_id + locale already exists, it will be overwritten.

Endpoint and Headers

POST https://catalog.api.useinsider.com/v2/ingest/nested

Header

Sample Value

Description

X-PARTNER-NAME

myParterName

This is your partner name. Navigate to InOne > Inone Settings > Account Settings to copy your partner name. The partner name should be lowercase.

X-REQUEST-TOKEN

1a2b3c4d5e6f

This key is required to authorize your request. Refer to API Authentication Tokens to generate your Catalog API token.

Body Parameters

Default Product Attributes

The following product fields should be sent as parameters in the object, along with their field name and data type, as stated. If any required fields are not sent through the Catalog API, the product is not updated or inserted.

Field Name

Description

Data Type

Required

item_id

Unique product identifier. Max 128 characters.

String

Yes

locale

ISO locale code (e.g., en_US, pt_BR). Max 64 characters.

String

Yes

name

Product name. Max 512 characters.

String

Yes

url

Product page URL. Must include protocol (e.g., https://). Max 512 characters.

String

Yes

image_url

Product image URL. Must start with http://, https://, or //.

String

Yes

price

Current selling price per currency. e.g., {"USD": 100, "BRL": 500}.

Object

Required for Stock & Revenue Feed Management Type

original_price

Original/list price per currency. Same structure as price.

Object

Required for Stock & Revenue Feed Management Type

omnibus_price

Omnibus directive price per currency. Same structure as price.

Object

No

in_stock

1 = in stock, 0 = out of stock.

Number

Required for Stock & Revenue and Availability Feed Management Types

stock_count

Available quantity. Must be >= 0.

Number

No

item_update_date

Last update timestamp. Format: YYYY-MM-DD hh:mm:ss

String

Required for Published Time Feed Management Type

item_start_date

Availability start date. Format: YYYY-MM-DD hh:mm:ss

String

Required for Start & End Time Feed Management Type

item_end_date

Availability end date. Format: YYYY-MM-DD hh:mm:ss

String

Required for Start & End Time Feed Management Type

description

Product description. Max 1024 characters.

String

No

brand

Brand name. Max 512 characters.

String

No

sku

Stock keeping unit. Max 512 characters.

String

No

color

Product color. Max 512 characters.

String

No

size

Product size. Max 512 characters.

String

No

gender

Gender classification. Max 512 characters.

String

No

category

Category as an array

String[]

No

tags

Product tags

String[]

No

groupcode

Product group identifier

String

No

variants

Product variants. Max 512 characters per item.

String[]

No

rating

Product rating, 0–10

Number

No

product_attributes

Custom attributes defined in your account.

Object {key:value}

No

is_status_passive

1 = passive/hidden in Smart Recommender and Eureka results, 0 = active.

Number

No

Custom Product Attributes

Custom Product Attributes allow you to define additional details specific to your business. These attributes enrich your catalog with data that supports your unique use cases, personalization logic, and recommendation filters.

Before sending Custom Product Attributes in your payload, you must define them in your account.

If a Default Product Attribute already exists for the information you want to include, use the default one instead of creating a custom one. This keeps your catalog structure consistent.

Custom attributes are sent inside the product_attributes object:

{
  "item_id": "velocity-runner-pro-white",
  "locale": "en_US",
  "name": "Velocity Runner Pro - White",
  "product_attributes": {
    "material_type": "Leather",
    "season": "Winter",
    "eco_friendly": "True",
    "collection": "Winter Collection 2025",
    "delivery_type": "Express"
  }
}

Feed Management Types

Your feed management type determines which pricing and stock attributes are required.

The Stock and Revenue Based feed management type is the most common type. It requires pricing and stock information.

curl --request POST "https://catalog.api.useinsider.com/v2/ingest" \
  --header "Content-Type: application/json" \
  --header "X-PARTNER-NAME: yourPartnerName" \
  --header "X-REQUEST-TOKEN: your-api-token" \
  --data '[
    {
      "item_id": "velocity-runner-pro-white",
      "locale": "en_US",
      "name": "Velocity Runner Pro - White",
      "url": "https://www.example-insiderone.com/shoes/velocity-runner-pro-white",
      "image_url": "https://cdn.example-insiderone.com/images/velocity-runner-pro-white.jpg",
      "category": [
        "Shoes",
        "Running",
        "Velox"
      ],
      "brand": "Velox",
      "price": {
        "USD": 129.99
      },
      "original_price": {
        "USD": 149.99
      },
      "in_stock": 1
    }
  ]'

For the Availability Based feed management type, only the stock status is required. Pricing is optional.

curl --request POST "https://catalog.api.useinsider.com/v2/ingest" \
  --header "Content-Type: application/json" \
  --header "X-PARTNER-NAME: yourPartnerName" \
  --header "X-REQUEST-TOKEN: your-api-token" \
  --data '[
    {
      "item_id": "velocity-runner-pro-white",
      "locale": "en_US",
      "name": "Velocity Runner Pro - White",
      "url": "https://www.example-insiderone.com/shoes/velocity-runner-pro-white",
      "image_url": "https://cdn.example-insiderone.com/images/velocity-runner-pro-white.jpg",
      "in_stock": 1
    }
  ]'

The Published Time Based feed management type requires an update timestamp instead of pricing.

curl --request POST "https://catalog.api.useinsider.com/v2/ingest" \
  --header "Content-Type: application/json" \
  --header "X-PARTNER-NAME: yourPartnerName" \
  --header "X-REQUEST-TOKEN: your-api-token" \
  --data '[
    {
      "item_id": "blog-top-running-shoes-2025",
      "locale": "en_US",
      "name": "Top 10 Running Shoes for 2025",
      "url": "https://www.example-insiderone.com/blog/top-running-shoes-2025",
      "image_url": "https://cdn.example-insiderone.com/images/blog/running-shoes-2025.jpg",
      "item_update_date": "2025-01-15 10:30:00"
    }
  ]'

The Start & End Time Based feed management type requires date range attributes for time-bound content.

curl --request POST "https://catalog.api.useinsider.com/v2/ingest" \
  --header "Content-Type: application/json" \
  --header "X-PARTNER-NAME: yourPartnerName" \
  --header "X-REQUEST-TOKEN: your-api-token" \
  --data '[
    {
      "item_id": "promo-summer-clearance-2025",
      "locale": "en_US",
      "name": "Summer Clearance Sale - Up to 50% Off",
      "url": "https://www.example-insiderone.com/campaigns/summer-clearance-2025",
      "image_url": "https://cdn.example-insiderone.com/images/campaigns/summer-clearance.jpg",
      "item_start_date": "2025-06-01 00:00:00",
      "item_end_date": "2025-08-31 23:59:59"
    }
  ]'

Product Availability by Feed Management Type

A product is considered available based on criteria that vary by feed management type:

Feed Type

Availability Condition

Stock & Revenue Based

in_stock must be 1

Availability Based

in_stock must be 1

Published Time Based

item_update_date must be within the last 2 days (default 2 days, adjustable in Smart Recommender campaigns)

Start & End Time Based

item_end_date must not be in the past

Attribute Specifications

Pricing attributes accept an object mapping currency codes to amounts. You can include multiple currencies in a single record.

{
  "price": {
    "USD": 129.99,
    "EUR": 119.99,
    "GBP": 104.99,
    "BRL": 899.90
  },
  "original_price": {
    "USD": 149.99,
    "EUR": 139.99,
    "GBP": 119.99,
    "BRL": 999.90
  }
}
  • Currency codes must contain only letters (e.g., USD, EUR, BRL).

  • Amounts must be >= 0.

The category attribute accepts an array of strings. How the array is interpreted depends on your account's category type, which is configured during onboarding.

  • Hierarchical Category Type

Use this if your categories follow a parent-child structure, with subcategories nested under broader categories. Each element in the array represents a level in the hierarchy, ordered from broadest to most specific.

{
  "category": ["Clothing", "Men", "Shirts", "Casual Shirts"]
}

This creates the hierarchy: Clothing → Men → Shirts → Casual Shirts.

The order matters; the first element is the top-level category, and each subsequent element is a child of the previous one.

Limits:

  • Combined length of all category elements: max 1024 characters.

  • Each element: max 512 characters.

Tags are used for product grouping and merchandising rules within the Insider One platform.

{
 "tags": ["new-arrival", "bestseller", "summer-collection", "free-shipping"]
                    }

You can use tags to:

  • Create product segments for personalization

  • Trigger merchandising rules

  • Filter products in recommendation widgets

  • Define campaign audiences

Limits:

  • Combined length of all tags: max 4096 characters

  • Each tag: max 512 characters

The groupcode attribute links product variants together as a single product group. Products sharing the same groupcode are treated as variations of the same product (e.g., different sizes or colors).

[
  {
    "item_id": "velocity-runner-pro-white",
    "groupcode": "velocity-runner-pro",
    "color": "White",
    "size": "10"
  },
  {
    "item_id": "velocity-runner-pro-black",
    "groupcode": "velocity-runner-pro",
    "color": "Black",
    "size": "10"
  }
]

Sample Request

The sample below displays a request to insert new products using a nested format. Shared fields go in base, locale-specific fields go in locales, and store overrides go in stores.

Use nested format when you have multiple locales or stores per product. Shared fields like url, image_url, and brand are defined once and inherited by all locales/stores, reducing payload size and repetition.

The following example is equivalent to the flat format: the same product, locales, and stores, but expressed as a single nested object instead of 4 separate records:

curl --request POST "https://catalog.api.useinsider.com/v2/ingest/nested" \
  --header "Content-Type: application/json" \
  --header "X-PARTNER-NAME: your-partner-name" \
  --header "X-REQUEST-TOKEN: your-api-token" \
  --data '[
    {
      "item_id": "velocity-runner-pro-white",
      "base": {
        "url": "https://www.example-insiderone.com/shoes/velocity-runner-pro-white",
        "image_url": "https://cdn.example-insiderone.com/images/velocity-runner-pro-white.jpg",
        "brand": "Velox",
        "groupcode": "velocity-runner-pro",
        "color": "White"
      },
      "locales": {
        "en_US": {
          "name": "Velocity Runner Pro - White",
          "category": [
            "Shoes",
            "Running",
            "Velox"
          ],
          "price": {
            "USD": 129.99
          },
          "original_price": {
            "USD": 149.99
          },
          "stores": {
            "main": {
              "in_stock": 1,
              "stock_count": 50
            },
            "newyork": {
              "price": {
                "USD": 119.99
              },
              "in_stock": 1,
              "stock_count": 12
            },
            "losangeles": {
              "in_stock": 0,
              "stock_count": 0
            }
          }
        },
        "pt_BR": {
          "name": "Velocity Runner Pro - Branco",
          "category": [
            "Calçados",
            "Corrida",
            "Velox"
          ],
          "price": {
            "BRL": 899.90
          },
          "original_price": {
            "BRL": 999.90
          },
          "stores": {
            "main": {
              "in_stock": 1,
              "stock_count": 30
            }
          }
        }
      }
    }
  ]'

Understanding the field inheritance

In nested format, the same field can be defined at multiple levels (base, locale, store). The Catalog API merges these into a final record using this priority:

store fields > locale fields > base fields

This allows you to define shared values once in the base and only override the differences at each level.

Example: In the request above, en_US defines price: USD 129.99 at the locale level. The newyork store overrides this with price: USD 119.99, while losangeles inherits the locale price since it doesn't define its own:

locale

name

price

in_stock

stock_count

en_US

Velocity Runner Pro - White

USD 129.99

1

50

en_US:newyork

Velocity Runner Pro - White

USD 119.99 (overridden)

1

12

en_US:losangeles

Velocity Runner Pro - White

USD 129.99 (inherited)

0

0

pt_BR

Velocity Runner Pro - Branco

BRL 899.90

1

30

Restrictions

Store Attributes

In the nested payload structure, fields can be defined at three levels:

base          → Shared across all locales and stores
locales       → Locale-specific (name, category, etc.)
  └─ stores   → Store-specific overrides (pricing and stock only)

Only the following fields are allowed at the store level:

  • price

  • original_price

  • omnibus_price

  • in_stock

  • stock_count

Including any other field at the store level returns a 400 error.

Example: A valid nested payload with store-level overrides:

{
  "item_id": "SKU-123",
  "base": {
    "url": "https://example.com/product/SKU-123",
    "image_url": "https://cdn.example.com/SKU-123.jpg",
    "brand": "Acme"
  },
  "locales": {
    "en_US": {
      "name": "Example Product",
      "category": ["Electronics"],
      "price": { "USD": 99.99 },
      "original_price": { "USD": 119.99 },
      "in_stock": 1,
      "stores": {
        "main": {
          "stock_count": 100
        },
        "outlet": {
          "price": { "USD": 79.99 },
          "in_stock": 1,
          "stock_count": 25
        }
      }
    }
  }
}

This produces two records:

  • en_US with price USD 99.99 and stock_count 100

  • en_US:outlet with price USD 79.99 and stock_count 25

Main Store

The main key is a reserved store identifier that represents the default/locale-level record. Unlike other store keys, it does not append a suffix to the locale string. For example, "main" under en_US produces a record with locale en_US, while "newyork" produces en_US:newyork.

This is useful when you want to define a base price/stock for the locale itself alongside store-specific overrides. If you use main without any other stores, the result is the same as not using stores at all.

Sample Response

All ingest endpoints return the same response structure:

{
  "success": true,
  "message": {
    "valid": {
      "count": 95
    },
    "invalid": {
      "count": 5,
      "details": [
        {
          "field": "original_price",
          "message": "Field is invalidated: 'original_price' is required",
          "count": 2,
          "document_ids": ["item-1", "item-2"]
        },
        {
          "field": "url",
          "message": "Field is invalidated: 'url' must match pattern",
          "count": 3,
          "document_ids": ["item-3", "item-4", "item-5"]
        }
      ]
    },
    "warnings": {
      "count": 1,
      "details": [
        {
          "field": "image_url",
          "message": "Image URL could not be validated",
          "count": 1,
          "document_ids": ["item-6"]
        }
      ]
    },
    "invalidRatio": 0.05
  }
}

Warnings are informational and do not prevent records from being processed.

Limitations

For all the limits applied, refer to Limitations.