Import products
Add or update many products at once by uploading a file in the Tokenz Dashboard, instead of creating them one by one.
Open Products, then select Import products. Products are managed in live mode, so switch off test mode first.
Before you start
The Import products button appears only when your role has all of these permissions. Ask an admin to add any that are missing.
| Group | Permissions |
|---|---|
| Catalog items | View catalog items, Create catalog items, Edit catalog items |
| Price plans | View price plans, Create price plans, List price plans |
Choose a format
| Format | Use it when |
|---|---|
CSV (.csv) | Most catalogs: one price per product, one image URL per product. Easy to export from a spreadsheet. |
JSON (products.json) | You need prices per region or more than one image per product. Every image is a URL. |
ZIP (products.json + images) | Same as JSON, but you want to upload the image files together with the manifest. |
All formats use the same rules: products are matched by sku, and the import only adds or updates products. It never deletes a product that is missing from the file.
CSV format
File rules
- Encoding is UTF-8, with or without the byte order mark (BOM) that Excel adds. Japanese Excel's plain "CSV" (Shift_JIS) and Excel's "Unicode Text" (UTF-16) are also read. See Save a CSV from a spreadsheet.
- Values are separated by commas. Semicolon and tab separated files also work: the separator is detected from the header row.
- Prices use a dot for decimals, such as
7.50. A decimal comma (7,50), a currency symbol (¥480) or a thousands separator (1,000) is reported as not a number. - Wrap a value in double quotes if it contains the file's separator (a comma, or a semicolon or tab in those files), a double quote or a line break. Write a double quote inside a value as
"". For example, in a semicolon-separated file:gem-pack-500;500 Gems;"500 gems; added instantly.";480;JPY - The first row must be a header row. Header names are case-insensitive. Empty columns and blank rows that a spreadsheet adds are ignored.
- Row numbers in messages count data rows: the first row under the header is row 1.
- A CSV or JSON file can be up to 25 MB. There is no limit on the number of rows.
Columns
| Column | Required | Description |
|---|---|---|
sku | Yes | Your unique product ID. Importing the same sku again updates that product. |
name | Yes | Product name. |
description | Yes | Product description. The column must be present, but the value may be empty. |
price | Unless free is true | Price as a number in the currency's normal unit, for example 480 for ¥480 or 4.99 for $4.99. |
currency | When price is set | ISO 4217 currency code, for example JPY or USD. See Supported currencies. |
free | No | true for a free product. Leave price and currency empty. |
category | No | Category name. A category that doesn't exist yet is created. |
taxCategory | No | virtualCurrency, digitalGoodsAndServices, eBook or saas. Default: virtualCurrency. |
publish | No | true publishes the product. Default: false, which saves it as a draft. |
image_url | No | One public https image URL. |
Boolean columns (free, publish) accept true/false, yes/no or 1/0.
Example
Three game items priced in JPY. The second row shows quoting, and the third is a free item.
sku,name,description,price,currency,free,category,taxCategory,publish,image_url
gem-pack-500,500 Gems,"500 gems, added to your account instantly.",480,JPY,false,Gems,virtualCurrency,true,https://cdn.example.com/items/gem-pack-500.webp
starter-bundle,Starter Bundle,"1,200 gems and the ""Rookie"" badge.",1980,JPY,false,Bundles,virtualCurrency,false,https://cdn.example.com/items/starter-bundle.webp
daily-gift,Daily Free Gift,One free reward per day.,,,true,Free gifts,virtualCurrency,true,
Save a CSV from a spreadsheet
Start from the template: select Download template in the import dialog, fill it in, and save it as CSV.
Microsoft Excel
- Use File > Save As (or Save a Copy) and choose CSV UTF-8 (Comma delimited) (*.csv). This is the recommended format in every language.
- On a Japanese system, Excel's default CSV (Comma delimited) saves the file as Shift_JIS. That works too, and Japanese text imports correctly.
- In regions that use a decimal comma, such as much of Europe, Excel saves "CSV" with semicolons and writes prices like
7,50. The semicolons are detected, but a decimal comma is not read as a price. Before saving, make the decimal separator a dot (in Excel for Windows, File > Options > Advanced, clear Use system separators and set Decimal separator to.), or type the prices as text with a dot. - Excel turns long numeric SKUs such as
123456789012into1.23457E+11and drops leading zeros. Format theskucolumn as Text before you enter the SKUs. A SKU saved in scientific notation is refused, because its digits are already lost.
Google Sheets
Use File > Download > Comma-separated values (.csv). The file is UTF-8 and imports as it is.
Apple Numbers
Use File > Export To > CSV. Keep Text Encoding set to Unicode (UTF-8).
JSON format
A JSON import is a single manifest named products.json. Upload it on its own when every image is a URL, or inside a ZIP when it refers to image files.
Manifest
| Field | Required | Description |
|---|---|---|
version | Yes | Always 1. |
defaults | No | Values used by every product that doesn't set its own: currency, taxCategory, category and publish. |
products | Yes | The list of products. |
Product fields
| Field | Required | Description |
|---|---|---|
sku | Yes | Your unique product ID, with no leading or trailing spaces. |
name | Yes | Product name. |
description | Yes | Product description. Use "" for none. |
price | One pricing field | A single price as a number, in the currency's normal unit. |
free | One pricing field | true for a free product. |
regionPrices | One pricing field | Prices per region, keyed by 2-letter country code, for example { "JP": 980, "US": 6.99 }. Each region uses its own currency. The first entry is the price for every region you don't list. |
currency | No | Currency of price. Defaults to defaults.currency, then JPY. Not allowed with regionPrices. |
category | No | Category name. Created if it doesn't exist. |
taxCategory | No | virtualCurrency, digitalGoodsAndServices, eBook or saas. |
images | No | Image paths or URLs. The first image is the main image. |
publish | No | true to publish, false to save as a draft. Must be a real boolean, not a string. |
Each product needs exactly one pricing field: price, free: true or regionPrices.
Example
{
"version": 1,
"defaults": {
"currency": "JPY",
"taxCategory": "virtualCurrency",
"publish": false
},
"products": [
{
"sku": "starter-bundle",
"name": "Starter Bundle",
"description": "1,200 gems and the Rookie badge.",
"price": 1980,
"category": "Bundles",
"images": ["images/starter-bundle.webp"]
},
{
"sku": "daily-gift",
"name": "Daily Free Gift",
"description": "",
"free": true,
"images": ["https://cdn.example.com/items/daily-gift.webp"],
"publish": true
},
{
"sku": "gem-pack-1200",
"name": "1,200 Gems",
"description": "Priced for each region.",
"regionPrices": { "JP": 980, "US": 6.99, "GB": 5.99 },
"category": "Gems",
"images": [
"images/gem-pack-1200.webp",
"https://cdn.example.com/items/gem-pack-1200-alt.webp"
]
}
]
}
Package images in a ZIP
When any image is a relative path, such as images/starter-bundle.webp, upload a ZIP with products.json at its root. Relative paths are read from inside the ZIP.
products.zip
products.json
images/
starter-bundle.webp
gem-pack-1200.webp
Prices
Write every price in the currency's normal unit (480 for ¥480, 4.99 for $4.99), as a number greater than 0. This applies to price in CSV and JSON and to every amount in regionPrices.
- Decimals. A price can't have more decimal places than its currency uses. JPY and KRW have none, so
480.5JPY is refused. Most currencies, such as USD and EUR, use 2. A few, such as BHD and KWD, use 3. See Supported currencies for each currency's decimals. - Maximum. The largest price is 99,999,999.99, scaled to the currency's decimals:
| Currency decimals | Example currencies | Maximum price |
|---|---|---|
| 0 | JPY, KRW | 99,999,999 |
| 2 | USD, EUR | 99,999,999.99 |
| 3 | BHD, KWD | 99,999,999.999 |
The preview checks every price before anything is written, so a price that breaks these rules stops the import with a message naming the row.
Images
- Formats: WebP, PNG, JPEG or GIF.
- Each image can be up to 25 MB. Empty files are rejected.
- Image URLs must be publicly reachable. URLs that need a login, and private or local addresses such as
localhost, are rejected. - CSV takes one URL per product in
image_url. Use JSON or a ZIP for several images or for image files. - When you update a product, leaving out its images keeps the images it already has.
Re-import and updates
Products are matched by sku:
- New
sku: the product is created. - Existing
sku: the product is updated with the values in the file. This is the default. skunot in the file: the product is left as it is. An import never deletes products.
To add new products without touching existing ones, select Create only (skip existing SKUs) before you import. Rows whose sku already exists are skipped and counted as skipped in the result.
A few things an import doesn't change on an existing product:
- Price of an existing plan. If the product already has a plan for the same billing interval (for example, its one-time price) at a different price, the row keeps the current price. The rest of the row is still updated, and the result notes "price not applied". To change the price, open the product in the Dashboard and change it there. Replacing a plan's price is a separate step that can't be undone, so an import never does it.
- Tax category. It is set when the product is created.
Import steps
- Select Import products and upload your
.csv,products.jsonor.zipfile. - Review the preview. Each row shows whether it will be created, updated or skipped, and any errors.
- Fix any errors and upload again. Nothing is written while the file has errors.
- Select Import. Progress is shown as products are created and updated.
- Review the result: how many products were created, updated, skipped and failed, with a reason for each failure.
Common errors
The import dialog shows each problem with the row it is on and the SKU, for example "Row 3 (SKU gem-pack-500): add a currency for the price, such as USD or JPY." In a JSON file, products are numbered by position ("Product 2 (SKU …)"). Nothing is written while any problem remains: fix the file and upload it again.
File problems
These stop the file from being read at all.
| Message | Fix |
|---|---|
| Add these columns to the header row: sku, description. | Add the missing required columns. sku, name and description are always required, even when description is empty. Start from the template if in doubt. |
| Unknown columns: … Rename or remove them. | Rename the column to one of the listed columns, or delete it. |
| … can't be imported from a CSV. | The column, such as regionPrices, needs JSON. See Choose a format. |
| These columns appear more than once: … | Keep one column of each name. |
| Column 7 has no name but row 2 has a value in it. | A header cell was deleted while the column still has data. Type the header back, or delete the whole column. |
| Row 4: a quoted value is never closed. | A value starts with " but never ends with one, so the rest of the file reads as one value. Add the closing quote, or remove the stray one. |
| Row 4: there is text after a closing quote. | Put the whole value inside the quotes, and write a quote mark inside it as "". |
| Row 5 has more values than the 10 columns in the header. | A value contains the file's separator (a comma, or a semicolon or tab) but isn't quoted, so later values shifted columns. Wrap that value in double quotes. |
| This CSV's text encoding can't be read. | Save the file again as CSV UTF-8 from Excel, or download it again from Google Sheets or Numbers. |
| This file has a header row but no products. | Add one product per row under the header. |
| This file is larger than 25MB. | Split the catalog into several files and import them one after another. |
| The ZIP has no products.json. | Put products.json at the top level of the ZIP, not inside a folder. |
Row problems
| Message | Fix |
|---|---|
| price "7,50" isn't a number. | Use a dot for decimals (7.50), with no currency symbol or thousands separator. See Save a CSV from a spreadsheet if Excel writes decimal commas. |
| JPY allows 0 decimal places, so 480.5 can't be charged. Round the price. | Round to the decimals the currency uses. JPY and KRW have none. See Prices. |
| price 150000000 is above the maximum of 99,999,999 JPY. | Use a price within the maximum for the currency. |
| add a currency for the price, such as USD or JPY. | In CSV, every row with a price needs a currency. |
| currency … isn't supported. | Use a code from Supported currencies. |
| another row uses SKU … too. Give each product its own SKU. | Each sku may appear only once per file. Change or remove the duplicate row. |
| SKU 1.23457E+11 looks like a number Excel turned into scientific notation. | Format the sku column as Text, enter the SKUs again and save. |
| add a SKU. / remove the spaces before or after the SKU. | Give every row a sku, with no spaces around it. |
| add a name. / add a description. | Fill in name. Include description, even if it is empty. |
| add a price and currency, or set free to true. | Set a price and currency, or mark the product free. |
| set a price or set free to true, not both. | For a free product, leave price and currency empty. |
| price must be more than 0. | Use a positive price, or leave it empty and set free to true. |
| taxCategory "…" isn't valid. | Use virtualCurrency, digitalGoodsAndServices, eBook or saas. |
| publish is "…". Set it to true or false. | Use true/false, yes/no or 1/0 in CSV. In JSON, write true or false without quotes. |
| image_url "…" isn't a full https URL. | Use a complete link that starts with https://. |
| A product uses an image that isn't in the ZIP. | Add the file to the ZIP at the same path, or fix the path. Paths are case-sensitive. |
| A product uses an image that is empty or larger than 25MB. | Replace the file with a smaller image. |
| Set version to 1. | Set "version": 1 in products.json. |
After the import
The result lists each row that failed or was changed less than the file asked, with a note in English.
| Note | What it means |
|---|---|
| price not applied: this interval already has a plan… | The product kept its current price. See Re-import and updates to change it. |
| sku already exists | You chose Create only, so the existing product was skipped. |
| sku belongs to another product | The SKU is in use by a product the import can't update. Use a different SKU. |
If text looks garbled after import, the file was saved in an encoding the import guessed wrong. Save it as CSV UTF-8 and import again.
Need help?
Contact Tokenz support with the file you tried to import and the error shown in the dashboard.