Importing resources

How to bulk import resources and their relationships

To import a CSV list you need to set the format attribute to csv. Otherwise, if the format is not specified, the import API will assume you're using the default format (JSON) and return an error.

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.

Resource relationships can be addressed by using their IDs. To do that, you need to append the _id suffix to the name of the related resource (e.g. price_list_id). Some relationships can also be specified as a nested array of objects (e.g. order line items, price tiers, SKU list items, etc.).

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.

External storage service URLs expire in 5 minutes. You need to uncompress (gunzip) the file in order to read the data back. If the imported data URL is expired you can just fetch the completed import to get a new working one.

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.

If you absolutely need to import any of the supported resources in one go, overriding the maximum import size and concurrent imports API limits above, you can leverage the power of our CLI import plugin (see example).

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.

With very few exceptions (e.g. shipments, transactions, etc.) you can use as inputs any output (both in JSON or CSV format) you get from the exports API.

Unique keys

If the single resource to be imported doesn't exist it gets created, otherwise it is updated.

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_id

  • Coupons — code + promotion_rule_id

  • Customer addresses — customer_id

  • Customer subscriptions — customer_id + reference

  • Customers — email

  • Gift cards — code

  • Orders — number

  • Prices — sku_code + price_list_id

  • Shipping categories — name

  • SKU options — name + currency_code

  • SKUs — code

  • Stock items — sku_code + stock_location_id

  • Tags — name

  • Tax categories — code + tax_calculator_id

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_id

  • Coupons — promotion_rule_id

  • Customer payment sources — payment_method_id

  • Gift cards — market_id

  • Orders — market_id

  • Prices — price_list_id

  • SKU list items — sku_list_id

  • SKU options — market_id

  • Stock items — stock_location_id

  • Tax 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

Just to be sure you can rollback, we strongly recommend to perform an export using the very same filter before any cleanup operation.

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,george@thebeatles.co.uk\n"
      }
    }
  }'

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"
          },
          { ... }
        ]
      }
    }
  }'

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,george@harrison.co.uk\n"
      }
    }
   }'

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": "john@example.com",
            "address_id": "gHbVCxZSdE"
          },
          {
            "customer_email": "mario@example.com",
            "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"
          },
          { ... }
        ]
      }
    }
  }'

To create an import of customer payment sources you must always provide the customer_token and payment_source_token you got from your payment gateway.

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": "john@example.com",
            "reference": "Marketing newsletter"
          },
          {
            "customer_email": "jane@example.com",
            "reference": "Whitepaper download"
          },
          { ... }
        ]
      }
    }
  }'

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\njohn@example.com,,\njack@example.com,secret,KngqdhAlpd\n"
      }
    }
  }'

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": "john@example.com"
          },
          {
            "balance_cents": 20000,
            "currency_code": "EUR",
            "single_use": true,
            "rechargeable": false,
            "expires_at": "2025-01-01T00:00:00Z",
            "recipient_email": "jane@example.com"
          },
          { ... }
        ]
      }
    }
  }'

To create an import of gift cards for the same market, remember to specify its ID as theparent_resource_id attribute. On the other hand, specifying the market_id or the market_code attributes for every single item of the inputs list lets you import gift cards associated with different markets all at once.

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": "john@example.com",
            "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": "jack@example.com",
            "_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 create an import of orders for the same market, remember to specify its ID as the parent_resource_id attribute. On the other hand, specifying the market_id or the market_code attributes for every single item of the inputs list lets you import orders associated with different markets all at once.

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"
      }
    }
  }'

To create an import of prices for the same price list, remember to specify its ID as the parent_resource_id attribute. On the other hand, specifying the price_list_id or the price_list_code attributes for every single item of the inputs list lets you import prices associated with different price lists all at once.

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",
              }
            ]
          },
          { ... }
        ]
      }
    }
  }'

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"
      }
    }
  }'

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"
          },
          { ... }
        ]
      }
    }
 }'

SKUs have no parent resource, hence the shipping category cannot be used as the parent_resource_id attribute. On the other hand, specifying the shipping_category_id or the shipping_category_code attributes for every single item of the inputs list lets you import SKUs associated with different shipping categories all at once (SKUs marked as do_not_ship included, for which you just can avoid setting any shipping_category_id at all).

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"
      }
    }
  }'

To create an import of stock items for the same stock location, remember to specify the stock location ID as the parent_resource_id attribute. On the other hand, specifying the stock_location_id or the stock_location_code attributes for every single item of the inputs list lets you import stock items associated with different stock locations all at once.

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.

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"
          },