> For the complete documentation index, see [llms.txt](https://learn.withessential.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://learn.withessential.com/administration/settings/bulk-upload-pricebook-items-from-a-spreadsheet.md).

# Bulk upload pricebook items from a spreadsheet

To add many items at once, use Bulk Upload in the menu next to Add Item on Settings -> Items Pricebook. Download Template first to get a correctly formatted file, fill it in, then upload it. You can also upload an export from another system: Essential matches your column headers to its item fields automatically, and any column it can't use is listed as ignored in the preview.

The template covers every field on the Add Item form:

* **Code**, **Name**, and **Type** — required for every new row. Type accepts **Service** or **Physical Item**. Use Service for work and other nonphysical offerings, including software and licenses; use Physical Item for equipment, products, parts, and materials. Type is the item's accounting and reporting category; it does not turn Essential inventory tracking on by itself.
* **Description** — optional details shown under the item's name and copied onto quote and invoice lines.
* **Category** — the optional grouping label used by the Revenue by line item report's By category view. Type is not a category: a file can carry both a Type column (Service / Physical Item) and a Category column (for example "Fire extinguisher" or "New Material"), and each goes to its own field. Leave the cell blank for no category; the reserved name "Uncategorized" is treated as blank. Older files that have no Type column and use a column named Category (or Item Category / Product Category) to hold Service or Physical Item are still read that way: when every value in it is a type, that column is treated as the Type.
* **Price**, **Cost**, and **Taxable** — Price and Cost are dollar amounts; Taxable accepts Yes/No, and an unrecognized value is treated as Yes with a preview warning. Leaving Price blank when the Price column is present sets that item's price to $0.00 — on new items and on existing ones being updated — with only a preview warning flagging it, so review it before confirming.
* **Track inventory in Essential** and **Inventory reorder level** — see below.
* **Name shown to supplier** and **Code shown to supplier** — the supplier-facing defaults used on purchase order documents in place of the item's own name and code. Leave them blank to send your item's own name and code.
* **Photo** — the file name of a photo you upload along with the spreadsheet (see [Add photos in the same upload](#add-photos-in-the-same-upload)).
* **Revenue account** — only in the template when **Map pricebook items to different revenue accounts** is turned on (Settings → Invoicing → Accounting). Enter the name of a QuickBooks income account as it appears in the item form's Revenue account list (capitalization and a leading account number don't matter); the template's example rows use your own account names. A QuickBooks Desktop full name such as `Income:Services` also works: it matches the account named Services, and a plain `Services` matches an account stored as `Income:Services` when no other account ends in Services. Leave the cell blank to use the fallback revenue account. This column never stops a row from importing. A name that matches no account, or more than one, shows a preview warning and leaves that item's revenue account as it was (a new item uses the fallback). If no QuickBooks income accounts are connected, the column is ignored with a warning on each row that has a name, so a file such as a QuickBooks Online Products and Services export, whose Income Account column is read as this column, still imports. See [Account mapping for QuickBooks](/reporting-and-integrations/accounting/account-mapping-for-quickbooks.md).

If your business uses inventory, set **Track inventory in Essential** to Yes for Physical Item rows whose on-hand quantities Essential should maintain. Tracked rows can also have an Inventory reorder level. Tracking is ignored for Service rows. Older type values such as Inventory, Non-inventory, Item, Product, Part, and Material are accepted as Physical Item for compatibility. Older template columns named Inventory Item are still recognized as the separate tracking choice.

Before anything is saved, a preview shows what will be created, what will be updated, and which rows are skipped for errors, so you can review and fix issues. The preview also shows how each of your columns was matched and which columns were ignored — for example an Active, Status, or internal ID column from another system is skipped rather than imported. New rows default tracking to No when that column is absent.

Updates match existing items by Code and only change the columns present in your file. If the code belonged to an item you'd previously removed, re-importing it restores that item instead of creating a new one. A partial update file can leave out Type, Category, tracking, or the supplier columns to keep an existing item's current values; a blank Type cell also keeps an existing item's type, while every nonblank value must be valid. When a text column such as Description, Category, Name shown to supplier, or Code shown to supplier is present, a blank cell clears that value on the existing item; blank Cost and reorder level cells keep the existing values. Confirm to import the valid rows. This is the fastest way to load or update a large pricebook.

![Bulk upload preview with type and inventory tracking](https://3838208579-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Flu1pgNH0CrkCPslG8suQ%2Fuploads%2Fgit-blob-be4ee82312f5fd894337965e92f91a967857fa36%2Fsettings-items-bulk-upload-preview.png?alt=media)

## Add photos in the same upload

Bulk Upload also takes item photos. Drop or choose them together with your spreadsheet: photo files (JPG, PNG, HEIC, WEBP, GIF, or BMP, up to 15 MB and 40 megapixels each), a .zip of photos, or both. A HEIC photo whose size Essential can't read from the file is refused when it uploads; export it as a JPEG and try again. Upload one spreadsheet at a time. One upload takes up to 10,000 photos, and the photos inside your .zip files can add up to at most 1 GB once unzipped — split a larger set into several uploads. Each .zip file can be at most 512 MB; split a larger archive into several .zip files.

Essential matches each photo to an item in one of two ways:

* **By code** — name each photo after the item's code, such as `PUMP-220.jpg` for the item with code PUMP-220. Upper and lower case don't matter. Only the name without its extension is compared, so an item whose code itself ends in an image extension (such as `PUMP.jpg`) needs a Photo column. If two codes differ only in capitalization (such as `PUMP` and `pump` as two rows of your spreadsheet, or as two of your items when you upload only photos), a photo goes only to the code its name spells exactly, so `PUMP.jpg` goes to PUMP. A photo that spells neither exactly (such as `Pump.jpg`) isn't used: those rows show a warning that the photo matches more than one item code. Rename the photo to the exact code, or use a Photo column.
* **By a Photo column** — when your spreadsheet has a Photo column, each row's Photo cell names its photo file, such as `pump-front.jpg`. Capitalization doesn't matter, and a cell matches a file with the same name even if the extension differs. When the column is present, photos are matched only through it.

The preview adds a **Photo** column showing which photo each row will get. A row whose Photo cell names a file you didn't upload shows **Not found:** and the file name; the row still imports, without changing the item's photo (a new item is added without one). Photos that didn't match any row are listed above the table and aren't imported. A blank Photo cell never removes an item's existing photo — remove a photo from the item's Edit Item form instead.

When you confirm, Essential uploads the matched photos first, showing its progress (for example, "Uploading photos 12 of 40…"), and then imports the rows. If any photo can't be uploaded, nothing is imported and a message names the photo to fix.

### Update only photos

To add or replace photos on items you already have, upload just the photos (or a .zip of them) with no spreadsheet, each named after its item's code. The preview shows "Updating photos for N items matched by code" and lists any photos whose names didn't match a code. A photo that matches two codes differing only in capitalization, without spelling either exactly, isn't used: both items show as errors with the reason, and you can rename the photo to the exact code and upload it again. Confirm to update only the matched items' photos; nothing else about the items changes.

Photos are internal: they show in Essential and in the technician app, never on customer quotes, invoices, or the customer portal. See [Add or edit a pricebook item](/administration/settings/add-or-edit-a-pricebook-item.md#add-a-photo-to-an-item).

> **Where to find it:** Settings -> Items Pricebook, the menu next to Add Item (Bulk Upload, Download Template)

## Related guides

* [Add or edit a pricebook item](/administration/settings/add-or-edit-a-pricebook-item.md)
* [Add the intake form to your website](/administration/settings/add-the-intake-form-to-your-website.md)
* [Automate task statuses with Task Automations](/administration/settings/automate-task-statuses-with-task-automations.md)
* [Build your intake form](/administration/settings/build-your-intake-form.md)
* [Choose your default home page](/administration/settings/choose-your-default-home-page.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://learn.withessential.com/administration/settings/bulk-upload-pricebook-items-from-a-spreadsheet.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
