Skip to main content
POST
/
api
/
v2
/
apps
/
{app_id}
/
batch
/
products
/
upsert_by_sku
curl -X POST "https://ecommerce.jelou.ai/api/v2/apps/{app_id}/batch/products/upsert_by_sku" \
  -H "Authorization: Bearer <API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "resources": [
      {
        "sku": "TSHIRT-BLU",
        "name": "Basic Blue T-Shirt",
        "description": "100% premium cotton t-shirt, regular fit",
        "price": 29.99,
        "has_tax": true,
        "status": true,
        "stock_type": "limited",
        "stock": 150,
        "product_url": "https://my-store.com/basic-blue-tshirt",
        "discount_type": "percentage",
        "discount": 10,
        "branch": "BRANCH-DOWNTOWN",
        "categories": ["Clothing", "T-Shirts"],
        "images": [
          "https://my-store.com/images/blue-tshirt-front.jpg",
          "https://my-store.com/images/blue-tshirt-back.jpg"
        ],
        "variations": [
          {
            "sku": "TSHIRT-BLU-S",
            "price": 29.99,
            "attributes": [
              { "name": "Size", "value": "S" },
              { "name": "Color", "value": "Blue" }
            ]
          },
          {
            "sku": "TSHIRT-BLU-M",
            "price": 29.99,
            "attributes": [
              { "name": "Size", "value": "M" },
              { "name": "Color", "value": "Blue" }
            ]
          },
          {
            "sku": "TSHIRT-BLU-L",
            "price": 31.99,
            "attributes": [
              { "name": "Size", "value": "L" },
              { "name": "Color", "value": "Blue" }
            ],
            "images": [
              "https://my-store.com/images/blue-tshirt-L.jpg"
            ]
          }
        ]
      },
      {
        "sku": "PANTS-BLK-M",
        "name": "Black Pants",
        "price": 49.99,
        "branch": "BRANCH-NORTH",
        "categories": ["Clothing", "Pants"]
      },
      {
        "sku": "PIZZA-FAMILY",
        "name": "Family Pepperoni Pizza",
        "description": "Family-size pepperoni pizza with artisan crust",
        "price": 18.99,
        "stock_type": "unlimited",
        "branch": "BRANCH-NORTH",
        "categories": ["Pizzas", "Promotions"],
        "images": ["https://example.com/pepperoni-pizza.jpg"],
        "modifier_groups": [
          {
            "code": "drinks",
            "name": "Choose your Drink",
            "min_quantity": 1,
            "max_quantity": 1,
            "is_required": true,
            "options": [
              { "code": "coca-1l", "name": "Coca Cola 1L", "price": 0 },
              { "code": "sprite-1l", "name": "Sprite 1L", "price": 0 },
              { "code": "fanta-1l", "name": "Fanta 1L", "price": 0.50 }
            ]
          },
          {
            "code": "extras",
            "name": "Extra Toppings",
            "min_quantity": 0,
            "max_quantity": 5,
            "max_per_option": 2,
            "is_required": false,
            "options": [
              { "code": "extra-cheese", "name": "Extra Cheese", "price": 1.50 },
              { "code": "ham", "name": "Ham", "price": 2.00 },
              { "code": "olives", "name": "Olives", "price": 1.00 }
            ]
          }
        ]
      }
    ]
  }'
{
  "message": "Batch upsert process initiated successfully",
  "count": 3,
  "jobs": 3
}
You can create or update products in bulk by their SKU. If a product with the specified SKU already exists, it is updated; otherwise, it is created. Products can be assigned to a branch, have multiple variations, and modifier groups.
app_id
string
required
Your store ID in Jelou Shop.
resources
object[]
required
List of products to create or update (max. 500 per request).

Product fields

Each object within resources accepts the following fields:
sku
string
required
Unique product identifier (max. 255 characters).
name
string
required
Product name (max. 255 characters).
price
number
required
Product price (min. 0).
description
string
Product description.
has_tax
boolean
default:"true"
Indicates whether the price includes taxes.
status
boolean
default:"true"
Product status (active/inactive).
stock_type
string
default:"unlimited"
Inventory type: limited or unlimited.
stock
number
Available quantity. Applies only when stock_type is limited.
product_url
string
URL of the product in your store (max. 2048 characters).
discount_type
string
Discount type: value (fixed amount) or percentage.
discount
number
Discount value (min. 0).
categories
string[]
List of category names. They are created automatically if they do not exist.
images
string[]
List of public image URLs for the product.
branch
string
Code of the branch to which the product is assigned. The branch must already exist.
The branch must be created before assigning it to a product. Use the Create branch endpoint to register it first.
variations
object[]
List of product variations.
modifier_groups
object[]
Product modifier groups (add-ons). Common in food delivery (e.g., “Choose your Drinks”, “Pick your Sauces”). If the field is absent, existing modifiers are preserved. If it is an empty array [], all modifiers are deleted. If it has data, modifiers are completely replaced.
Modifiers are stored on the product and returned automatically in all endpoints that return products.

Full example

This example creates three products: a t-shirt with size variations, a simple pair of pants, and a pizza with modifier groups.
curl -X POST "https://ecommerce.jelou.ai/api/v2/apps/{app_id}/batch/products/upsert_by_sku" \
  -H "Authorization: Bearer <API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "resources": [
      {
        "sku": "TSHIRT-BLU",
        "name": "Basic Blue T-Shirt",
        "description": "100% premium cotton t-shirt, regular fit",
        "price": 29.99,
        "has_tax": true,
        "status": true,
        "stock_type": "limited",
        "stock": 150,
        "product_url": "https://my-store.com/basic-blue-tshirt",
        "discount_type": "percentage",
        "discount": 10,
        "branch": "BRANCH-DOWNTOWN",
        "categories": ["Clothing", "T-Shirts"],
        "images": [
          "https://my-store.com/images/blue-tshirt-front.jpg",
          "https://my-store.com/images/blue-tshirt-back.jpg"
        ],
        "variations": [
          {
            "sku": "TSHIRT-BLU-S",
            "price": 29.99,
            "attributes": [
              { "name": "Size", "value": "S" },
              { "name": "Color", "value": "Blue" }
            ]
          },
          {
            "sku": "TSHIRT-BLU-M",
            "price": 29.99,
            "attributes": [
              { "name": "Size", "value": "M" },
              { "name": "Color", "value": "Blue" }
            ]
          },
          {
            "sku": "TSHIRT-BLU-L",
            "price": 31.99,
            "attributes": [
              { "name": "Size", "value": "L" },
              { "name": "Color", "value": "Blue" }
            ],
            "images": [
              "https://my-store.com/images/blue-tshirt-L.jpg"
            ]
          }
        ]
      },
      {
        "sku": "PANTS-BLK-M",
        "name": "Black Pants",
        "price": 49.99,
        "branch": "BRANCH-NORTH",
        "categories": ["Clothing", "Pants"]
      },
      {
        "sku": "PIZZA-FAMILY",
        "name": "Family Pepperoni Pizza",
        "description": "Family-size pepperoni pizza with artisan crust",
        "price": 18.99,
        "stock_type": "unlimited",
        "branch": "BRANCH-NORTH",
        "categories": ["Pizzas", "Promotions"],
        "images": ["https://example.com/pepperoni-pizza.jpg"],
        "modifier_groups": [
          {
            "code": "drinks",
            "name": "Choose your Drink",
            "min_quantity": 1,
            "max_quantity": 1,
            "is_required": true,
            "options": [
              { "code": "coca-1l", "name": "Coca Cola 1L", "price": 0 },
              { "code": "sprite-1l", "name": "Sprite 1L", "price": 0 },
              { "code": "fanta-1l", "name": "Fanta 1L", "price": 0.50 }
            ]
          },
          {
            "code": "extras",
            "name": "Extra Toppings",
            "min_quantity": 0,
            "max_quantity": 5,
            "max_per_option": 2,
            "is_required": false,
            "options": [
              { "code": "extra-cheese", "name": "Extra Cheese", "price": 1.50 },
              { "code": "ham", "name": "Ham", "price": 2.00 },
              { "code": "olives", "name": "Olives", "price": 1.00 }
            ]
          }
        ]
      }
    ]
  }'
{
  "message": "Batch upsert process initiated successfully",
  "count": 3,
  "jobs": 3
}
Replace {app_id} with your store ID and <API_KEY> with the token provided by Jelou.

Behavior

The endpoint returns 202 Accepted immediately. Products are processed in the background.
If the branch code does not match any branch in the store, the product is created without a branch assignment. No error is produced.
If a category does not exist, it is created automatically within the store and the corresponding branch.
Images are downloaded and processed in the background after the product is created.
Variations are identified by their SKU. If a variation with that SKU already exists, it is updated instead of creating a new one.
If modifier_groups is absent in the payload, existing modifiers are preserved. If it is an empty array [], all modifiers are deleted. If it has data, modifiers are completely replaced.

Validation errors

If the data does not meet the validation rules, the API responds with 422 and details the fields with errors.
{
  "message": "The resources field is required.",
  "errors": {
    "resources": ["The resources field is required."]
  }
}
FieldMessage
resourcesAt least one product is required.
resourcesCannot process more than 500 products at once.
resources.*.skuEach product must have a SKU.
resources.*.nameEach product must have a name.
resources.*.priceEach product must have a price. / Price cannot be negative.
resources.*.stock_typeStock type must be either limited or unlimited.
resources.*.images.*Each image must be a valid URL.
resources.*.modifier_groups.*.codeEach modifier group must have a code.
resources.*.modifier_groups.*.nameEach modifier group must have a name.
resources.*.modifier_groups.*.optionsEach modifier group must have at least one option.
resources.*.modifier_groups.*.options.*.codeEach modifier option must have a code.
resources.*.modifier_groups.*.options.*.nameEach modifier option must have a name.

Limits

  • Maximum 500 products per request.
  • All products are validated before being processed.