Importing resources
How to bulk import resources and their relationships
Commerce Layer lets you import multiple resources in batches. To do that, you need to create a new import resource, specify the resource_type you want to import, and populate the inputs attribute with a JSON (default) or CSV list of items. Each element of the inputs list (which is an array of objects for JSON and a string for CSV) contains the resource attributes and relationships (at least the ones required for the specific resource to be created).
When importing a CSV list of items you also need to flatten the resource attributes and relationships on a single line. The headers for the attributes of a relationship must be prepended by the associated resource name (see example). When importing tags together with a tagged resource the elements related to the tags.id and tags.name headers can contain a string with the list of IDs/names, comma separated (see example). In general, using CSV is fine for simple imports (resources with a few attributes and no relationship included), otherwise we strongly recommend using JSON to ensure better readability in terms of inputs list.
The process is asynchronous and you can poll the status attribute to check the import progress. Once the import has been completed you can check the number of imported items by inspecting the processed_count attribute. In case of validation errors, the errors_count and errors_log attributes are populated.
Some automations normally triggered on resources' creation or update (e.g. webhooks, callbacks, and most event-driven communications) might not be enabled when using imports. Read here for more information.
Attachment URL
When an import is started, the data you pass within the inputs list is validated, compressed (gzip), and then uploaded to an external storage service (currently Amazon S3). You can download the imported data using the link exposed in the attachment_url attribute, which is populated as soon as the import is completed.
Import limits
Maximum import size
There is no limit on the total number of resources you can import, but the single batches are subject to some soft limits: the inputs array must contain a maximum of 10000 items, otherwise the import will be rejected at the time of creation.
Maximum error percentage
During the import process, the errors count is also monitored: imports whose errors_count attribute value overflows the maximum percentage of 10% of the total import size (i.e. the number of items contained in the inputs array) will be interrupted.
Concurrent imports
The maximum number of concurrent imports (i.e. imports whose status is pending or in_progess) allowed per organization is 10.
Supported resources
At the moment, imports are available for the following resources (more to come):
Addresses
Bundles
Coupons
Customer addresses
Customer payment sources
Customer subscriptions
Customers
Gift cards
Line items
Line item options
Orders
Price tiers
Prices
Shipping categories
SKU list items
SKU lists
SKU options
SKUs
Stock items
Stock transfers
Tags
Tax categories
Please find some examples of how to import them here below.
Exporting resourcesUnique keys
In order to detect if a resource already exists the id key is checked for each inputs array element. Some resources also support specific (combined) attributes to identify an existing record, which can be helpful in case the resource ID isn't known during the import process:
Bundles —
code+market_idCoupons —
code+promotion_rule_idCustomer addresses —
customer_idCustomer subscriptions —
customer_id+referenceCustomers —
emailGift cards —
codeOrders —
numberPrices —
sku_code+price_list_idShipping categories —
nameSKU options —
name+currency_codeSKUs —
codeStock items —
sku_code+stock_location_idTags —
nameTax categories —
code+tax_calculator_id
In case both the specific unique key and the id are passed, the latter is used to identify existing records to be updated. This way is possible to modify the value of the specific unique key with a new one (i.e. changing the code of an SKU or the number of an order). Keep in mind that in this case every entry of the inputs array must have the id key, otherwise the specific key is used to identify the record and the import result could not be as expected (e.g. new records could be created instead of updating existing ones).
Specifying the parent resource
If the resources you're importing refer to the same parent resource (e.g. prices to the same price list), you can avoid repeating its value on each inputs items by specifying the parent_resource_id attribute. In case you specify both the parent resource ID and the relationship ID for each item, the latter wins. These are the supported parent resources:
Bundles —
market_idCoupons —
promotion_rule_idCustomer payment sources —
payment_method_idGift cards —
market_idOrders —
market_idPrices —
price_list_idSKU list items —
sku_list_idSKU options —
market_idStock items —
stock_location_idTax categories —
tax_calculator_id
Disabled automations
Webhooks
Excluding those associated with order status change events (orders.place, orders.approve, orders.cancel, orders.authorize, orders.void, orders.pay, orders.refund, orders.start_fulfilling, orders.cancel_fulfilling, and orders.fulfill), during imports all of the real-time webhooks are disabled.
In case you need to leverage all the other real-time events you have to create/update resources via the related API endpoints.
After-save callbacks
All of the resource's after-save callbacks are not executed on imports. This means that some attributes dependent on such callbacks will not be persisted (i.e. timestamps after status change or numbers set with the ID value).
In case you need to run after-save callbacks you have to make standard CRUD actions via the related API endpoints.
Cleaning-up records
If you need to remove some resources and their associated relationships before or after importing new ones we suggest leveraging the cleanups endpoint, making sure to use a valid filter and include the necessary relationships.
Examples
Importing a list of addresses (CSV)
The following request creates an import with a list of addresses in CSV format:
curl -g -X POST \
'https://yourdomain.commercelayer.io/api/imports' \
-H 'Accept: application/vnd.api+json' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/vnd.api+json' \
-d '{
"data": {
"type": "imports",
"attributes": {
"resource_type": "addresses",
"format": "csv",
"inputs": "first_name,last_name,company,line_1,city,zip_code,state_code,country_code,phone,email\nGeorge,Harrison,The Beatles,Viale Borgo Valsugana 93,Prato,59100,PO,IT,+39 0574 933550,[email protected]\n"
}
}
}'For a list of all the required attributes you need to create an address, refer to the related section of the API reference.
Importing a list of bundles (JSON)
The following request creates an import with a list of bundles in JSON format:
curl -g -X POST \
'https://yourdomain.commercelayer.io/api/imports' \
-H 'Accept: application/vnd.api+json' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/vnd.api+json' \
-d '{
"data": {
"type": "imports",
"attributes": {
"resource_type": "bundles",
"parent_resource_id": "bgOEQhznoZ",
"inputs": [
{
"code":"FWOUTFIT",
"name":"FW outfit",
"image_url":"https://img.yourdomain.com/bundles/FWOUTFIT.png",
"reference": "FWOUTFIT",
"sku_list_id": "GHYfrWszHp"
},
{
"code":"SSOUTFIT",
"name":"SS outfit",
"image_url":"https://img.yourdomain.com/bundles/SSOUTFIT.png",
"reference": "SSOUTFIT",
"sku_list_id": "GHYfrWszHp"
},
{ ... }
]
}
}
}'For a list of all the required attributes you need to create a bundle, refer to the related section of the API reference.
Importing a list of coupons (CSV)
The following request creates an import with a list of coupons in CSV format and clean-up the ones existing for the same promotion rule:
curl -g -X POST \
'https://yourdomain.commercelayer.io/api/imports' \
-H 'Accept: application/vnd.api+json' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/vnd.api+json' \
-d '{
"data": {
"type": "imports",
"attributes": {
"resource_type": "coupons",
"format": "csv",
"parent_resource_id": "FreQKlNxZA",
"inputs": "code,customer_single_use,usage_limit,usage_count,recipient_email\n11111111,false,,0,\n22222222,false,,0,\n33333333,false,,0,[email protected]\n"
}
}
}'For a list of all the required attributes you need to create a coupon, refer to the related section of the API reference.
Importing a list of customer addresses (JSON)
The following request creates an import with a list of customer addresses in JSON format (the associated address can be either specified by ID if existing or created if not existing):
curl -g -X POST \
'https://yourdomain.commercelayer.io/api/imports' \
-H 'Accept: application/vnd.api+json' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/vnd.api+json' \
-d '{
"data": {
"type": "imports",
"attributes": {
"resource_type": "customer_addresses",
"inputs": [
{
"customer_email": "[email protected]",
"address_id": "gHbVCxZSdE"
},
{
"customer_email": "[email protected]",
"address": {
"first_name": "Mario",
"last_name": "Rossi",
"line_1": "Viale Borgo Valsugana 7",
"city": "Prato",
"zip_code": "59100",
"state_code": "PO",
"country_code": "IT",
"phone": "+39 0574 933550"
}
},
{ ... }
]
}
}
}'Importing a list of customer payment sources (JSON)
The following request creates an import with a list of customer payment sources in JSON format (you must always provide the customer_token and payment_source_token you've got from your payment gateway):
curl -g -X POST \
'https://yourdomain.commercelayer.io/api/imports' \
-H 'Accept: application/vnd.api+json' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/vnd.api+json' \
-d '{
"data": {
"type": "imports",
"attributes": {
"resource_type": "customer_payment_sources",
"parent_resource_id": "hgTfDcXXzs",
"inputs": [
{
"customer_token": "255203791",
"payment_source_token: "5f8k2cr",
"customer_id": "hGdEwsAqlK"
},
{
"customer_token": "255265209",
"payment_source_token: "6gh02cz",
"customer_id": "jHgfTTrcVn"
},
{ ... }
]
}
}
}'For a list of all the required attributes you need to create a customer payment sources, refer to the related section of the API reference.
Importing a list of customer subscriptions (JSON)
The following request creates an import with a list of customer subscriptions in JSON format:
curl -g -X POST \
'https://yourdomain.commercelayer.io/api/imports' \
-H 'Accept: application/vnd.api+json' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/vnd.api+json' \
-d '{
"data": {
"type": "imports",
"attributes": {
"resource_type": "customer_subscriptions",
"inputs": [
{
"customer_email": "[email protected]",
"reference": "Marketing newsletter"
},
{
"customer_email": "[email protected]",
"reference": "Whitepaper download"
},
{ ... }
]
}
}
}'For a list of all the required attributes you need to create a customer subscription, refer to the related section of the API reference.
Importing a list of customers (CSV)
The following request creates an import with a list of customers in CSV format:
curl -g -X POST \
'https://yourdomain.commercelayer.io/api/imports' \
-H 'Accept: application/vnd.api+json' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/vnd.api+json' \
-d '{
"data": {
"type": "imports",
"attributes": {
"resource_type": "customers",
"format": "csv",
"inputs": "email,password,customer_group_id\[email protected],,\[email protected],secret,KngqdhAlpd\n"
}
}
}'For a list of all the required attributes you need to create a customer, refer to the related section of the API reference.
Importing a list of gift cards (JSON)
The following request creates an import with a list of gift cards in JSON format:
curl -g -X POST \
'https://yourdomain.commercelayer.io/api/imports' \
-H 'Accept: application/vnd.api+json' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/vnd.api+json' \
-d '{
"data": {
"type": "imports",
"attributes": {
"resource_type": "gift_cards",
"parent_resource_id": "bgOEQhznoZ",
"inputs": [
{
"balance_cents": 12500,
"currency_code": "USD",
"single_use": false,
"rechargeable": true,
"image_url": "https://img.yourdomain.com/skus/MYGITFCARDIMAGE.png",
"expires_at": "2030-01-01T00:00:00Z",
"recipient_email": "[email protected]"
},
{
"balance_cents": 20000,
"currency_code": "EUR",
"single_use": true,
"rechargeable": false,
"expires_at": "2025-01-01T00:00:00Z",
"recipient_email": "[email protected]"
},
{ ... }
]
}
}
}'For a list of all the required attributes you need to create a gift card, refer to the related section of the API reference.
Importing a list of orders with line items and line item options (JSON)
The following request creates an import with a list of orders with associated line items and line item options in JSON format:
curl -g -X POST \
'https://yourdomain.commercelayer.io/api/imports' \
-H 'Accept: application/vnd.api+json' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/vnd.api+json' \
-d '{
"data": {
"type": "imports",
"attributes": {
"resource_type": "orders",
"parent_resource_id": "KmjljGJzWQ",
"inputs": [
{
"customer_email": "[email protected]",
"line_items": [
{
"item_type": "skus",
"name": "Black Hat Size M",
"quantity": 2,
"unit_amount_cents": 1000,
"line_item_options": [
{
"name": "engraving",
"sku_option_id": "GhFDsAWqRU",
"quantity": 1
},
{
"name": "embossing",
"sku_option_id": "hJgFCvBNmK",
"quantity": 2
}
]
},
{
"item_type": "skus",
"name": "White T-shirt Size XL",
"quantity": 1,
"unit_amount_cents": 2000
}
]
},
{
"customer_email": "[email protected]",
"_archive": 1,
"status": "cancelled",
"cancelled_at": "2018-01-01T12:00:00.000Z",
"line_items": [
{
"item_type": "skus",
"name": "Black T-Shirt Size S",
"quantity": 2,
"unit_amount_cents": 1500
}
]
},
{ ... }
]
}
}
}'To bypass some of the order's standard validations and avoid any issues, we strongly recommend passing the _archive trigger attribute when importing orders that are in a status different from draft and pending. This way, the orders will be automatically archived and you will be allowed to specify also some attributes that normally are not updatable status, payment_status, fulfillment_status, placed_at, approved_at, cacelled_at, payment_updated_at, and fulfillment_updated_at) — just make sure to be consistent when doing that (e.g. if you define a cancelled_at datetime, set the order status to cancelled accordingly).
For a list of all the required attributes you need to create an order, refer to the related section of the API reference.
Importing a list of prices with price tiers (CSV)
The following request creates an import with a list of prices and the associated price tiers in CSV format:
curl -g -X POST \
'https://yourdomain.commercelayer.io/api/imports' \
-H 'Accept: application/vnd.api+json' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/vnd.api+json' \
-d '{
"data": {
"type": "imports",
"attributes": {
"resource_type": "prices",
"format": "csv",
"parent_resource_id": "vLrWRCJWBE",
"inputs": "currency_code,sku_code,amount_cents,compare_at_amount_cents,price_tiers.type,price_tiers.name,price_tiers.up_to,price_tiers.price_amount_cents\nEUR,REDHANDBAG,1000,1000,PriceVolumeTier,10 pack,10,600\nEUR,REDHANDBAG,1000,1000,PriceVolumeTier,20 pack,20,400\nEUR,BLUEHANDBAG,2000,2000,PriceVolumeTier,XL pack,,300\n"
}
}
}'For a list of all the required attributes you need to create a price, refer to the related section of the API reference. More info about price volume tiers here.
Importing a list of SKU lists with SKU list items (JSON)
The following request creates an import with a list of SKU lists with associated SKU list items in JSON format:
curl -g -X POST \
'https://yourdomain.commercelayer.io/api/imports' \
-H 'Accept: application/vnd.api+json' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/vnd.api+json' \
-d '{
"data": {
"type": "imports",
"attributes": {
"resource_type": "sku_lists",
"inputs": [
{
"name":"Promotional Items 15%",
"sku_list_items": [
{
"sku_code": "BABYONBU000000E63E7667MX",
},
{
"sku_code": "BABYONBU000000E63E7418MX",
}
]
},
{ ... }
]
}
}
}'For a list of all the required attributes you need to create an SKU list, refer to the related section of the API reference.
Importing a list of SKU options (CSV)
The following request creates an import with a list of SKU options in CSV format:
curl -g -X POST \
'https://yourdomain.commercelayer.io/api/imports' \
-H 'Accept: application/vnd.api+json' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/vnd.api+json' \
-d '{
"data": {
"type": "imports",
"attributes": {
"resource_type": "sku_options",
"format": "csv",
"parent_resource_id": "XHnLEsQaZp",
"inputs": "name,price_amount_cents,sku_code_regex\n,engraving,500,^A\nshipping costs,700,^B\n"
}
}
}'For a list of all the required attributes you need to create an SKU option, refer to the related section of the API reference.
Importing a list of SKUs (JSON)
The following request creates an import with a list of SKUs in JSON format:
curl -g -X POST \
'https://yourdomain.commercelayer.io/api/imports' \
-H 'Accept: application/vnd.api+json' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/vnd.api+json' \
-d '{
"data": {
"type": "imports",
"attributes": {
"resource_type": "skus",
"inputs": [
{
"code":"BABYONBU000000E63E7424MX",
"name":"Baby's Black Onesie Short Sleeve with Pink Logo (24 Months)",
"image_url":"https://img.yourdomain.com/skus/BABYONBU000000E63E74.png",
"reference": "BABYONBU000000E63E74",
"shipping_category_code": "2_days"
},
{
"code":"BABYONBU000000E63E7418MX",
"name":"Baby's Black Onesie Short Sleeve with Pink Logo (18 Months)",
"image_url":"https://img.yourdomain.com/skus/BABYONBU000000E63E74.png",
"reference": "BABYONBU000000E63E74",
"shipping_category_id": "zwzQeFBrNj"
},
{ ... }
]
}
}
}'For a list of all the required attributes you need to create an SKU, refer to the related section of the API reference.
Importing a list of stock items (CSV)
The following request creates an import with a list of stock items in CSV format:
curl -g -X POST \
'https://yourdomain.commercelayer.io/api/imports' \
-H 'Accept: application/vnd.api+json' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/vnd.api+json' \
-d '{
"data": {
"type": "imports",
"attributes": {
"resource_type": "stock_items",
"format": "csv",
"parent_resource_id": "bnEeQuqZgn",
"inputs": "sku_code,quantity,_validate\nBABYONBU000000E63E7424MX,110,1\nBABYONBU000000E63E7418MX,140,1\n"
}
}
}'When importing stock items, existing records may be updated with inconsistent quantities: this occurs when the quantity of a stock item is less than the existing reserved stock, which is probably an overselling symptom. To avoid this scenario, we recommend passing the _validate trigger attribute for each of the imported inputs: in case the quantity is smaller than the associated reserved_stock, the update fails and an error is logged for further inspection.
For a list of all the required attributes you need to create a stock item, refer to the related section of the API reference.
Importing a list of stock transfers (JSON)
The following request creates an import with a list of stock transfers in JSON format:
curl -g -X POST \
'https://yourdomain.commercelayer.io/api/imports' \
-H 'Accept: application/vnd.api+json' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/vnd.api+json' \
-d '{
"data": {
"type": "imports",
"attributes": {
"resource_type": "stock_transfers",
"format": "json",
"inputs": [
{
"sku_code":"BABYONBU000000E63E7424MX",
"quantity":2,
"origin_stock_location_id": "ondYzudReG",
"destination_stock_location_id": "znmoyuXpYk"
},
{
"sku_code":"BABYONBU000000E63E7418MX",
"quantity":3,
"origin_stock_location_code": "EUCOM",
"destination_stock_location_code": "EUWHR"
},
{ ... }
]
}
}
}'For a list of all the required attributes you need to create a stock transfer, refer to the related section of the API reference.
Importing a list of tags (CSV)
The following request creates an import with a list of tags in CSV format:
curl -g -X POST \
'https://yourdomain.commercelayer.io/api/imports' \
-H 'Accept: application/vnd.api+json' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/vnd.api+json' \
-d '{
"data": {
"type": "imports",
"attributes": {
"resource_type": "tags",
"format": "csv",
"inputs": "name\nbags\nhats\naccessories"
}
}
}'For a list of all the required attributes you need to create a tag, refer to the related section of the API reference.
Importing a list of SKUs with tags (JSON)
The following request creates an import with a list of SKUs and the associated tags in JSON format:
curl -g -X POST \
'https://yourdomain.commercelayer.io/api/imports' \
-H 'Accept: application/vnd.api+json' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/vnd.api+json' \
-d '{
"data": {
"type": "imports",
"attributes": {
"resource_type": "skus",
"parent_resource_id": "BNdxyFenNG",
"inputs": [
{
"code": "TSHIRTMS000000FFFFFFLXXX",
"name": "Men's Black T-Shirt with White Logo (L)",
"tags": [
{
"name": "t_shirts"
}
]
},
{
"code": "TOYCARMINICOUNTRYMANYB",
"name": "Toy Car — Mini Countryman, Yellow/Black",
"tags": [
{
"name": "toys"
},
{
"name": "black_friday"
}
]
},
{
"code": "BASEBCAPLABLUE",
"name": "Baseball Cap LA, Blue",
"tags": [
{
"name": "black_friday"
},
{
"name": "hats"
},
{
"name": "new_collection"
}
]
}
]
}
}
}'For a list of all the required attributes you need to create a SKU, refer to the related section of the API reference. More info about tags here.
Importing a list of customers with tags (CSV)
The following request creates an import with a list of customers and the associated tags in CSV format:
curl -g -X POST \
'https://yourdomain.commercelayer.io/api/imports' \
-H 'Accept: application/vnd.api+json' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/vnd.api+json' \
-d '{
"data": {
"type": "imports",
"attributes": {
"resource_type": "customers",
"format": "csv",
"inputs": "email,tags.id,tags.name\[email protected],\"\",\"newsletter\"\[email protected],\"\",\"vip,black_friday\""
}
}
}'For a list of all the required attributes you need to create a customer, refer to the related section of the API reference. More info about tags here.
Importing a list of tax categories (CSV)
The following request creates an import with a list of tax categories in CSV format:
curl -g -X POST \
'https://yourdomain.commercelayer.io/api/imports' \
-H 'Accept: application/vnd.api+json' \
-H 'Authorization: Bearer your-access-token' \
-H 'Content-Type: application/vnd.api+json' \
-d '{
"data": {
"type": "imports",
"attributes": {
"resource_type": "tax_categories",
"format": "csv",
"parent_resource_id": "daSWQhzjkiZ",
"inputs": "sku_code,code\nBABYONBU000000E63E7424MX,31000\nBABYONBU000000E63E7418MX,31000\n"
}
}
}'For a list of all the required attributes you need to create a tax category, refer to the related section of the API reference.
Importing more than 10K gift cards using the CLI
The following command imports a set of gift cards for the market identified by the ID "YlqxGhzDgJ" from a JSON file saved to a specified path:
commercelayer imports:create -t gift_cards -p YlqxGhzDgJ -i ./imports/gift_cards.jsonChecking the import status
You can inspect the status of a specific import by fetching the single import by ID and looking at the status attribute.
The following request fetches a single import, the one identified by the ID "PmjlkIJzRA":
curl -g -X GET \
'https://yourdomain.commercelayer.io/api/imports/PmjlkIJzRA' \
-H 'Content-Type: application/vnd.api+json' \
-H 'Authorization: Bearer your-access-token'If an import gets stuck in the in_progress status for any reason, you can mark it as interrupted by patching it with the _interrupt trigger attribute set to true.
Webhooks for imports
You can also leverage Commerce Layer real-time webhooks mechanism, listen to imports.create, imports.start, imports.complete, imports.interrupt, or imports.destroy and react properly.
Handling import errors
When an import is completed or interrupted, import errors and warnings (related to clean-up) are reported through the errors_count, errors_log, warnings_count, and warnings_log attributes:
...
"errors_count": 5,
"warnings_count": 0,
"destroyed_count": 0,
"processed_count": 95,
"errors_log": {
"BABYONBU000000E63E7418MX": {
"name": [
"has already been taken"
]
},
"BABYONBU000000E63E7424MX": {
"shipping_category": [
"must exist"
]
},
...
},
"warnings_log": {},
...Last updated

