Skip to main content

Importable sales order columns reference

This page is the complete lookup for every column the Import Sales Orders spreadsheet importer reads, plus the exact validation each one is subject to. It's the reference companion to the task guide Import sales orders — read that first if you want the step-by-step Upload → Map → Validate → Import flow; come here to look up a specific column, its accepted values, or an edge case.

Everything below is read straight from the importer, so it's authoritative for what the Import Sales Orders window accepts. For what each field means once it lands on the order, see the Fields reference.

Before you begin

  • Importing requires the Import sales orders permission (sales_orders.import). Without it the Import button is hidden. See the Permissions reference.
  • Products, sales channels, currencies, warehouses, and nominal codes referenced by your file must already exist — the importer resolves them by name (or code) and errors on anything it can't find. It never creates them for you.
  • Customers are the exception. A row can auto-create a new customer when the email or name doesn't match an existing one (see Customer columns).
  • The download template (Download Template on step 1) is seeded with your own channels, customers, products, and reference values, and carries a Field Guide sheet mirroring the tables below.

How rows become orders

The importer uses one row per line item. Header columns (order number, customer, channel, currency, addresses, and the order-level totals) are repeated on every row that belongs to the same order, and the importer collapses them into one multi-line order.

AspectBehavior
Accepted file types.csv, .tsv, .xlsx, .xls, or pasted CSV/TSV text.
Delimiter & header rowAuto-detected; you confirm the First row is a header checkbox before mapping.
Column mappingEach file column is bound to a target field via a Maps To dropdown. Required fields are flagged; unwanted columns can be set to Skip this column.
GroupingRows are grouped into one order by id, or by (sales_order_number + customer), so repeated header values on each line collapse into a single order.
Order-level valuesorder_discount_amount, order_discount_rate, shipping_amount, addresses, and all header fields are read from the first row of each order group. Custom fields are read from the first row too.
Row capUp to 50,000 rows per run.

Header & upsert columns

These describe the whole order and are read from the first row of each order group.

ColumnRequiredType / formatAccepted valuesNotes
idNoIntegerAn existing sales order IDThe upsert key. When present, the row updates that exact order. Blank creates a new order (or matches on number + channel — see Upsert rules). An ID that doesn't exist is Blocked.
sales_order_numberNoText (≤255)AnyBlank auto-generates a number. When id is blank, this combines with sales_channel_name as the upsert match key.
order_dateYes (create)Date YYYY-MM-DDA parseable dateInterpreted in your account timezone. Optional on an update (the existing order keeps its date).
sales_channel_nameYes (create)TextAn existing channel nameEvery order must belong to a sales channel. Resolved by name (case-insensitive). Optional on an update.
sub_sales_channel_nameNoTextAn existing sub-channel nameResolved by name.
store_nameNoTextAn existing store nameDefaults to your sales-order default store when blank.
currency_codeNoTextAn existing ISO currency codeDefaults to the channel's or your account's default currency when blank.
customer_po_numberNoTextAnyThe customer's own PO reference.
requested_shipping_methodNoTextFree text, or a shipping-method nameStored as free text; also matched to a system shipping method when the value resolves to one.
ship_by_dateNoDate YYYY-MM-DDA parseable dateLatest date the order should ship by.
deliver_by_dateNoDate YYYY-MM-DDA parseable dateLatest date the order should be delivered by.
hold_until_dateNoDate YYYY-MM-DDA parseable dateEarliest date the order may ship — held until then (for example, preorders).
tagsNoTextComma-separated (tag1, tag2)Tags are auto-created if missing. On an update a blank cell preserves the existing tags.

Customer columns

The customer is resolved in this order: customer_idcustomer_emailcustomer_name. Only customer_email can auto-create a customer; the other two must match an existing record.

ColumnRequiredType / formatAccepted valuesNotes
customer_idNoIntegerAn existing customer IDExact match, checked first. An ID that doesn't exist is a row error.
customer_emailPreferredTextAny emailMatches an existing customer by email; if none matches, a new customer is created from the row. This is the recommended key.
customer_nameNoTextAnyFallback used only when customer_id and customer_email are blank. Errors if the name is ambiguous (more than one customer shares it) or not found (it can't auto-create without an email).
customer_companyNoTextAnyOnly used when auto-creating a new customer. Ignored for a matched/existing customer.
customer_phoneNoTextAnyOnly used when auto-creating a new customer. Ignored for a matched/existing customer.
A create needs a customer; an update can inherit one

On a new order at least one of customer_id, customer_email, or customer_name is required. On an update where the row's customer matches (or omits) the order's current customer, the existing customer is kept and no change is made.

Order-level total columns

Read from the first row of each order group only. If you put a non-zero value on a later line of a multi-line order, it's ignored and the preview warns you.

ColumnRequiredType / formatAccepted valuesNotes
order_discount_amountNoNumber ≥ 0Amount in the order currencyAn order-level discount as a fixed amount, allocated across the lines.
order_discount_rateNoNumber 0–100PercentageAn order-level discount as a percentage. If both order_discount_amount and order_discount_rate are given, the rate wins and the amount is discarded with a warning.
shipping_amountNoNumber ≥ 0Amount in the order currencyAdds a "Shipping" revenue charge to the order.
Imported totals are idempotent

Re-importing the same order wipes the discount and shipping records the previous import created and re-applies them from the new values — so correcting a sheet and re-importing doesn't stack duplicate charges. Discounts and shipping added manually or by a channel sync are left untouched.

Address columns

Only these five fields are read for each of shipping and billing. On an update, a blank cell preserves the existing address rather than wiping it; supply at least one non-blank field to overwrite.

ColumnRequiredType / formatNotes
shipping_addressNoTextStreet address line.
shipping_cityNoText
shipping_provinceNoTextState / province / region.
shipping_zipNoTextZIP / postal code.
shipping_countryNoTextCountry name or ISO code.
billing_addressNoTextStreet address line.
billing_cityNoText
billing_provinceNoTextState / province / region.
billing_zipNoTextZIP / postal code.
billing_countryNoTextCountry name or ISO code.

Line-item columns

One set per row. Every row with a sku becomes a line on its order.

ColumnRequiredType / formatAccepted valuesNotes
skuYes (create)TextAn existing product SKUMust resolve to a standard or kit product. Bundles and subscription products are rejected. An unmatched SKU is a line error.
descriptionNoText (≤255)AnyDefaults to the product's name when blank.
quantityYesNumber > 0A positive number
unit_priceYesNumber ≥ 0Price per unit, in the order currency
discountNoNumber ≥ 0Amount per unitStored as a fixed line discount of discount × quantity — it's per-unit, not a percentage and not a line total.
tax_rateNoNumberPercentage (for example, 8.875)Defaults to 0 when blank.
warehouse_nameNoTextAn existing warehouse nameBlank lets the system route the line by inventory.
nominal_codeNoTextAn existing nominal codeThe accounting code for the line; matched by code.

Custom-field columns

For every custom field you've defined on sales orders, the template offers a custom_<slug> column (for example custom_gift_message). Mapping one sets that custom field's value on the order.

BehaviorDetail
Column namecustom_<slug>, one per sales-order custom field. The Field Guide sheet lists the slug, type, and valid values for each.
Sets a valueA non-blank cell writes that value to the custom field.
Clears a value (update)A mapped but blank cell clears the field on the order.
Leaves a value untouchedA custom-field column you don't map is left exactly as it was — a partial-import sheet never wipes custom fields it doesn't include.
Which rowRead from the first row of each order group, like the other header fields.
Custom fields import correctly

Mapping custom_<slug> columns now writes the values through as described above. (An earlier version silently dropped these columns; that has been fixed.)

How the importer decides create vs update

For each order group the importer picks a target in this order:

  1. By id — if a row has an id, that exact order is the target.
  2. By (sales_order_number + sales_channel_name) — if id is blank and the number-plus-channel pair matches an existing order, that order is updated. Otherwise a new order is created.

An update with line rows replaces every line

When an update row includes line items, all lines on the matched order are replaced with the rows in your import — not merged. For a header-only change (tags, PO number, dates, sub-channel, shipping method, custom fields), leave the sku/quantity/unit_price columns out of the file entirely so the existing lines are left untouched.

States that block an update

An order in one of these states is marked Blocked in the preview and never sent:

StateWhat's blockedWorkaround
ArchivedAny import update.Unarchive it first, or drop the row.
CanceledAny import update.Drop the row.
id not foundThe referenced order doesn't exist.Remove the id to create a new order instead.
ClosedAny field except tags, sub_sales_channel_name, customer_po_number, and requested_shipping_method.Restrict the row to those four fields, or reopen the order.

If two rows in the same file both target the same existing order, both are Blocked with a collision error — consolidate them into one group.

Validation rules at a glance

Field kindRuleBlank cell
Text lookups (sales_channel_name, sub_sales_channel_name, store_name, currency_code, warehouse_name, nominal_code)Must resolve to an existing record by name/code (case-insensitive); an unknown value is an error.Left unset (defaults apply where noted).
skuMust resolve to an existing standard or kit product.A row with no SKU is treated as a non-line (header-only) row.
quantityMust be a positive number.Error on a line row.
unit_priceMust be a non-negative number.Error on a line row.
order_discount_rateNumeric, 0100.Ignored.
order_discount_amount, shipping_amount, discountNumeric, non-negative.Ignored.
Dates (order_date, ship_by_date, deliver_by_date, hold_until_date)Must be a parseable date; interpreted in your account timezone.Left unset (except order_date, required on create).
tags / addresses / custom fieldsBlank preserves the existing value on an update.

Next steps

Last verified: