# /productData Batch upsert or delete product catalog records in LoudCrowd. Aligns with the supported file formats documented in the LoudCrowd developer docs. # Send Product Data **POST** `/product-data` Batch upsert or delete product catalog records in LoudCrowd. Aligns with the supported file formats documented in the LoudCrowd developer docs. This API is designed to mirror the ingestion pipeline currently used for file-based product loads so that existing mappings can be reused. ## Headers | Header | Required | Description | | ----------------- | -------- | ------------------------------------------------------------------------------------------------ | | `Authorization` | Yes | Bearer token for authentication | | `X-LC-SHOP-ID` | Yes | Your LoudCrowd internal shop identifier | | `X-Signature` | Yes | The SHA-256 hexadecimal digest of the UTF-8 encoded JSON payload | | `X-LC-TOPIC` | Yes | Specifies the operation to apply to the provided products (`PRODUCT_UPSERT` or `PRODUCT_DELETE`) | | `Content-Type` | Yes | Must be `application/json` | | `Idempotency-Key` | Yes | A unique identifier for the request (UUID format recommended) | ## Request Body ```json { "products": [ { "platform_product_id": "PROD-001", "parent_id": "PROD-001", "position": 0, "title": "Summer T-Shirt", "brand": "YourBrand", "active": true, "product_url": "https://store.com/products/prod-001", "image_src": "https://store.com/images/prod-001.jpg", "language": "en", "country": "US", "list_price": 29.99, "sale_price": 24.99, "currency_code": "USD", "availability": "in stock", "allowed_regions": ["US", "CA"], "variants": [ { "variant_sku": "PROD-001-RED-M", "parent_id": "PROD-001", "position": 1, "title": "Summer T-Shirt - Red Medium", "product_url": "https://store.com/products/prod-001?color=red&size=m", "image_src": "https://store.com/images/prod-001-red.jpg", "list_price": 29.99, "sale_price": 24.99, "currency_code": "USD", "availability": "in stock", "allowed_regions": ["US", "CA"], "option1_name": "Color", "option1_value": "Red", "option1_swatch_src": "https://store.com/swatches/red.jpg", "option2_name": "Size", "option2_value": "Medium", "prices": [ { "list_price": 29.99, "sale_price": 24.99, "currency_code": "USD", "allowed_region": "US" }, { "list_price": 39.99, "sale_price": 32.99, "currency_code": "CAD", "allowed_region": "CA" } ] } ] } ] } ``` ### Request Schema | Field | Type | Required | Description | | ---------- | ----- | -------- | ----------------------------------------------------------- | | `products` | Array | Yes | Batch of product records to upsert or delete (1-1000 items) | #### Product Record Schema | Field | Type | Required | Description | | --------------------- | ------- | -------- | --------------------------------------------------------------------- | | `platform_product_id` | String | Yes | Unique product identifier from the eCommerce platform | | `parent_id` | String | Yes | ID of the parent product (same as product_id for standalone products) | | `position` | Integer | No | Display order for variants (0 for parent products) | | `title` | String | Yes | Product title | | `brand` | String | No | Brand name | | `active` | Boolean | No | Whether product is active/available (Y/N) | | `product_url` | String | No | Product PDP URL | | `image_src` | String | No | Primary product image URL | | `language` | String | No | Locale language (ISO 639-1 alpha2 format) | | `country` | String | No | Locale region (ISO 3166-1 alpha2 format) | | `list_price` | Number | No | Regular price of the product | | `sale_price` | Number | No | Currently discounted price | | `currency_code` | String | No | Currency code (ISO 4217 format) | | `availability` | String | No | Stock status ("in stock" or "out of stock") | | `allowed_regions` | Array | No | Selling regions where product is available | | `variants` | Array | No | List of product variants (max 250) | #### Product Variant Schema | Field | Type | Required | Description | | -------------------- | ------- | -------- | ------------------------------------------------ | | `variant_sku` | String | Yes | Variant SKU (acts as external key) | | `parent_id` | String | Yes | ID of the parent product | | `position` | Integer | No | Display order for this variant | | `title` | String | No | Variant-specific title | | `product_url` | String | No | Variant PDP URL | | `image_src` | String | No | Variant-specific image URL | | `list_price` | Number | No | Regular price of the variant | | `sale_price` | Number | No | Currently discounted price | | `currency_code` | String | No | Currency code (ISO 4217 format) | | `availability` | String | No | Stock status ("in stock" or "out of stock") | | `allowed_regions` | Array | No | Selling regions where variant is available | | `option1_name` | String | No | Name of the 1st variant option (e.g., "Color") | | `option1_value` | String | No | Value of the 1st variant option (e.g., "Red") | | `option1_swatch_src` | String | No | URL for the 1st option's swatch image | | `option2_name` | String | No | Name of the 2nd variant option (e.g., "Size") | | `option2_value` | String | No | Value of the 2nd variant option (e.g., "Medium") | | `option2_swatch_src` | String | No | URL for the 2nd option's swatch image | | `option3_name` | String | No | Name of the 3rd variant option | | `option3_value` | String | No | Value of the 3rd variant option | | `option3_swatch_src` | String | No | URL for the 3rd option's swatch image | | `prices` | Array | No | Multiple prices per region/currency (see below) | #### Variant Price Schema | Field | Type | Required | Description | | ---------------- | ------ | -------- | ----------------------------------------- | | `list_price` | Number | No | Regular price for this region/currency | | `sale_price` | Number | No | Discounted price for this region/currency | | `currency_code` | String | No | Currency code (ISO 4217 format) | | `allowed_region` | String | No | Selling region this price applies to | ## Responses ### Success Response (200) ```json { "success": true, "message": "Product data processed", "processedCount": 123 } ``` **Headers:** - `X-RateLimit-Limit`: Total requests allowed in the current window - `X-RateLimit-Remaining`: Requests remaining in the current window - `X-RateLimit-Reset`: Unix epoch seconds when the current window resets ### Validation Error Response (422) ```json { "code": 422, "message": "Unprocessable Entity", "recordErrors": [ { "index": 0, "field": "products[0].platform_product_id", "code": "REQUIRED", "message": "platform_product_id is required" }, { "index": 1, "field": "products[1].title", "code": "INVALID_FORMAT", "message": "title must be a non-empty string" } ] } ``` ### Rate Limit Response (429) ```json { "code": 429, "message": "Rate Limit Exceeded" } ``` **Headers:** - `X-RateLimit-Limit`: Total requests allowed in the current window - `X-RateLimit-Remaining`: Requests remaining in the current window - `X-RateLimit-Reset`: Unix epoch seconds when the current window resets - `Retry-After`: Seconds until the next request may be made ### Error Responses | Status | Description | | ------ | --------------------------------------------------------------- | | `400` | Bad Request - Invalid data provided | | `401` | Unauthorized - Invalid authentication | | `403` | Forbidden - Invalid API key | | `404` | Not Found - Resource doesn't exist | | `422` | Unprocessable Entity - Validation errors for individual records | | `429` | Too Many Requests - Rate limit exceeded | | `500` | Internal Server Error | | `503` | Service Unavailable | ## Examples ### Upsert Products ```bash curl -X POST https://api.loudcrowd.com/product-data \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "X-LC-SHOP-ID: your-shop-id" \ -H "X-Signature: sha256-hash-of-payload" \ -H "X-LC-TOPIC: PRODUCT_UPSERT" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: a1b2c3d4-e5f6-7890-1234-567890abcdef" \ -d '{ "products": [ { "platform_product_id": "PROD-001", "parent_id": "PROD-001", "position": 0, "title": "Summer T-Shirt", "brand": "YourBrand", "active": true, "product_url": "https://store.com/products/prod-001", "image_src": "https://store.com/images/prod-001.jpg", "list_price": 29.99, "sale_price": 24.99, "currency_code": "USD", "availability": "in stock", "allowed_regions": ["US", "CA"], "variants": [ { "variant_sku": "PROD-001-RED-M", "parent_id": "PROD-001", "position": 1, "product_url": "https://store.com/products/prod-001?color=red&size=m", "list_price": 29.99, "sale_price": 24.99, "currency_code": "USD", "availability": "in stock", "allowed_regions": ["US", "CA"], "option1_name": "Color", "option1_value": "Red", "option2_name": "Size", "option2_value": "Medium", "prices": [ { "list_price": 29.99, "sale_price": 24.99, "currency_code": "USD", "allowed_region": "US" }, { "list_price": 39.99, "sale_price": 32.99, "currency_code": "CAD", "allowed_region": "CA" } ] } ] } ] }' ``` ### Delete Products ```bash curl -X POST https://api.loudcrowd.com/product-data \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "X-LC-SHOP-ID: your-shop-id" \ -H "X-Signature: sha256-hash-of-payload" \ -H "X-LC-TOPIC: PRODUCT_DELETE" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: b2c3d4e5-f6g7-8901-2345-678901bcdefg" \ -d '{ "products": [ { "platform_product_id": "PROD-001", "parent_id": "PROD-001", "title": "Summer T-Shirt" } ] }' ``` ## Notes - **Multiple Regions**: Use `allowed_regions` array to specify which regions a product/variant is available in - **Multiple Prices**: Use the `prices` array in variants to specify different prices per region/currency - **Variant Options**: Support up to 3 variant options (option1, option2, option3) with names, values, and swatch images - **Translations**: Use `language` and `country` fields for localized content - **Position**: Use `position` field to control display order of variants - **Parent-Child Relationship**: Use `parent_id` to group variants under parent products - For delete operations, only `platform_product_id`, `parent_id`, and `title` are required - Idempotency keys should be unique per request and can be reused for retries - Rate limits are shared across all endpoints for an account ## Alignment with File-Based Ingestion This API is designed to mirror the [file-based product ingestion format](https://intercom.help/loudcrowd-developer-docs/en/articles/9294595-send-product-data-to-loudcrowd) to ensure compatibility with existing product data mappings. The JSON structure maps directly to the CSV fields used in the SFTP-based ingestion system. # OpenAPI definition ```json { "info": { "title": "LoudCrowd API", "version": "0.0.0", "description": "This API provides access to LoudCrowd's Creator Storefronts and Attribution Events functionality. The Creator Storefronts API is used in place of the creator storefront web-components, and the Attribution Events API enables submission of order and return data for commission calculation.\n", "license": { "name": "MIT", "url": "https://opensource.org/licenses/MIT" } }, "openapi": "3.0.0", "servers": [ { "url": "https://store-api.loudcrowd.com/api", "description": "LoudCrowd Creator Storefronts API" }, { "url": "https://api.loudcrowd.com", "description": "LoudCrowd Attribution Events API" } ], "x-readme": { "explorer-enabled": false }, "paths": { "/product-data": { "post": { "summary": "Send Product Data", "description": "Batch upsert or delete product catalog records in LoudCrowd. Aligns with the supported file formats documented in the LoudCrowd developer docs. This API is designed to mirror the ingestion pipeline currently used for file-based product loads so that existing mappings can be reused.", "operationId": "send_product_data", "parameters": [ { "in": "header", "name": "X-LC-SHOP-ID", "description": "Your LoudCrowd internal shop identifier", "required": true, "schema": { "type": "string" } }, { "in": "header", "name": "X-Signature", "description": "The SHA-256 hexadecimal digest of the UTF-8 encoded JSON payload", "required": true, "schema": { "type": "string" } }, { "in": "header", "name": "X-LC-TOPIC", "description": "Specifies the operation to apply to the provided products", "required": true, "schema": { "type": "string", "enum": [ "PRODUCT_UPSERT", "PRODUCT_DELETE" ] } }, { "in": "header", "name": "Content-Type", "description": "Content type of the request", "required": true, "schema": { "type": "string", "default": "application/json" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": [ "products" ], "properties": { "products": { "type": "array", "description": "Batch of product records to upsert or delete.", "minItems": 1, "maxItems": 1000, "items": { "type": "object", "description": "Product payload aligned with file-based ingestion formats. Use nulls for clearing optional values.", "required": [ "platform_product_id", "title" ], "properties": { "platform_product_id": { "type": "string", "description": "Unique product identifier from the eCommerce platform" }, "handle": { "type": "string", "description": "Product handle or slug" }, "title": { "type": "string", "description": "Product title" }, "brand": { "type": "string", "nullable": true, "description": "Brand name" }, "image_src": { "type": "string", "nullable": true, "description": "Primary product image URL" }, "product_url": { "type": "string", "nullable": true, "description": "Product PDP URL" }, "active": { "type": "boolean", "description": "Whether product is active/available" }, "in_stock": { "type": "boolean", "nullable": true, "description": "Inventory availability flag" }, "price_currency_code": { "enum": [ "USD", "CAD", "GBP", "AUD", "AED", "AFN", "ALL", "AMD", "ANG", "AOA", "ARS", "AWG", "AZN", "BAM", "BBD", "BDT", "BGN", "BHD", "BIF", "BMD", "BND", "BOB", "BOV", "BRL", "BSD", "BTN", "BWP", "BYN", "BZD", "CDF", "CHE", "CHF", "CHW", "CLF", "CLP", "CNY", "COP", "COU", "CRC", "CUC", "CUP", "CVE", "CZK", "DJF", "DKK", "DOP", "DZD", "EGP", "ERN", "ETB", "EUR", "FJD", "FKP", "GEL", "GHS", "GIP", "GMD", "GNF", "GTQ", "GYD", "HKD", "HNL", "HRK", "HTG", "HUF", "IDR", "ILS", "INR", "IQD", "IRR", "ISK", "JMD", "JOD", "JPY", "KES", "KGS", "KHR", "KMF", "KPW", "KRW", "KWD", "KYD", "KZT", "LAK", "LBP", "LKR", "LRD", "LSL", "LYD", "MAD", "MDL", "MGA", "MKD", "MMK", "MNT", "MOP", "MRU", "MUR", "MVR", "MWK", "MXN", "MXV", "MYR", "MZN", "NAD", "NGN", "NIO", "NOK", "NPR", "NZD", "OMR", "PAB", "PEN", "PGK", "PHP", "PKR", "PLN", "PYG", "QAR", "RON", "RSD", "RUB", "RWF", "SAR", "SBD", "SCR", "SDG", "SEK", "SGD", "SHP", "SLE", "SLL", "SOS", "SRD", "SSP", "STN", "SVC", "SYP", "SZL", "THB", "TJS", "TMT", "TND", "TOP", "TRY", "TTD", "TWD", "TZS", "UAH", "UGX", "USN", "UYI", "UYU", "UYW", "UZS", "VED", "VES", "VND", "VUV", "WST", "XAF", "XAG", "XAU", "XBA", "XBB", "XBC", "XBD", "XCD", "XDR", "XOF", "XPD", "XPF", "XPT", "XSU", "XTS", "XUA", "XXX", "YER", "ZAR", "ZMW", "ZWL" ], "type": "string", "description": "The currency code of the product prices.", "example": "USD", "nullable": true, "x-readme-ref-name": "priceCurrencyCode" }, "prices": { "properties": { "discountedPriceRanges": { "description": "List of the discounted price ranges for the product.", "items": { "properties": { "discount": { "properties": { "id": { "type": "string" } }, "type": "object" }, "range": { "properties": { "max": { "type": "number" }, "min": { "type": "number" } }, "type": "object" } }, "type": "object" }, "type": "array", "maxItems": 10 }, "discountedPrices": { "description": "List of the discounted prices for the product.", "items": { "properties": { "discount": { "properties": { "id": { "type": "string" } }, "type": "object" }, "price": { "type": "number" } }, "type": "object" }, "type": "array", "maxItems": 10 }, "price": { "description": "The price of the product.", "type": "number", "nullable": true }, "priceRange": { "description": "The price range of the product.", "properties": { "max": { "type": "number" }, "min": { "type": "number" } }, "type": "object", "nullable": true }, "promotionalPrice": { "description": "If there is a site wide promotion applied to the product data, the promotional price of the product.", "type": "number", "nullable": true }, "promotionalPriceRange": { "description": "If there is a site wide promotion applied to the product data, the promotional price range of the product.", "properties": { "max": { "type": "number" }, "min": { "type": "number" } }, "type": "object", "nullable": true }, "salePrice": { "description": "The sale price of the product.", "type": "number", "nullable": true }, "salePriceRange": { "description": "The sale price range of the product.", "properties": { "max": { "type": "number" }, "min": { "type": "number" } }, "type": "object", "nullable": true } }, "type": "object", "nullable": true, "x-readme-ref-name": "productPrices" }, "promotional_code": { "type": "string", "nullable": true, "description": "Applied sitewide promo code, if any" }, "collections": { "type": "array", "nullable": true, "description": "Optional list of collection identifiers the product belongs to", "items": { "type": "string" }, "maxItems": 250 }, "tags": { "type": "array", "nullable": true, "description": "Optional list of product tags", "items": { "type": "string" }, "maxItems": 250 }, "variants": { "type": "array", "nullable": true, "description": "Optional list of product variants", "items": { "type": "object", "required": [ "variant_sku" ], "properties": { "variant_sku": { "type": "string", "description": "Variant SKU (acts as external key)" }, "price": { "type": "number", "nullable": true, "description": "Variant price" }, "sale_price": { "type": "number", "nullable": true, "description": "Variant sale price" }, "product_url": { "type": "string", "nullable": true, "description": "Variant PDP URL" }, "selected_options": { "type": "array", "nullable": true, "description": "Key/value option selections like Size/Color", "items": { "properties": { "name": { "description": "The name of the selected option.", "type": "string", "example": "Color", "nullable": true }, "value": { "description": "The value of the selected option.", "type": "string", "example": "Red", "nullable": true } }, "type": "object", "x-readme-ref-name": "selectedOptionItem" }, "maxItems": 100 } }, "x-readme-ref-name": "productVariantIngestRecord" }, "maxItems": 250 } }, "x-readme-ref-name": "productIngestRecord" } } }, "x-readme-ref-name": "sendProductDataRequest" } } } }, "responses": { "200": { "description": "Request accepted and processed", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "example": true }, "message": { "type": "string", "example": "Product data processed" }, "processedCount": { "type": "integer", "example": 123 } } } } } }, "400": { "description": "Request is missing or has a bad parameter.", "content": { "application/json": { "schema": { "type": "object", "properties": { "code": { "type": "integer", "example": 400 }, "message": { "type": "string", "example": "Bad Request" } } } } } }, "401": { "description": "Key is valid, but the account does not have permissions to perform this action.", "content": { "application/json": { "schema": { "type": "object", "properties": { "code": { "type": "integer", "example": 401 }, "message": { "type": "string", "example": "Not Authorized" } } } } } }, "422": { "description": "Validation failed for one or more product records.", "content": { "application/json": { "schema": { "type": "object", "properties": { "code": { "type": "integer", "example": 422 }, "message": { "type": "string", "example": "Unprocessable Entity" }, "recordErrors": { "type": "array", "description": "Per-record validation errors", "items": { "type": "object", "properties": { "index": { "type": "integer", "description": "Zero-based index of the product in the payload", "example": 0 }, "field": { "type": "string", "description": "JSON pointer or field path", "example": "products[0].platform_product_id" }, "code": { "type": "string", "description": "Machine-readable error code", "example": "REQUIRED" }, "message": { "type": "string", "description": "Human readable error", "example": "platform_product_id is required" } }, "required": [ "index", "code", "message" ] } } } } } } }, "429": { "description": "You hit the rate limit for this account. All endpoints share the same rate limit for an account.", "headers": { "X-RateLimit-Limit": { "schema": { "type": "integer" }, "description": "Total requests allowed in the current window" }, "X-RateLimit-Remaining": { "schema": { "type": "integer" }, "description": "Requests remaining in the current window" }, "X-RateLimit-Reset": { "schema": { "type": "integer" }, "description": "Unix epoch seconds when the current window resets" }, "Retry-After": { "schema": { "type": "integer" }, "description": "Seconds until the next request may be made" } }, "content": { "application/json": { "schema": { "type": "object", "properties": { "code": { "type": "integer", "example": 429 }, "message": { "type": "string", "example": "Rate Limit Exceeded" } } } } } }, "500": { "description": "Something is wrong on LoudCrowd's end.", "content": { "application/json": { "schema": { "type": "object", "properties": { "code": { "type": "integer", "example": 500 }, "message": { "type": "string", "example": "Server Error" } } } } } } } } } }, "security": [ { "bearerAuth": [] } ], "components": { "securitySchemes": { "bearerAuth": { "type": "http", "scheme": "bearer", "description": "Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"" } } } } ```