What Is a Product Import?
A product import automation pulls product data from an external source -- a supplier's FTP server, a distributor's API, an email attachment -- and creates or updates products in SureDone. This is the most common automation type. If your supplier sends you a daily inventory file, a weekly catalog update, or a price list via their API, a product import automation handles it automatically.
The data flow is always the same: connect to the source, download the data, map the vendor's fields to SureDone's fields, transform if needed, and import through the bulk system.
Connection: Where the Data Comes From
Product imports support all connection types. The most common setups are:
- SFTP/FTP -- Download a file from a supplier's server. Specify the
address,username,password, andpathto the file directory. - HTTP -- Fetch data from a REST API. Configure the
address,method,headers, and optionallypayloadfor POST requests. Supports OAuth, pagination, and trigger chains. - Email -- Import data from an email attachment. Use
email_searchto filter which emails to process (by subject, sender, date, etc.). - SDSFTP / SDS3 -- Pull files from SureDone's own SFTP server or S3 bucket.
File Formats
The Automation Engine can parse several file formats. You control the format through settings in file_configs:
| Format | Config | When to Use |
|---|---|---|
| CSV / TSV | delimiter, enclosure |
Most supplier files. Delimiter defaults to ,, enclosure to ". Set delimiter: "\t" for TSV. |
| XML | xpath: true |
When the vendor provides XML. Use XPath queries in field_map to extract values. |
| JSON | jsonpath: true |
When fetching from an API that returns JSON. Use JSONPath queries in field_map. |
| Bulk file | bulk_file: true |
When the file is already in SureDone's native bulk format. Skips all field mapping -- the engine imports it directly. |
For CSV files without headers, you can provide an ordered array of field names in the headers config to tell the engine what each column represents.
Import Modes: Create, Update, and Remove
Every product import must specify at least one of create, update, or remove. These control what happens when the engine processes each item:
| Config | Value | What It Does |
|---|---|---|
create |
"start" |
Creates new products with a "starting" status (not yet active on channels) |
create |
"add" |
Creates new products and immediately lists them on channels |
update |
"edit" |
Updates existing products with new data |
update |
"relist" |
Updates existing products and relists any that were previously ended |
remove |
"end" |
Ends (deactivates) matched products that already exist in SureDone |
remove |
"delete" |
Permanently deletes matched products from SureDone |
You can combine modes. For example, "create": "start" with "update": "edit" will create products that are new and update products that already exist.
create, update, or remove must be set in each file config. If you forget to include one, the automation will not process any items.Identifier Matching
The identifier setting tells the engine which SureDone field to use when determining whether a vendor item already exists in your catalog. It defaults to guid.
If your vendor uses their own part number, and you store that in a custom field like vendorsku, set "identifier": "vendorsku". When the engine processes each row, it searches SureDone for products where vendorsku matches the incoming value. If a match is found, the product is updated. If not, it is created (when create is set).
"field_map": {
"guid": "PartNumber",
"vendorsku": "PartNumber",
"stock": "Available",
"price": "SellPrice"
},
"identifier": "vendorsku"
For cases where a product might match on multiple fields, use identifiers as an array. The engine checks each field in order and uses the first non-empty match:
"identifiers": ["vendorsku", "upc", "mpn"]
You can also add or strip prefixes/suffixes for matching with identifier_prefix_vendor, identifier_prefix_suredone, identifier_suffix_vendor, and identifier_suffix_suredone. And identifier_case_sensitive (default true) controls whether matching is case-sensitive.
Diff Updates: Only Update What Changed
When you are processing large inventory files daily, most rows will not have changed since the last run. The diff_update and diff_fields configs let you skip unchanged items, saving significant processing time.
"diff_update": true,
"diff_fields": ["stock", "price"]
With this configuration, the engine only imports a product if its stock or price value differs from what is currently in SureDone. Everything else is skipped. If diff_update is true but diff_fields is not set, the engine checks all mapped fields for changes.
The optional diff_tolerance setting lets you define a numeric threshold. If two values differ by no more than the tolerance, they are considered the same -- useful for prices that fluctuate by a fraction of a cent.
Stock Management
Product imports include several configs for managing inventory:
stock_field -- Designates which SureDone field holds the stock value for this automation. Has no default -- must be explicitly set when using stock_sum_fields or stock_negative.
stock_sum_fields -- When a vendor provides inventory across multiple warehouses, this config adds them up. The sum is stored in the field specified by stock_field:
"stock_field": "total_stock",
"stock_sum_fields": ["warehouse_east", "warehouse_west", "warehouse_central"]
stock_sum_multiline_field -- For files where the same product appears on multiple rows (one per warehouse), this tells the engine which field identifies the warehouse, so it can sum stock across rows for the same product.
stock_negative -- Defaults to true. Set to false (along with stock_field) to prevent stock from going below zero.
Missing Vendor Items
The missing_vendor_items config controls what happens to products that exist in SureDone but are absent from the vendor's file. This is critical for inventory accuracy:
| Value | Effect |
|---|---|
"delete" |
Deletes products from SureDone that are not in the vendor file |
"end" |
Ends (deactivates) products not in the vendor file |
"zeroStock" |
Sets stock to 0 for products not in the vendor file |
You can also pass an array combining a string action with conditional actions for more complex logic.
missing_vendor_items carefully. If your vendor sends a partial file (only updated items), this config would act on every product not in that partial file. Only use it with full catalog feeds.Channel Control
These settings control how imported data flows to your sales channels:
skip_channels-- An array of channels to skip updating (e.g.,["ebay", "amazon2"]).skip_all-- Set totrueto skip all channel updates. Useful for internal-only imports like cost updates.force-- Set totrueto allow updates to protected fields likesku.import_media-- Set totrueto download and import images when media URLs are included in the field map.
Custom Field Creation
The create_custom_fields config lets your automation automatically create SureDone custom fields that do not exist yet. You can pass a simple array of field names (for defaults) or an object with detailed field properties:
"create_custom_fields": {
"vendorcost": {
"type": "float",
"length": 10,
"label": "Vendor Cost"
},
"vendorsku": {
"type": "varchar",
"length": 64,
"index": true,
"label": "Vendor SKU"
}
}
File Handling After Import
After processing a file, you can clean up:
delete_remote_file-- Delete the file from the remote server after import.move_remote_file-- Move the file to a different directory (e.g., an "archive" folder).rename_remote_file-- Rename the file after processing.limit_files-- When usingregexto match multiple files, limit how many are processed per run.
Complete Example: Inventory Update from SFTP CSV
This automation downloads a daily inventory file from a supplier's SFTP server, matches products by vendor SKU, and updates stock and price. Only changed values are imported, and all channel updates are skipped since this is an inventory-only sync.
{
"name": "Daily Inventory Sync",
"vendor": "Acme Parts",
"active": true,
"schedule": "15 6 * * *",
"type": "products",
"action": "import",
"connection": {
"type": "sftp",
"address": "sftp.acmeparts.com",
"username": "{{sftp_user}}",
"password": "{{sftp_pass}}",
"path": "/exports/inventory",
"port": 22
},
"file_configs": [
{
"name": "inventory_full.csv",
"identifier": "vendorsku",
"update": "edit",
"field_map": {
"vendorsku": "PartNumber",
"stock": "QtyAvailable",
"price": "DealerPrice"
},
"field_run": {
"warehouse_east": "EastQty",
"warehouse_west": "WestQty"
},
"stock_field": "stock",
"stock_sum_fields": ["warehouse_east", "warehouse_west"],
"stock_negative": false,
"diff_update": true,
"diff_fields": ["stock", "price"],
"skip_all": true,
"missing_vendor_items": "zeroStock",
"delete_remote_file": false
}
],
"parameters": [
{
"name": "sftp_user",
"value": "",
"label": "SFTP Username"
},
{
"name": "sftp_pass",
"value": "",
"encrypted": true,
"label": "SFTP Password"
}
]
}
What this does:
- Runs daily at 6:15 AM UTC
- Connects to the supplier's SFTP and downloads
inventory_full.csv - Matches each row to existing products using the
vendorskufield - Sums
warehouse_eastandwarehouse_westinto thestockfield - Only updates products where
stockorpriceactually changed - Sets stock to 0 for any SureDone products not found in the file
- Skips all channel updates (inventory-only sync)
Complete Example: Product Catalog Import from HTTP API
This automation fetches a full product catalog from a vendor's JSON API, creates new products, and updates existing ones with images.
{
"name": "Catalog Import",
"vendor": "GlobalParts",
"active": true,
"schedule": "0 2 * * 1",
"type": "products",
"action": "import",
"connection": {
"type": "http",
"address": "https://api.globalparts.com/v2/products",
"method": "GET",
"headers": {
"Authorization": "Bearer {{api_key}}",
"Accept": "application/json"
},
"paginate": true,
"pagination": {
"next_token": "$.meta.next_page_url"
}
},
"file_configs": [
{
"jsonpath": true,
"identifier": "mpn",
"create": "start",
"update": "edit",
"field_map": {
"guid": "$.data[*].sku",
"mpn": "$.data[*].part_number",
"title": "$.data[*].name",
"longdescription": "$.data[*].description",
"brand": "$.data[*].brand",
"price": "$.data[*].retail_price",
"cost": "$.data[*].wholesale_price",
"stock": "$.data[*].quantity",
"weight": "$.data[*].weight_lbs",
"upc": "$.data[*].upc",
"media1": "$.data[*].images[0]",
"media2": "$.data[*].images[1]",
"media3": "$.data[*].images[2]"
},
"value_map_default": {
"condition": "New"
},
"import_media": true,
"diff_update": true
}
],
"parameters": [
{
"name": "api_key",
"value": "",
"encrypted": true,
"label": "API Key"
}
]
}
What this does:
- Runs every Monday at 2:00 AM UTC
- Calls the vendor's paginated JSON API and follows pagination links automatically
- Uses JSONPath to extract product fields from the API response
- Creates new products in "start" status and updates existing ones
- Downloads and imports product images
- Sets a default
conditionof "New" for all imported products - Only imports products that have actually changed since the last run