Upload Base Products Xlsx
curl --request POST \
--url https://api.merchantops.ai/api/products/upload-base-xlsx \
--header 'Content-Type: multipart/form-data' \
--form 'file=<string>' \
--form batch_size=25 \
--form merge_only_provided=falseimport requests
url = "https://api.merchantops.ai/api/products/upload-base-xlsx"
payload = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"batch_size\"\r\n\r\n25\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"merge_only_provided\"\r\n\r\nfalse\r\n-----011000010111000001101001--"
headers = {"Content-Type": "multipart/form-data"}
response = requests.post(url, data=payload, headers=headers)
print(response.text)const form = new FormData();
form.append('file', '<string>');
form.append('batch_size', '25');
form.append('merge_only_provided', 'false');
const options = {method: 'POST'};
options.body = form;
fetch('https://api.merchantops.ai/api/products/upload-base-xlsx', 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/upload-base-xlsx",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"batch_size\"\r\n\r\n25\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"merge_only_provided\"\r\n\r\nfalse\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Content-Type: multipart/form-data"
],
]);
$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/upload-base-xlsx"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"batch_size\"\r\n\r\n25\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"merge_only_provided\"\r\n\r\nfalse\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
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/upload-base-xlsx")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"batch_size\"\r\n\r\n25\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"merge_only_provided\"\r\n\r\nfalse\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.merchantops.ai/api/products/upload-base-xlsx")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"batch_size\"\r\n\r\n25\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"merge_only_provided\"\r\n\r\nfalse\r\n-----011000010111000001101001--"
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>"
}
]
}Products
Upload Base Products Xlsx
Upload base products (and variants) from an XLSX file — the round-trip export edited in Excel. Text cells preserve long UPCs/SKUs verbatim.
Requires product:write. Same variant-capable format as the CSV
upload; never enriches (a pure data round-trip). merge_only_provided
overlays only the provided columns onto existing products/variants.
POST
/
api
/
products
/
upload-base-xlsx
Upload Base Products Xlsx
curl --request POST \
--url https://api.merchantops.ai/api/products/upload-base-xlsx \
--header 'Content-Type: multipart/form-data' \
--form 'file=<string>' \
--form batch_size=25 \
--form merge_only_provided=falseimport requests
url = "https://api.merchantops.ai/api/products/upload-base-xlsx"
payload = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"batch_size\"\r\n\r\n25\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"merge_only_provided\"\r\n\r\nfalse\r\n-----011000010111000001101001--"
headers = {"Content-Type": "multipart/form-data"}
response = requests.post(url, data=payload, headers=headers)
print(response.text)const form = new FormData();
form.append('file', '<string>');
form.append('batch_size', '25');
form.append('merge_only_provided', 'false');
const options = {method: 'POST'};
options.body = form;
fetch('https://api.merchantops.ai/api/products/upload-base-xlsx', 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/upload-base-xlsx",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"batch_size\"\r\n\r\n25\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"merge_only_provided\"\r\n\r\nfalse\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Content-Type: multipart/form-data"
],
]);
$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/upload-base-xlsx"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"batch_size\"\r\n\r\n25\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"merge_only_provided\"\r\n\r\nfalse\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
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/upload-base-xlsx")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"batch_size\"\r\n\r\n25\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"merge_only_provided\"\r\n\r\nfalse\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.merchantops.ai/api/products/upload-base-xlsx")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"batch_size\"\r\n\r\n25\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"merge_only_provided\"\r\n\r\nfalse\r\n-----011000010111000001101001--"
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
multipart/form-data
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
⌘I