Importing Products
What Kassly can and cannot bulk-load from a spreadsheet, the exact columns of each import sheet, and what happens when a row is wrong.
19 min read · Updated 25 Oct 2026
On this page
- What the three sheets do
- How a sheet import works
- File format
- Importing from Loyverse
- The products sheet
- Sizes and flavours: one product with variants
- The same name in two categories
- The ingredients sheet
- How rows are matched
- The compositions sheet
- The bulk stock-in sheet
- What happens to a bad row
- Re-uploading a sheet
- The Free plan and imports
- Getting data out
Kassly has four spreadsheet importers. Between them they cover sellable products, raw materials, recipes and stock quantities — and they are worth knowing about before you type a hundred rows by hand.
What the three sheets do
| Sheet | Where to start | What it creates or changes | Add-on needed |
|---|---|---|---|
| Products | Catalog → Products → Import | Creates and updates sellable products: prices, category, VAT, stock tracking, reorder points, opening stock and preferred supplier | None |
| Ingredients | Inventory → Ingredients → Import | Creates and updates raw-material products, their costs, units, reorder points and opening stock | None |
| Compositions | Inventory → Compositions → Import | Creates and updates recipes and their ingredient lines | Recipe Costing (₱350 per branch each month) |
| Bulk Stock-In | Inventory → Stock Levels → Bulk Stock-In → Import from Excel | Adds quantities to products that already exist. Creates nothing | None |
Two sheets create catalog rows: the products sheet for things you sell, and the ingredients sheet for raw materials. They are kept apart on purpose — a product row never rewrites a raw material of the same name.
Only an Owner or a Manager can import.
How a sheet import works
All four follow the same three steps, and it is worth doing them in order:
- Download the template. It comes back already filled in with what you have, so you are editing your own data rather than guessing at a format.
- Fill it in. Edit an existing row to update that item; type new rows underneath to add.
- Upload it back. Kassly checks every row before it writes anything.
File format
| Accepted | .xlsx and .xls. The products import also takes .csv (a Loyverse export, or the products template saved as CSV) |
| Not accepted | Google Sheets links, PDF, ODS |
| Maximum size | 5 MB |
CSV works for products only. The ingredients, compositions and bulk
stock-in imports still need .xlsx: open your CSV in Excel, Numbers or Google
Sheets and save it as .xlsx first.
Each template also arrives with a second tab called How to use, which repeats the column rules next to the sheet itself. Do not rename the first tab — the importer looks for it by name and falls back to whichever sheet is open, which is not always the one you meant.
Importing from Loyverse
Moving over from Loyverse? You don't need our template. Upload the items file Loyverse gives you, exactly as it is.
- In Loyverse Back Office, go to Items → Item list and click Export. Loyverse downloads a CSV file.
- In Kassly, go to Catalog → Products → Import.
- Pick the branch that should receive your stock. If your Loyverse account has several stores, pick the Kassly branch with the same name as the store you want. Kassly reads that store's price and stock columns.
- Choose the Loyverse CSV and click Import.
What comes across:
| Loyverse column | Becomes in Kassly |
|---|---|
| Name | Product name |
| Category | Category (created if it doesn't exist; blank goes to Uncategorized) |
| Default price, or the store's Price | Selling price. A blank price means "set at the counter", so the item allows a custom price |
| Cost (or Purchase cost) | Cost price |
| SKU | SKU |
| Barcode | Barcode, leading zeros kept |
| Option 1–3 name / value | Variants. Rows sharing a Handle become one product with a variant per row, e.g. Small / Large |
| Track stock | Track Stock |
| In stock (for the chosen store) | Opening stock at the branch you picked, for items new to Kassly |
| Low stock | Reorder point |
| Sold by weight | Sold by weight, in kg |
| Available for sale | Show in POS |
| Supplier | Preferred supplier, if it matches one on your Suppliers page |
| Description | Description |
What doesn't come across, and is listed after the import so you can finish it by hand:
- Composite items. The item imports, but its "included items" don't. Build the recipe under Compositions.
- Modifiers. Set up your modifier groups under Modifiers.
- Taxes. Loyverse tax columns are ignored and items import as Vatable. Change the VAT setting on any exempt item.
- Negative stock. An item below zero in Loyverse imports without opening stock. Count it and adjust it in Kassly.
Uploading the same Loyverse file again updates your items instead of adding them twice. Stock is only added for items that are new to Kassly, so a second upload never doubles your counts.
The same all-or-nothing rule applies: a bad price or a repeated SKU rejects the whole file with a list of rows to fix.
Loyverse customer exports can't be imported yet. Kassly has no customer importer; send the file through Free setup help on your dashboard and we'll load it for you.
Not on Loyverse, or your list is in some other shape? The dashboard's Free setup help card lets you send us any spreadsheet, and we'll import it for you during your first two weeks.
The products sheet
Start from Catalog → Products → Import. The Export button beside it downloads the same sheet without opening the dialog, which is the quickest way to get your product list into a spreadsheet.
Not signed up yet, or keeping your stock list in Excel? The free inventory list template at kasslypos.com/tools has these same columns, with three example rows and stock value and margin formulas. Fill it in and upload it here as it is. Delete the example rows first, and pick a branch so the Opening Qty lands somewhere. The two grey formula columns after the last heading are ignored on import.
Nineteen columns, in this order.
| Col | Heading | Required | Notes |
|---|---|---|---|
| A | Name | Yes | What the item is called on the menu or shelf. |
| B | SKU | No | Blank generates one. Keep it to update the product on a re-upload. |
| C | Barcode | No | Scanned at the counter. |
| D | Category | On a new product | A category that doesn't exist yet is created, so watch the spelling. |
| E | Cost Price | No | Blank on a new product means 0. |
| F | Selling Price | On a new product | What the customer pays. |
| G | VAT | No | Vatable, VAT Exempt or Zero Rated. Defaults to Vatable. |
| H | Track Stock | No | Yes or No. |
| I | Stock Unit | No | One of the stock units, e.g. pc, kg, L. Only matters when Track Stock is Yes. |
| J | Opening Qty | No | Stock to add at the branch you pick. Needs Track Stock set to Yes. |
| K | Reorder Point | No | Warn when stock falls to this level. Only saved if you pick a branch. |
| L | Show in POS | No | Yes or No. |
| M | Active | No | Yes or No. |
| N | Description | No | Shown on the online store and receipts. |
| O | Sold By | No | Per piece (default) or By weight/volume/length. |
| P | Supplier | No | The preferred supplier. Must match a name on your Suppliers page; capitals don't matter. |
| Q | Supplier SKU | No | The supplier's own code for the item. Up to 100 characters. |
| R | Reorder Qty | No | How much Inventory → Reorder suggests ordering at the selected branch. Blank leaves it as it is. |
| S | Variant | No | A size or flavour, e.g. 16oz or Iced. Rows with the same Name and Category and a Variant become one product with variants. See below. |
How rows are matched and written:
- A row updates the product with the same SKU (capitals don't matter), anywhere in your catalog. A row with a blank SKU matches a sellable product of the same name in the same category instead, and never a raw material.
- A blank cell on an existing product leaves that field alone. Only what you type overwrites what is there, so deleting a column by accident changes nothing.
- Pick a branch in the dialog if you fill in Opening Qty or Reorder Point — both are per branch.
- Suppliers are matched, never created. A supplier carries contact details and a TIN the sheet can't supply, so add new suppliers on the Suppliers page first. A name that matches no supplier — or more than one — does not stop the upload: the rest of the row imports, the product's supplier is left as it was, and the dialog lists the skipped cells after the import. See Suppliers.
A sheet downloaded before the Supplier columns existed still imports; its empty P and Q columns simply leave suppliers alone.
Sizes and flavours: one product with variants
An item you sell in sizes or flavours, such as 12oz and 16oz or Hot and Iced, is one product with variants. In the sheet, give each variant its own row: the same Name and Category on every row, and the size or flavour in Variant.
| Name | SKU | Category | Cost Price | Selling Price | Track Stock | Opening Qty | Variant |
|---|---|---|---|---|---|---|---|
| Iced Coffee | Drinks | 35 | 90 | Yes | 20 | 12oz | |
| Iced Coffee | Drinks | 42 | 110 | 15 | 16oz | ||
| Iced Coffee | Drinks | 50 | 130 | 10 | 22oz |
Those three rows import as one product, Iced Coffee, with three variants. The columns not shown are left blank.
Some columns belong to each variant, and the rest to the product as a whole:
| Belongs to | Columns |
|---|---|
| Each variant, on its own row | SKU, Barcode, Cost Price, Selling Price, Opening Qty, Reorder Point, Reorder Qty |
| The whole product | VAT, Track Stock, Stock Unit, Show in POS, Active, Description, Sold By, Supplier, Supplier SKU |
Fill a product-wide column on one row, or repeat it on every row, but the rows that fill it in must agree. Track Stock is Yes on the first row above, which is enough for all three. Rows that disagree are refused: "Row 5: "Iced Coffee" has VAT "VAT Exempt" here but "Vatable" on row 3. Its variants share one VAT, so make the rows match or leave this cell blank."
The rules:
- An item needs two to 50 variants, as on the product form. A Variant on a single row is refused, because one variant would just repeat the product: clear the Variant cell to sell it as a single item.
- A new variant needs a Selling Price.
- Each variant name appears once per item.
- A variant's SKU must be its own, not one of your products' SKUs. Leave it
blank and Kassly numbers it the way the product form does: the product's SKU
followed by
-1,-2and so on. - Opening Qty goes to each variant's own stock at the branch you pick, and needs Track Stock set to Yes.
Updating works the same way. The template lists a product that already has variants as one row per variant, with Variant filled in, so uploading it unchanged changes nothing. A row updates the variant with its SKU or, when the SKU is blank, the variant of that name on that product. A new Variant name adds a variant. A variant you leave out of the sheet is left as it is: the import never deletes one.
To update a variant, name the product in Name and the variant in Variant. A row without a Variant whose SKU belongs to a variant is refused with a note saying exactly that: "Row 7: SKU "IC-16" is the "16oz" variant of "Iced Coffee". To update it, put "Iced Coffee" in Name and "16oz" in Variant."
Kassly finds the Variant column by its heading, not its letter, so keep the heading Variant. A sheet without that column imports as before, every row a single product.
The same name in two categories
A row without a SKU is identified by its Name within its Category, so a Green Apple soda under Drinks and a Green Apple yoghurt under Yoghurt are two different products. There is no need to number one of them.
- The same Name twice in one Category, with no SKU or Variant, is refused: "Row 9: "Green Apple" is repeated on row 4. Give each row a unique name or SKU, or list the sizes or flavours of one item in the Variant column."
- A name the sheet lists under more than one category needs its Category filled in on every row with that name.
- A name your catalog already holds more than once needs a Category or a SKU on the row, or Kassly can't tell which product you mean: "… matches 2 products in your catalog. Fill in its Category or SKU to say which one."
- Moving a product to another category still works. If your catalog has the name only once and the sheet lists it under one category, the row updates that product and moves it there. Once a name is in more than one category, a row for a new category creates a new product instead.
The ingredients sheet
Seven columns, in this order.
| Column | Header | Required | What to put in it |
|---|---|---|---|
| A | Name | Yes | What you call the raw material. |
| B | SKU | No | Leave blank and one is generated. Keep the existing value to update rather than duplicate. |
| C | Stock Unit | Yes | One of pc, g, kg, ml, L. Blank is read as pc. The column has a dropdown. |
| D | Cost per Unit | Yes | The cost of one Stock Unit — not the price of a whole sack. Sub-centavo values are kept to four decimals. |
| E | Opening Qty | No | Stock to add at the selected branch. |
| F | Reorder Point | No | Warn when stock falls to this level. |
| G | Notes | No | Recorded against the opening stock movement. |
| H | Reorder Qty | No | How much Inventory → Reorder suggests ordering at the selected branch. Blank leaves it as it is. |
The template lists your existing ingredients first and leaves about fifty blank rows underneath to type into. It reads up to about 2,000 rows.
Two things to be careful about:
- Opening Qty adds, it does not set. The template deliberately leaves it blank on existing rows. Fill it in on a re-upload and you will add that quantity a second time.
- Opening Qty and Reorder Point need a branch. Both are per branch, so pick one in the dialog. Upload a sheet with quantities and no branch selected and Kassly stops you: "Pick a branch before importing opening quantities — stock has to land somewhere."
How rows are matched
For each row, Kassly looks for an existing ingredient:
- by SKU, ignoring capitalisation, then
- by exact name, ignoring capitalisation and surrounding spaces.
A match updates the name, unit and cost. No match creates a new ingredient.
Matching only looks at items already flagged as ingredients. A row named after an ordinary product you have not flagged will create a second, ingredient-flagged copy instead of updating it. Flag the item as an ingredient first — the Products page can do it in bulk — then import.
The compositions sheet
This one is in long format: one row per ingredient line. Rows that share the same Menu Item, Variant and Composition Name make up one recipe.
| Column | Header | Required | What to put in it |
|---|---|---|---|
| A | Menu Item SKU | One of A or B | The item you sell. Matched first. |
| B | Menu Item | One of A or B | Used when the SKU is blank. |
| C | Variant | No | Leave blank if the recipe applies to every size or option. |
| D | Composition Name | Yes | e.g. Chicken Adobo Standard. Repeat it on every row of the recipe. |
| E | Yield | No | Servings the listed quantities make. Blank is read as 1. Repeat it on every row. |
| F | Ingredient SKU | One of F or G | Must already exist. |
| G | Ingredient | One of F or G | Used when the SKU is blank. |
| H | Quantity | Yes | How much of the ingredient the whole yield uses. |
| I | Unit | No | Defaults to the ingredient's stock unit. Any packaging conversion you have set up also works. |
| J | Waste % | No | 0 to 99.99. |
| K | Producible (commissary) | No | yes only for batches produced at a commissary. These are not deducted at the point of sale. |
You need either the SKU or the name for the menu item, and either the SKU or the name for the ingredient. The SKU wins when both are filled in.
Ingredients must exist before you import recipes. The sheet cannot create them. Run the ingredients import first, or add them on the Ingredients page.
Two rules protect what you already have:
- A recipe you leave out of the sheet is untouched. A partial sheet is never a mass delete.
- A recipe that is in the sheet has its ingredient lines replaced by whatever the sheet says. Half a recipe in the sheet means half a recipe afterwards.
It reads up to about 5,000 rows, which is a lot of recipes.
The bulk stock-in sheet
This one changes quantities only — it never creates or edits a product. It also requires you to pick a branch.
| Column | Header | Notes |
|---|---|---|
| A | product_id | Filled in for you. Do not edit or clear it. |
| B | variant_id | Filled in for you. Leave alone. |
| C | Product Name | For your reference. |
| D | SKU | For your reference. |
| E | Variant | For your reference. |
| F | Current Qty | What is on hand now. For your reference. |
| G | Quantity to Add | The one column you fill in. Must be at least 0.01. |
| H | Cost Price | Optional. The cost of this batch. |
| I | Batch Number | Optional. |
| J | Expiry Date (YYYY-MM-DD) | Optional, except for an item set to Require expiry date on stock-in. |
| K | Notes | Optional. |
Leave a row's Quantity to Add blank and that row is skipped. A row for an item set to Require expiry date on stock-in must have its Expiry Date filled in, or the upload is refused and that row listed: "Paracetamol 500mg needs an expiry date. Enter the date printed on the pack."
Batch numbers and expiry dates are only meaningful with the Inventory Pro add-on — see Batch and expiry — and receiving against a purchase order is a different, better-documented path: see Receiving stock.
What happens to a bad row
All four importers are all-or-nothing. If one row is wrong, nothing at all is saved — you never end up with half a catalog and no idea which half.
Instead the dialog shows a list, in place, under the heading "Nothing was saved — fix these rows and upload again", with one line per problem naming the row number. For example:
Row 14: Cost per Unit must be a number of 0 or more.
Row 22: "Kalamansi" is repeated on row 9. Give each row a unique name or SKU.
Row 31: no ingredient found for "Patis". Add it on the Ingredients page (or import it) first.
The checks that will stop an import:
| Sheet | Rows are rejected for |
|---|---|
| Products | Missing name; no category or selling price on a new product; a non-numeric or negative cost, price, opening quantity or reorder point; an unrecognised VAT setting, stock unit or Sold By value; a Yes/No column that is neither; an opening quantity on an item that doesn't track stock; the same SKU twice; the same name twice in one category when the SKU and Variant are blank; a name that matches several products, with no Category or SKU to say which; a Supplier SKU over 100 characters. For an item with variants: only one variant, or more than 50; the same variant twice; a new variant with no selling price; product-wide columns that disagree between its rows; a variant SKU that belongs to a product, or a product row whose SKU belongs to a variant. |
| Ingredients | Missing name; an unrecognised stock unit; a non-numeric or negative cost, opening quantity or reorder point; the same SKU twice; the same name twice when the SKU is blank; a SKU that already belongs to a product that is not an ingredient. |
| Compositions | A menu item or ingredient that cannot be found; a missing composition name; an ingredient that does not track stock, since it would never deduct; a quantity of zero or less; a yield of zero or less; waste outside 0–99.99; a variant name the item does not have; the same ingredient twice in one recipe. |
| Bulk Stock-In | A quantity below 0.01; no Expiry Date on an item set to Require expiry date on stock-in. |
Fix the sheet and upload it again. Nothing was written, so there is nothing to undo.
Entirely blank rows are ignored, not treated as errors — the templates ship with spare rows on purpose.
One thing is reported without rejecting the file: on the products sheet, a Supplier name that matches no supplier. That row still imports, and the dialog stays open after the import with a note naming the row, so you can add the supplier and set it on the product page.
Re-uploading a sheet
Re-uploading is the normal way to make bulk changes, and both catalog importers are built for it: download, edit, upload, repeat. The one thing that does not survive a careless re-upload is the ingredients sheet's Opening Qty, because it adds rather than sets. Clear that column before you upload again.
The Free plan and imports
New rows count against the Free plan's 50-item limit, and the check happens before anything is written:
"This file would add 40 new items but only 12 remain on your plan. Subscribe to any add-on to unlock unlimited SKUs."
Rows that update an existing item do not count, and an item with variants counts once, however many variant rows it has. See Plans and add-ons.
Getting data out
Exports are separate from imports and more widely available:
- Compositions — the Export CSV button on the Compositions page gives you the whole filtered list with cost per serving and cost percentage.
- Products — the Export button on the Products page downloads the products sheet, pre-filled with your catalog.
- Templates as exports — because every template arrives pre-filled with your current data, downloading one is also the quickest way to get your ingredient list or your recipes into a spreadsheet.
A full reference of every file format Kassly reads and writes is collected in Import formats.