# File Upload (2026-07-21)

> Import sales transactions from a CSV file, and the columns the importer reads

Source: https://docs.trykintsugi.com/docs/2026-07-21/guides/file-upload

File upload imports sales transactions from a CSV, which is the fastest way to bring in history when you are onboarding or backfilling a period. Uploaded transactions behave exactly like ones created through the API: they count toward nexus, feed compliance reporting, and land on the right return at filing time.

This page is the column reference. Download the template from the app, or with Download a CSV import template, then use the tables below to fill it in.

CSV column names are snake_case, such as transaction_external_id. They describe the file, not the API, so they do not change to camelCase on the Tenanted API. The camelCase names appear only in API responses, such as the resultData rows that Validate a CSV file returns.

## Before You Start

Five columns have to be in the file A file missing any of these is rejected before any row is read. The first four need a value on every row. amount is required as a column so that a file without it cannot book every line at 0.00. Every other column can be left out entirely, and the value falls back to the default listed on its row. Leaving one out is not the same as including it and leaving cells blank, which the next two cards cover.

transaction_external_id date customer_id product_external_id amount

Omitting a column is safe. Blanking a cell is not A default only applies when the column is absent from the file. Once you include a column, the upload validator expects a value in it, and it is stricter than the defaults suggest.

Column absent The documented default applies to every row. This is the safe way to skip a column you have no data for.

Column present, cell empty Rejected for operation, and a conflict on any transaction-level column where another row of the same transaction does carry a value. Delete the column, or fill it in on every row.

One transaction, many rows, identical values A multi-line sale is several rows sharing one transaction_external_id. Only the line item columns are allowed to differ between them. Every transaction-level column you include has to carry the same value on every row, including the addresses, the buyer, the date, status, currency, transaction_type and operation. Filling a column in on the first row and leaving it blank on the rest is the most common way to trip this, because an empty cell counts as a different value. The error names the column and the row it first saw: Inconsistent 'transaction_type': '' vs 'SALE'.

## Before You Start

Save the file as text, not as a spreadsheet Format every cell as General before exporting. A cell typed as Date or Number is re-serialized on save, which is the most common reason a file that looks correct fails validation. Postal codes are the other one: a leading zero has to survive the export.

Reading the badges

Required A value in every row.

Conditional Required in a stated case. The rule is on the row.

Optional Leave the column out and the default applies.

The downloadable template carries two columns the importer does not read. total_amount is ignored because transaction totals come from the line items, so fill in amount and tax_amount per row instead. source is ignored too: each transaction takes its source from the import itself.

On the Tenanted API, an import's source is the source you send to the Imports endpoints, and it reads back as transactionSource.

## Transaction Columns

These describe the sale. Every row of a multi-line sale repeats them, and rows sharing a transaction_external_id are read as line items of one transaction.

Identity, type and date 9 columns

transaction_external_id Required

Your own id for the transaction. Kintsugi keys the record on it.

e.g. in_ctvrAUrbiRdSywvQ

Alphanumeric, underscores, hyphens, spaces Minimum length 1

Unique per transaction. Rows sharing an id are read as line items of the same sale.

related_external_id Conditional

The original transaction's id, when this row credits an earlier sale.

e.g. PCR_ctvrAUrbiRdSywvQ

Required when transaction_type is FULL_CREDIT_NOTE or PARTIAL_CREDIT_NOTE. A row cannot reference itself.

transaction_type Optional

What kind of transaction the row represents.

e.g. SALE

Defaults to SALE

Accepted values

SALE FULL_CREDIT_NOTE PARTIAL_CREDIT_NOTE TAX_REFUND

Both credit-note types require related_external_id. Transaction-level, so every row of a multi-line sale needs the same value.

status Optional

Where the transaction sits in its lifecycle.

e.g. COMMITTED

Defaults to COMMITTED

Accepted values

COMMITTED PENDING CANCELLED FULLY_REFUNDED PARTIALLY_REFUNDED

INVALID and ARCHIVED are set by Kintsugi and rejected on import. Transaction-level, so repeat it on every row of a multi-line sale.

operation Conditional

What the importer should do with the row.

e.g. IMPORT

Defaults to IMPORT when the column is absent

Accepted values

IMPORT UPDATE ARCHIVE

Required as soon as the column is in the file. A blank cell is rejected outright rather than falling back to IMPORT, so leave the column out or fill it in on every row.

date Required

When the transaction took place.

e.g. 2024-03-23T00:00:00

The template uses YYYY-MM-DDT00:00:00

## Transaction Columns

Format the cell as General. A cell typed as Date is rewritten on save and the row fails.

currency Optional

Currency for every amount on the row.

e.g. USD

Any ISO 4217 code Defaults to USD

Transaction-level, so repeat it on every row of a multi-line sale.

description Optional

Free text describing the transaction.

e.g. Heirloom Ring Size 8.5 14K

Max 1000 characters

marketplace Optional

Whether a marketplace facilitator collected the tax on this sale.

e.g. FALSE

TRUE, FALSE, true, false, 1, 0, t, f Defaults to FALSE

The buyer 5 columns

customer_id Required

Your own id for the buyer. Exemptions attach to it.

e.g. cust_cCMVtrsfoUV

Alphanumeric, underscores, hyphens, spaces Max 100 characters

Transaction-level, so every row of a multi-line sale needs the same buyer.

customer_name Optional

The buyer's full name.

e.g. Faith Ortega

Max 200 characters

customer_email Optional

The buyer's email address.

e.g. michele45@example.com

Any valid email address Max 200 characters

customer_company_name Optional

The buyer's registered or legal business name.

e.g. Example Company Inc.

Max 200 characters

tax_id Optional

The buyer's registration number.

Max 100 characters

Transaction-level, so every row of a multi-line sale needs the same value.

## Address Columns

Addresses decide the rate, so this is the part of the file worth checking twice. A postal code resolves to a local jurisdiction; a state on its own does not.

The one rule Every row needs a postal code and a country from one side or the other. Which side is up to you, but you cannot leave both empty.

Either ship_to_postal_code + ship_to_country

Or bill_to_postal_code + bill_to_country

Ship to 7 columns

ship_to_country Conditional

The recipient's country.

e.g. US

Max 100 characters

Required unless bill_to_postal_code and bill_to_country are both present. A country of PR is read as state PR in the US.

ship_to_postal_code Conditional

The recipient's postal code. This is what resolves the local rate.

e.g. 21830

US: 5-digit ZIP or ZIP+4 Max 50 characters

Checked when the country is US or blank. A 4-digit code is accepted and gets its leading zero back, but exporting the column as text is safer.

ship_to_state Optional

The recipient's state or province.

e.g. CO

US: 2-letter code or full state name CA: 2-letter province code

ship_to_city Optional

The recipient's city.

e.g. Aurora

ship_to_street_line_1 Optional

First line of the street address.

e.g. 811 Eric Flat Suite 183

Max 1000 characters

ship_to_street_line_2 Optional

Second line of the street address.

e.g. Apt 1606

Max 1000 characters

ship_to_phone Optional

The recipient's phone number.

e.g. +1 665-869-8307

Max 50 characters

Bill to 7 columns

bill_to_country Conditional

The billed party's country.

e.g. US

Max 100 characters

Required unless ship_to_postal_code and ship_to_country are both present. A country of PR is read as state PR in the US.

bill_to_postal_code Conditional

The billed party's postal code. This is what resolves the local rate.

e.g. 21830

## Address Columns

US: 5-digit ZIP or ZIP+4 Max 50 characters

Checked when the country is US or blank. A 4-digit code is accepted and gets its leading zero back, but exporting the column as text is safer.

bill_to_state Optional

The billed party's state or province.

e.g. CO

US: 2-letter code or full state name CA: 2-letter province code

bill_to_city Optional

The billed party's city.

e.g. Aurora

bill_to_street_line_1 Optional

First line of the street address.

e.g. 811 Eric Flat Suite 183

Max 1000 characters

bill_to_street_line_2 Optional

Second line of the street address.

e.g. Apt 1606

Max 1000 characters

bill_to_phone Optional

The billed party's phone number.

e.g. +1 665-869-8307

Max 50 characters

## Line Item Columns

One row per line item. The product columns drive classification, and the money columns are what your filings reconcile against.

The product and the money 10 columns

product_external_id Required

Your own id for the product, usually the SKU.

e.g. F80-BRW

Alphanumeric, underscores, hyphens, spaces Max 200 characters

product_name Optional

The product's name.

e.g. Product Name 9

product_description Optional

The product's description.

e.g. Product Description 9

line_item_id Optional

Your own id for this line of the transaction.

e.g. il_lQtcAcqhLGPQZhSa

Max 200 characters

amount Conditional

What this line came to, after discounts and excluding tax.

e.g. 550.51

Commas allowed, no currency symbols A blank cell is 0.00

The column has to be in the file. Transaction totals are summed from these, so this is the figure that has to reconcile.

tax_amount Optional

Tax collected on this line.

e.g. 1.69

Defaults to 0.00

quantity Optional

How many units this line covers.

e.g. 14

A value below 1 is rejected Defaults to 1

discount_amount Optional

Discount applied to this line.

e.g. 0.69

Defaults to 0.00

When present it has to be greater than 0 and no more than amount. Since amount is already net of discounts, this column records the discount rather than applying it.

exempt Optional

Whether this line is exempt from tax.

e.g. FALSE

TRUE, FALSE, true, false, 1, 0, t, f Defaults to FALSE

customer_exempt Optional

Whether the buyer holds an exemption covering this sale.

e.g. FALSE

TRUE, FALSE, true, false, 1, 0, t, f

Cannot be TRUE when exempt is also TRUE: the row has to say whether the product or the buyer is the reason.

## Line Item Columns

product_name and product_description are optional columns that do real work: Kintsugi classifies the product from them, and classification is what decides taxability per state. A file with bare SKUs imports cleanly and prices badly.

## Importing a Refund

A refund is a credit note row that points at the original sale.

1

Mark the row as a credit note

Set transaction_type to FULL_CREDIT_NOTE or PARTIAL_CREDIT_NOTE. That is what makes the next column required.

2

Point it at the original

Put the original sale's id in related_external_id, and give the credit note its own transaction_external_id. A row cannot reference itself.

PCR_ Credit note ids are conventionally the original id behind a PCR_ prefix, which keeps the pair legible in an export.

Set the original's status

PARTIALLY_REFUNDED and FULLY_REFUNDED are both accepted values of status, for the original sale's rows.

Recording refunds through the API instead? See Handling Refund Transactions.

## After the Upload

Kintsugi validates the file before importing any of it, and errors come back per row and per column, so a rejected file tells you which cell to fix rather than just failing.

The same checks are available through the Tenanted API's Imports endpoints:

Validate a CSV file checks a file's contents before you upload it. It always answers 200; read isValid and errors to see whether the file passed.

Get an import by id reports an import's status and its row counts, including validRowCount and invalidRowCount.

Get a download link for an import's error artifact returns the validation errors as a file, or the row-processing errors with phase=import.

Import the validated rows imports the rows that passed. submitMode ALL requires every row to have passed validation; VALID_ONLY imports the rows that passed and skips the rest.

## Related Resources

Getting Started

Set up your account and import historical data.

Syncing Transaction Records

Prefer automation? Sync transactions programmatically instead.

Migrating from Avalara or TaxJar

Moving providers? CSV upload is usually the fastest way to backfill history.

Product Categories

How Kintsugi classifies products, which is what the product columns feed.

---

Index of every page: https://docs.trykintsugi.com/llms.txt
