Exports & imports
Move whole catalogs as files: CSV, Excel, XML or JSON out — in your own column layout or a marketplace template — and spreadsheets or feeds in.
Exports
Describe the export in the body: format (csv, xlsx, xml, json), an optional product filter, fields (column keys, in order), options and optionally a channelId to use that channel's field mapping as a marketplace template.
Filter keys: q, ids, skus, status, types, categoryIds (category ids, subcategories included unless includeSubcategories: false), collectionIds, tags, brand, updatedSince, completenessMin, completenessMax, hasImages, topLevelOnly, channelId with channelStatus, and attributes. Lists are JSON arrays. An unknown key (in the body or the filter) answers 422 instead of being ignored, so a typo never exports the whole catalog by accident.
curl -X POST "https://library.retailcommerceai.com/api/v1/exports" \
-H "Authorization: Bearer cl_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"format": "xlsx",
"filter": {
"status": [
"approved"
],
"categoryIds": [
"cm1…"
]
},
"options": {
"includeTranslations": true,
"includeVariants": true,
"imageCount": 5
}
}'| Outcome | When |
|---|---|
| 200 with the file (Content-Disposition: attachment) | Up to 1,000 rows and no zipped images |
| 202 with a job | More rows, zipImages: true, or "async": true in the body |
Run a saved export with { "profileId": "…" } (fields you add override the saved settings). When an export job completes, links.download on the job points to the file; download it with the same API key (scope exports:read). Files are kept for 7 days.
curl -L "https://library.retailcommerceai.com/files/<workspace>/exports/<file>.xlsx?download=catalog.xlsx" \
-H "Authorization: Bearer cl_live_YOUR_API_KEY" -o catalog.xlsxOptions
| Option | Meaning |
|---|---|
locale | Content language of the main columns (default: the workspace default) |
includeTranslations | Add name.ar, description.ar … columns for every language |
includeVariants | Add variant rows after their parent (default true) |
includePrices | Add price.SAR, compare_at_price.SAR … columns |
currency | Show prices in this currency where the product has one |
imageCount | Number of image_N columns (default 10) |
delimiter | CSV delimiter: , ; tab or | |
Imports
Send the file as multipart/form-data in a file part. Without a mapping the columns are matched automatically — standard keys such as sku, name, price, category_path, attr.volume_ml, name.ar and common synonyms — and the mapping used comes back in the response. Options can be one JSON options part or separate fields.
curl -X POST "https://library.retailcommerceai.com/api/v1/imports" \
-H "Authorization: Bearer cl_live_YOUR_API_KEY" \
-F "file=@products.xlsx" \
-F 'options={"mode":"create_update","dryRun":false,"defaultStatus":"draft"}'| Option | Default | Meaning |
|---|---|---|
mode | create_update | create_only skips existing SKUs; update_only never creates |
dryRun | false | Validate every row and report, without saving |
defaultStatus | draft | Status of new products |
matchBy | sku | Match existing products by sku, gtin or mpn |
downloadImages | true | Download image URLs into the asset library |
createMissingCategories | true | Create categories from category_path |
createMissingOptions | true | Add unknown select values as new options |
clearEmptyCells | false | true: an empty cell clears the stored value |
sheet | first sheet | Excel sheet to read |
{
"data": {
"jobId": "cm1j0b…",
"job": {
"id": "cm1j0b…",
"type": "import",
"status": "queued",
"progress": 0,
"total": 0
},
"analysis": {
"fileName": "products.csv",
"format": "csv",
"rowCount": 1284,
"sheet": null,
"mapping": {
"Item code": "sku",
"Title EN": "name",
"Notes": "__ignore__"
}
}
}
}Poll GET /jobs/{jobId}: when it completes, result has counts (created, updated, unchanged, skipped, failed), the first issues, and links.report points to a CSV with every row issue.
Upload size on serverless hosting
- Parents must come before their variants in the file (parent_sku column).
- Imports never delete products; archive them with status instead.