---
title: "How to import, update and export a price list with CSV"
description: "Process Wholesale can create or replace a price list from a CSV file with a price column and a SKU or Handle column, and export a list to CSV. Use Import from CSV, Update from CSV and Export to CSV on the Professional plan."
type: how-to
plans: [Professional]
keywords:
  [
    price list CSV,
    bulk upload wholesale prices,
    import wholesale prices,
    CSV price list upload,
    export price list,
    spreadsheet prices,
    B2B catalog import,
    Fixed Price column,
    bulk edit price list,
  ]
questions:
  - "How do I import a wholesale price list from a CSV file?"
  - "Does Update from CSV replace the whole price list?"
  - "How are CSV rows matched to my products?"
  - "Can I import a Shopify product export as a price list?"
  - "How many rows can a price list CSV have?"
  - "How do I see which rows did not match?"
last_verified: 2026-11-11
order: 9
---

# How to import, update and export a price list with CSV

Process Wholesale can create a [price list](price-lists.md) from a CSV file, replace an existing list's prices from a CSV file, and export a list to CSV. The file needs a price column and a SKU or Handle column, and can have up to 50,000 rows. Use **Import from CSV** on the **Create new set price list** page, and **Update from CSV** or **Export to CSV** on an existing list's page, in **Discounts > Price Lists** on the Professional plan. This is also called a bulk price upload or a price sheet import.

**At a glance**

- **Plan:** Professional
- **Where:** Process Wholesale > **Discounts** > **Price Lists**, then **Create new pricelist** (import) or **Edit** on a list (update and export)
- **File:** `.csv`, one file at a time, up to 50,000 rows
- **Required columns:** a price column, and a SKU column or a Handle column (or both)
- **Matching:** by SKU first, then by Handle
- **Update mode:** replaces the whole list. Products not in the file are removed from the list.
- **Column details:** [Price list CSV format reference](../reference/price-list-csv-format.md)

## Before you start

- Your store must be on the Professional plan.
- Prepare a CSV file with a header row. Accepted price headers include `Price`, `Fixed Price` and `Wholesale Price`; accepted key headers include `SKU` and `Handle`. Other columns are ignored. The [CSV format reference](../reference/price-list-csv-format.md) lists every accepted header.
- Write prices without thousands separators: `1299.99` or `1299`, not `1,299`. A value such as `1,299` is read as 1.299.
- Give each variant a unique SKU where you can. A row whose SKU belongs to several variants, or whose handle belongs to a product with several variants, is not imported.
- A Shopify product export is not recognized as it is: its price column, `Variant Price`, is not an accepted header. Rename that column to `Price` first. A Shopify B2B catalog export with `SKU`, `Handle` and `Fixed Price` columns works without changes.
- Run one import at a time. While another import is reading your product catalog, a new one shows **Couldn't start the import. A store export may already be running — please try again in a minute.**

## Steps to create a price list from CSV

1. In Shopify admin, open the **Process Wholesale** app and select **Discounts**, then the **Price Lists** tab.
2. Select **Create new pricelist**.
3. In the **Name** card, enter the name of the new list, using lowercase letters and numbers only. The import uses this name. With an invalid name the import window shows **Enter a valid price list name (letters and numbers only, no "B2B") before importing.** and the import button is disabled.
4. Select **Import from CSV**. The **Import prices from CSV** window opens.
5. Select **Add CSV file**, or drop a `.csv` file on the box. To start from a sample file, select **Download template**.
6. Check the preview (see "How to read the CSV preview"), then select **Import prices**.
7. Wait for the result. When it shows **Import complete for "<name>"**, select **Done**. The app shows **Price list created from CSV** and returns to the **Price Lists** tab.

Products and prices you add this way do not need to fit the editor's 200-product limit.

## Steps to update a price list from CSV

1. On the **Price Lists** tab, select **Edit** next to the list.
2. Select **Update from CSV**. The **Update prices from CSV** window opens with this warning: "This replaces the prices in "<name>". Products in the file are updated or added; products currently in the list but **not** in the file are removed and their price cleared. Rows that don't match a product in your store are skipped."
3. Add the CSV file and check the preview.
4. Select **Update prices**.
5. When it shows **Update complete for "<name>"**, select **Done**. The app shows **Price list updated from CSV**.

> **Important:** **Update from CSV** replaces the whole price list. A variant that is in the list but not matched in the file, including a row that was skipped for an invalid price or an ambiguous SKU, is removed from the list. To change a few prices, export the list first, edit the prices in the exported file and upload the complete file.

**Example.** The list `wholesale` holds product A at 5, B at 8 and C at 3. You upload a file with A at 7 and D at 6. After the update the list holds A at 7 and D at 6. The result shows 1 added (D), 1 updated (A) and 2 removed (B and C).

## Steps to export a price list to CSV

1. On the **Price Lists** tab, select **Edit** next to the list.
2. Select **Export to CSV**. The file `price-list-<name>.csv` downloads.

The export has the columns `SKU`, `Handle`, `Title` and `Price`, one row per variant on the list. `Title` is the variant title. Prices are written as stored, for example `7` rather than `7.00`. Variants that were deleted from your store are left out. If the export fails, the app shows **Couldn't export the price list**.

You can edit the exported file and upload it again with **Update from CSV**. The `Title` column is ignored on import. Two kinds of exported rows are not matched when you upload the file again, so **Update from CSV** removes those variants from the list: a variant whose SKU another variant in your store also uses, and a variant with no SKU on a product with several variants. Give those variants unique SKUs in Shopify before you re-upload.

> **Important:** Before you upload an exported file with **Update from CSV**, check that it is complete: the number of rows matches the number of variants you expect on the list. If an export is interrupted, the downloaded file can be shorter than the list. Uploading a partial file removes every product missing from it. Export again if the file looks short.

## How to read the CSV preview

After you add a file, the import window reads it and shows a summary before anything is imported:

- **{count} ready**: rows that have a SKU or Handle and a valid price.
- **{count} skipped (missing key or invalid price)**: rows with no SKU and no Handle, or a price that is empty, not a number or negative.
- **of {count} rows**: the total number of data rows.
- **Matched to SKU / Handle; price from "<column>".**: which key columns were found and which column the prices come from.

"Ready" means the row is well formed. It does not yet mean the product was found in your store. Matching happens after you start the import. Skipped rows are listed later in the unmatched rows file with their reason.

If the file has no price column, or neither a SKU nor a Handle column, the window shows **Couldn't detect the required columns. The file needs a price column (e.g. “Fixed Price” or “Price”) and at least one of “SKU” or “Handle”.** A file that cannot be read at all shows **Failed to parse the CSV file.** or the reader's own message.

## How rows are matched to products

Process Wholesale matches each row to one product variant in your store:

1. The price is checked first. A row with an invalid or negative price is not matched.
2. The SKU is looked up, ignoring capitals and surrounding spaces. If exactly one variant has that SKU, the row is matched. If several variants share it, the row is not matched and the Handle is not tried.
3. If the SKU is empty or not found, the Handle is looked up, ignoring capitals. If the product has exactly one variant, the row is matched. If it has several variants, the row is not matched, because a handle alone cannot say which variant is meant.
4. When several rows match the same variant, the last row wins.

**Example.** Your store has a variant with SKU `BCA` on the product `bass-casting`, and a product `single` with one variant. A row with SKU `BCA`, handle `wrong-handle` and price `4.79` is matched by SKU at 4.79. A row with no SKU, handle `single` and price `9.99` is matched to the one variant of `single`. A row with SKU `DUP`, used by two variants, is not matched.

## What happens while the import runs

The import runs in the background. The window shows a progress bar and a status line:

1. **Starting…**: the import is being set up.
2. **Reading your product catalog…**: Process Wholesale reads every variant in your store to match the rows.
3. **Publishing prices to checkout…**: the matched prices are being made available to checkout.

The window says: "Importing… this runs in the background and may take a minute for large catalogs. You can keep this open to watch progress." Larger catalogs take longer. You cannot close the window while the import runs. If you leave the page or close the app, the import keeps running; open the list on the **Price Lists** tab later to see the result.

## The import result

When the import finishes, the window shows **Import complete for "<name>"** or **Update complete for "<name>"** with counts:

- Import: **{count} prices set**, plus **{count} unmatched** when some rows were not matched.
- Update: **{count} added**, **{count} updated**, **{count} removed** (when any) and **{count} unmatched**.

The banner is green when every row matched and yellow when some did not, with the note "Some rows couldn't be matched (no matching SKU/Handle, ambiguous match, or invalid price). Download unmatched rows to fix and re-import."

Select **Download unmatched rows** to get `unmatched-<name>.csv` with the columns `row`, `sku`, `handle` and `reason`. The `row` number is the line in your file, counting the header as line 1. The file holds up to 2,000 unmatched rows; the unmatched count on screen is always the full number. Fix the rows and upload the complete file again with **Update from CSV**.

If the import fails, the window shows **The import failed: <reason> No price list was created. Please try again.** (or **The update failed: <reason> Your existing price list was left unchanged. Please try again.**), with a link to download the unmatched rows when there are any. The [CSV format reference](../reference/price-list-csv-format.md) lists every message.

## What your customers see

A price list created or updated from CSV works the same as one made in the editor. Logged-in customers with the `B2B` tag and the list's tag pay the list price at checkout, shown as a discount labeled `PW : <name>` on each line. See [what customers see for a price list](price-lists.md#what-your-customers-see). Customers get the new prices once the import shows complete.

## Limits and things to know

- **Up to 50,000 rows per file.** A larger file shows **Imports are limited to 50000 rows.** Remove the rows you do not need. Do not split one list across several files: each **Update from CSV** replaces the list, so only the last file's prices remain.
- **Up to 2,000 rows in the unmatched rows file.** Fix those and import again to see the next ones.
- **One file per import, `.csv` only.**
- **One import at a time per store.**
- **No thousands separators.** `1,299` is read as 1.299. `1,299.99` and `1.299,99` are both read as 1299.99. A comma alone is treated as the decimal separator, so `12,50` is 12.5.
- **A price of 0 is accepted** and makes the variant free for customers on the list. Negative prices are not imported.
- **Update replaces the whole list,** including removing variants whose rows did not match.
- **The import uses the name in the Name field.** Import creates a new list with that name; a name already used shows **A price list with the tag name "<name>" already exists. Please use a different tag name.** To change an existing list, open it and use **Update from CSV**.
- **Do not re-import a partial export.** Missing products are removed from the list.

## Troubleshooting

| Symptom                                                            | Likely cause                                                                                                                | Fix                                                                                                   |
| ------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| "Couldn't detect the required columns"                             | No accepted price header, or no SKU or Handle header. A Shopify product export uses `Variant Price`, which is not accepted. | Rename the price column to `Price` or `Fixed Price`, and make sure a `SKU` or `Handle` column exists. |
| Many rows unmatched                                                | SKUs or handles in the file do not match your store, or SKUs are shared by several variants                                 | Download unmatched rows and fix each row by its reason.                                               |
| "Couldn't start the import. A store export may already be running" | Another import or store export is running                                                                                   | Wait a minute and try again.                                                                          |
| Prices are 1,000 times too small                                   | The file uses commas as thousands separators                                                                                | Remove thousands separators and run **Update from CSV**.                                              |
| Products disappeared after an update                               | They were not in the file, or their rows did not match                                                                      | Export, add the missing rows and update again.                                                        |

For more cases, see [Price list CSV import problems](../troubleshooting/price-list-import-problems.md).

## Frequently asked questions

### Does Update from CSV replace the whole price list?

Yes. After an update the list holds exactly the variants matched in the file. Products in the list that are not in the file, or whose rows did not match, are removed.

### Can I import a Shopify product export as a price list?

Yes, after renaming one column. The product export's price column is `Variant Price`, which Process Wholesale does not recognize; rename it to `Price`. The `Variant SKU` and `Handle` columns are recognized.

### How many rows can a price list CSV have?

Up to 50,000 rows. The unmatched rows file holds the first 2,000 unmatched rows.

### How are CSV rows matched to my products?

By SKU first, then by Handle. A handle matches only a product with one variant, so use SKUs for products with several variants.

### Can I add a few products without replacing the list?

Not with **Update from CSV**, which replaces the list. Export the list, add rows to the exported file and upload the whole file, or add the products in the editor when the list has 200 products or fewer.

## Related articles

- [How to create a wholesale price list with fixed prices](price-lists.md)
- [Price list CSV format reference](../reference/price-list-csv-format.md)
- [Price list CSV import problems](../troubleshooting/price-list-import-problems.md)
- [How to assign discounts to wholesale customers](assign-discounts-to-customers.md)
