Upload a product catalog to an ecommerce connector. The catalog must be a JSON array of product objects. There are two upload modes:
Single-file upload — POST a single catalog file (up to 99 MB per request). Omit finalize and import_job_id. Returns 202 Accepted when sync has started.
Multipart upload — For catalogs that must be split across multiple requests:
- POST the first part with
finalize=false(noimport_job_id). The response returns animport_job_idandnext_part_number. - POST each subsequent part with
finalize=false, theimport_job_idfrom step 1, and thepart_numberfrom the previous response. Each part must be ≤ 99 MB. - POST with
finalize=trueand theimport_job_idto complete the upload and start the sync. No catalog file is required in the finalization request.
Part uploads are idempotent — retrying the same part_number does not create a duplicate. If a response is lost, retry with the same part_number.
The catalog file must be a JSON array where each element is a product object. Only id, title, and url are required — all other fields are optional.
| Field | Type | Required | Description |
|---|---|---|---|
id | string | ✓ | Your unique product identifier. Used to match products on re-upload so only changed products are re-indexed. Also the delete key — any product ID absent from a new upload is removed from Fin's knowledge. Must be stable across uploads. |
title | string | ✓ | Product name. Used by Fin when searching for and recommending products. |
url | string | ✓ | Canonical product page URL shown in Fin's product recommendations. Must be a valid https:// URL. |
description | string | Product description that Fin reads to understand what the product is. HTML formatting is supported and safely sanitized (description_html takes precedence if both are provided). This is the primary field Fin uses to match products to shopper questions — a richer description leads to better recommendations. | |
featured_image_url | string | Primary product image shown in Fin's recommendation cards. Falls back to the first entry of image_urls if not provided. If no valid image can be resolved for a variant, that variant's card is not shown to the shopper. | |
image_urls | string[] | Additional product images. Used as a fallback when featured_image_url is absent or when a variant has no specific image. | |
price_min | number | Lowest price across all variants. If omitted, derived automatically from variant prices. Fin uses this to filter products when a shopper mentions a budget (e.g. "under $100"). Displayed as a range alongside price_max, or as a single value if both are equal. | |
price_max | number | Highest price across all variants. If omitted, derived from variant prices. Used alongside price_min for budget filtering and price display. | |
currency | string | ISO 4217 currency code (e.g. "USD", "EUR", "GBP"). Defaults to USD if omitted. Used to format prices with the correct symbol in Fin's responses and product cards. | |
in_stock | boolean | Whether the product is available to purchase. If omitted, derived from variant stock — the product is in stock if at least one variant has in_stock: true. Products with no in-stock variants are hidden from Fin entirely. | |
category_path | string or string[] | Strongly recommended | Hierarchical category breadcrumb (e.g. ["Clothing", "Outerwear", "Jackets"]). Fin understands the hierarchy — a shopper asking about "Clothing" sees products from all subcategories underneath it. The most specific category is shown in search results. |
collections | string[] | Strongly recommended | Collections or groupings this product belongs to in your store. Fin uses collections to understand your catalog's structure and answer questions like "what's in the sale collection?". |
tags | string[] | Free-form keywords matching how shoppers phrase needs in chat (e.g. ["waterproof", "gift", "plus-size"]). Complements category_path and collections. | |
available_options | object[] | Option types and their possible values (e.g. {"name": "Size", "values": ["S", "M", "L"]}). Fin uses these to understand what choices a shopper can make and to correctly filter variants when asked for a specific size, colour, or other attribute. | |
additional_data | object | Custom attributes for your business. Fin uses these to show each customer only relevant products. All keys must be consistent across all products in your catalog — the attribute schema is read from the first product in the file. | |
variants | object[] | Individual purchasable variants. Fin recommends specific variants (not just products), so populating variants with accurate stock, price, and option data leads to more precise recommendations. See the variant table below. |
Each object in the variants array may contain:
| Field | Type | Required | Description |
|---|---|---|---|
id | string | ✓ | Unique identifier for this variant within the product. |
title | string | Variant display name shown to shoppers (e.g. "Small / Blue"). | |
price | number | Price of this specific variant. Fin uses variant prices for precise budget filtering and displays the variant price in recommendation cards. | |
compare_at_price | number | Original price before a discount. When provided, Fin will naturally mention the saving (e.g. "down from $129 to $99"). | |
in_stock | boolean | Whether this variant is currently available. Out-of-stock variants are not shown in Fin's recommendation cards and Fin will not suggest them to shoppers. | |
image_url | string | Image specific to this variant. Takes precedence over the product's featured_image_url. Falls back to featured_image_url, then image_urls. If no valid image can be resolved, this variant's recommendation card will not be shown. | |
selected_options | object[] | The specific option values that define this variant (e.g. [{"name": "Size", "value": "Small"}, {"name": "Color", "value": "Blue"}]). Fin uses these to match shopper requests like "do you have this in medium?" to the correct variant. | |
url | string | Direct link to this variant's page. Takes precedence over the product URL in recommendation cards. If omitted, constructed automatically as {product_url}?variant={id}. |
[
{
"id": "prod-12345",
"title": "Classic Cotton T-Shirt",
"url": "https://example.com/products/classic-cotton-t-shirt",
"description": "A comfortable everyday t-shirt.",
"featured_image_url": "https://cdn.example.com/images/t-shirt.jpg",
"price_min": 19.99,
"price_max": 29.99,
"currency": "USD",
"in_stock": true,
"tags": ["organic", "bestseller"],
"collections": ["Summer Collection"],
"category_path": "Clothing > T-Shirts",
"available_options": [
{"name": "Size", "values": ["S", "M", "L"]},
{"name": "Color", "values": ["White", "Blue"]}
],
"variants": [
{
"id": "var-001",
"title": "S / White",
"price": 19.99,
"in_stock": true,
"selected_options": [
{"name": "Size", "value": "S"},
{"name": "Color", "value": "White"}
]
},
{
"id": "var-002",
"title": "M / Blue",
"price": 29.99,
"in_stock": true,
"selected_options": [
{"name": "Size", "value": "M"},
{"name": "Color", "value": "Blue"}
]
}
],
"additional_data": {
"sku": "TSHIRT-WHT-S",
"vendor": "Acme Apparel"
}
}
]Preview Intercom API version. Used for closed beta endpoints or other features under managed availability.
The catalog JSON file. Required for all requests except finalization (finalize=true). Must be a valid JSON array of product objects. Max 99 MB.
Each element in the array must conform to the ecommerce_catalog_product schema. The id, title, and url fields are required on every product; all other fields are optional. Variants, if provided, must conform to the ecommerce_catalog_variant schema.
Set to true to finalize a multipart upload session and start the catalog sync. No catalog file is required when finalizing. Set to false to upload a part in a multipart session. Omit entirely for a single-file upload.
The import job ID returned from the first multipart upload request. Required when uploading subsequent parts (part_number ≥ 2) and when finalizing a multipart session (finalize=true).
- The production API serverhttps://api.intercom.io/ecommerce/connectors/{id}/catalog
- The european API serverhttps://api.eu.intercom.io/ecommerce/connectors/{id}/catalog
- The australian API serverhttps://api.au.intercom.io/ecommerce/connectors/{id}/catalog
- Single-file upload
- Multipart — Step 1: First part
- Multipart — Step 2: Append part
- Multipart — Step 3: Finalize
curl -i -X POST \
https://api.intercom.io/ecommerce/connectors/42939/catalog \
-H 'Authorization: Bearer <YOUR_TOKEN_HERE>' \
-H 'Content-Type: multipart/form-data' \
-H 'Intercom-Version: preview' \
-F catalog=@products.jsonMultipart catalog part uploaded successfully.
{ "import_job_id": "job_01abc123", "next_part_number": 2 }