curl --request POST \
--url https://api.merchantops.ai/api/products/import-json \
--header 'Content-Type: application/json' \
--data '
{
"products": [
{
"key": "<string>",
"productType": "<string>",
"isPublished": false,
"properties": {},
"properties_metadata": {},
"source": "merchant_input",
"variants": [
{
"key": "<string>",
"isPublished": false,
"properties": {},
"properties_metadata": {}
}
]
}
],
"batch_size": 25,
"enrich_product": true,
"ignore_manual_edits": false,
"merge_only_provided": false,
"scrape_brand_site": true,
"search_lakehouse": true,
"validate": false
}
'import requests
url = "https://api.merchantops.ai/api/products/import-json"
payload = {
"products": [
{
"key": "<string>",
"productType": "<string>",
"isPublished": False,
"properties": {},
"properties_metadata": {},
"source": "merchant_input",
"variants": [
{
"key": "<string>",
"isPublished": False,
"properties": {},
"properties_metadata": {}
}
]
}
],
"batch_size": 25,
"enrich_product": True,
"ignore_manual_edits": False,
"merge_only_provided": False,
"scrape_brand_site": True,
"search_lakehouse": True,
"validate": False
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
products: [
{
key: '<string>',
productType: '<string>',
isPublished: false,
properties: {},
properties_metadata: {},
source: 'merchant_input',
variants: [{key: '<string>', isPublished: false, properties: {}, properties_metadata: {}}]
}
],
batch_size: 25,
enrich_product: true,
ignore_manual_edits: false,
merge_only_provided: false,
scrape_brand_site: true,
search_lakehouse: true,
validate: false
})
};
fetch('https://api.merchantops.ai/api/products/import-json', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.merchantops.ai/api/products/import-json",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'products' => [
[
'key' => '<string>',
'productType' => '<string>',
'isPublished' => false,
'properties' => [
],
'properties_metadata' => [
],
'source' => 'merchant_input',
'variants' => [
[
'key' => '<string>',
'isPublished' => false,
'properties' => [
],
'properties_metadata' => [
]
]
]
]
],
'batch_size' => 25,
'enrich_product' => true,
'ignore_manual_edits' => false,
'merge_only_provided' => false,
'scrape_brand_site' => true,
'search_lakehouse' => true,
'validate' => false
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.merchantops.ai/api/products/import-json"
payload := strings.NewReader("{\n \"products\": [\n {\n \"key\": \"<string>\",\n \"productType\": \"<string>\",\n \"isPublished\": false,\n \"properties\": {},\n \"properties_metadata\": {},\n \"source\": \"merchant_input\",\n \"variants\": [\n {\n \"key\": \"<string>\",\n \"isPublished\": false,\n \"properties\": {},\n \"properties_metadata\": {}\n }\n ]\n }\n ],\n \"batch_size\": 25,\n \"enrich_product\": true,\n \"ignore_manual_edits\": false,\n \"merge_only_provided\": false,\n \"scrape_brand_site\": true,\n \"search_lakehouse\": true,\n \"validate\": false\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.merchantops.ai/api/products/import-json")
.header("Content-Type", "application/json")
.body("{\n \"products\": [\n {\n \"key\": \"<string>\",\n \"productType\": \"<string>\",\n \"isPublished\": false,\n \"properties\": {},\n \"properties_metadata\": {},\n \"source\": \"merchant_input\",\n \"variants\": [\n {\n \"key\": \"<string>\",\n \"isPublished\": false,\n \"properties\": {},\n \"properties_metadata\": {}\n }\n ]\n }\n ],\n \"batch_size\": 25,\n \"enrich_product\": true,\n \"ignore_manual_edits\": false,\n \"merge_only_provided\": false,\n \"scrape_brand_site\": true,\n \"search_lakehouse\": true,\n \"validate\": false\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.merchantops.ai/api/products/import-json")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"products\": [\n {\n \"key\": \"<string>\",\n \"productType\": \"<string>\",\n \"isPublished\": false,\n \"properties\": {},\n \"properties_metadata\": {},\n \"source\": \"merchant_input\",\n \"variants\": [\n {\n \"key\": \"<string>\",\n \"isPublished\": false,\n \"properties\": {},\n \"properties_metadata\": {}\n }\n ]\n }\n ],\n \"batch_size\": 25,\n \"enrich_product\": true,\n \"ignore_manual_edits\": false,\n \"merge_only_provided\": false,\n \"scrape_brand_site\": true,\n \"search_lakehouse\": true,\n \"validate\": false\n}"
response = http.request(request)
puts response.read_body{
"created": 123,
"failed": 123,
"total": 123,
"errors": [
{}
],
"job_id": "<string>",
"skipped": 0,
"variants_created": 0
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>",
"ctx": {},
"input": "<unknown>"
}
]
}Import Json
Import products from JSON.
Authentication Required: Requires product:write permission.
Accepts a JSON body with a products array. Each product specifies
a key, productType, and a properties dict with arbitrary property values.
Maximum 250 products per request. Creates a Job to track the batch operation.
curl --request POST \
--url https://api.merchantops.ai/api/products/import-json \
--header 'Content-Type: application/json' \
--data '
{
"products": [
{
"key": "<string>",
"productType": "<string>",
"isPublished": false,
"properties": {},
"properties_metadata": {},
"source": "merchant_input",
"variants": [
{
"key": "<string>",
"isPublished": false,
"properties": {},
"properties_metadata": {}
}
]
}
],
"batch_size": 25,
"enrich_product": true,
"ignore_manual_edits": false,
"merge_only_provided": false,
"scrape_brand_site": true,
"search_lakehouse": true,
"validate": false
}
'import requests
url = "https://api.merchantops.ai/api/products/import-json"
payload = {
"products": [
{
"key": "<string>",
"productType": "<string>",
"isPublished": False,
"properties": {},
"properties_metadata": {},
"source": "merchant_input",
"variants": [
{
"key": "<string>",
"isPublished": False,
"properties": {},
"properties_metadata": {}
}
]
}
],
"batch_size": 25,
"enrich_product": True,
"ignore_manual_edits": False,
"merge_only_provided": False,
"scrape_brand_site": True,
"search_lakehouse": True,
"validate": False
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
products: [
{
key: '<string>',
productType: '<string>',
isPublished: false,
properties: {},
properties_metadata: {},
source: 'merchant_input',
variants: [{key: '<string>', isPublished: false, properties: {}, properties_metadata: {}}]
}
],
batch_size: 25,
enrich_product: true,
ignore_manual_edits: false,
merge_only_provided: false,
scrape_brand_site: true,
search_lakehouse: true,
validate: false
})
};
fetch('https://api.merchantops.ai/api/products/import-json', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.merchantops.ai/api/products/import-json",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'products' => [
[
'key' => '<string>',
'productType' => '<string>',
'isPublished' => false,
'properties' => [
],
'properties_metadata' => [
],
'source' => 'merchant_input',
'variants' => [
[
'key' => '<string>',
'isPublished' => false,
'properties' => [
],
'properties_metadata' => [
]
]
]
]
],
'batch_size' => 25,
'enrich_product' => true,
'ignore_manual_edits' => false,
'merge_only_provided' => false,
'scrape_brand_site' => true,
'search_lakehouse' => true,
'validate' => false
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.merchantops.ai/api/products/import-json"
payload := strings.NewReader("{\n \"products\": [\n {\n \"key\": \"<string>\",\n \"productType\": \"<string>\",\n \"isPublished\": false,\n \"properties\": {},\n \"properties_metadata\": {},\n \"source\": \"merchant_input\",\n \"variants\": [\n {\n \"key\": \"<string>\",\n \"isPublished\": false,\n \"properties\": {},\n \"properties_metadata\": {}\n }\n ]\n }\n ],\n \"batch_size\": 25,\n \"enrich_product\": true,\n \"ignore_manual_edits\": false,\n \"merge_only_provided\": false,\n \"scrape_brand_site\": true,\n \"search_lakehouse\": true,\n \"validate\": false\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.merchantops.ai/api/products/import-json")
.header("Content-Type", "application/json")
.body("{\n \"products\": [\n {\n \"key\": \"<string>\",\n \"productType\": \"<string>\",\n \"isPublished\": false,\n \"properties\": {},\n \"properties_metadata\": {},\n \"source\": \"merchant_input\",\n \"variants\": [\n {\n \"key\": \"<string>\",\n \"isPublished\": false,\n \"properties\": {},\n \"properties_metadata\": {}\n }\n ]\n }\n ],\n \"batch_size\": 25,\n \"enrich_product\": true,\n \"ignore_manual_edits\": false,\n \"merge_only_provided\": false,\n \"scrape_brand_site\": true,\n \"search_lakehouse\": true,\n \"validate\": false\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.merchantops.ai/api/products/import-json")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"products\": [\n {\n \"key\": \"<string>\",\n \"productType\": \"<string>\",\n \"isPublished\": false,\n \"properties\": {},\n \"properties_metadata\": {},\n \"source\": \"merchant_input\",\n \"variants\": [\n {\n \"key\": \"<string>\",\n \"isPublished\": false,\n \"properties\": {},\n \"properties_metadata\": {}\n }\n ]\n }\n ],\n \"batch_size\": 25,\n \"enrich_product\": true,\n \"ignore_manual_edits\": false,\n \"merge_only_provided\": false,\n \"scrape_brand_site\": true,\n \"search_lakehouse\": true,\n \"validate\": false\n}"
response = http.request(request)
puts response.read_body{
"created": 123,
"failed": 123,
"total": 123,
"errors": [
{}
],
"job_id": "<string>",
"skipped": 0,
"variants_created": 0
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>",
"ctx": {},
"input": "<unknown>"
}
]
}Cookies
Body
Request model for JSON product import.
List of products to import
Show child attributes
Show child attributes
Batch size for processing
1 <= x <= 50Run AI enrichment
When True, do NOT preserve properties flagged properties_metadata.{key}.manual_edit — the incoming values win. Default False keeps the manual-edit protection. Intended for a deliberate authoritative resync where the source of truth is external; protect specific fields by omitting them from the payload instead.
When True, overlay ONLY the provided properties onto each existing product's latest version, preserving all other fields. Ignored when enrichment is requested.
Scrape brand website during enrichment
Search product lakehouse for existing data
Validate against ProductType
Response
Successful Response
Response model for batch product creation.
Number successfully created
Number that failed
Total products submitted
List of errors
Show child attributes
Show child attributes
Job ID for tracking batch progress
Number unchanged (no new version created)
Number of variants created/updated from variant rows