# 2. Product & Customer Records (2026-07-21)

> Create and manage product and customer records that power tax calculations and compliance tracking

Source: https://docs.trykintsugi.com/docs/2026-07-21/api-guides/product-customer-records

Product and customer records are the foundation of every Kintsugi integration. Products carry the tax classification that decides whether an item is taxable in a given jurisdiction. Customer records anchor exemptions to the buyers who hold them. This guide covers when to create each record, how to reference them, and how to verify they landed.

## Understanding Product Records

A product record maps one of your catalog items to a Kintsugi tax classification. Each record holds:

Your identifier for the item ( externalId) plus its name and description

A tax classification ( productCategory and productSubcategory)

A tax-exempt flag ( taxExempt)

An approval status ( status)

Transaction lines and tax estimates reference products by externalProductId. Kintsugi reads the matching product's classification to decide whether the item is taxable where your customer is.

Create products first: Transaction lines reference products by externalProductId, so create your catalog before calling POST /transactions. A tax estimate line can instead name a productCategory and productSubcategory pair, which is priced without creating a product, but a pre-built catalog keeps classification consistent across every call.

## Creating Product Records

Create products with POST /products.

POST /products

-H "Api-Key: ***"

-H "Api-Version: 2026-07-21"

{

"externalId": "sku-1001",

"name": "Blue T-Shirt",

"productCategory": "Physical",

"productSubcategory": "General Clothing",

"taxExempt": false,

"source": "API"

}

A new product answers 201. Creating is idempotent on externalId and source: sending the same pair again returns the existing product unchanged with 200 instead of creating a duplicate. Use PATCH /products/{product_id} to change it.

Required Fields

externalId: Your stable identifier for the product (for example, "sku-1001")

name: Product name

productCategory: Top-level tax category: Digital, Misc, Physical, or Services

productSubcategory: Subcategory label within that category, such as General Clothing or B2B SaaS. An unrecognized category and subcategory pair returns 400

taxExempt: Whether tax calculation treats the product as exempt

Optional Fields

description: Product description

status: Approval status ( APPROVED, PARTIALLY_APPROVED, or PENDING)

source: Where the record originated, for example API. Defaults to OTHER

sourceTaxExempt: The raw tax-exempt signal from your source system, stored for auditing. taxExempt is the flag tax calculation applies

Pull the category list from the API: Supported categories and subcategories are returned by List the product category catalog. Its category and each subcategory label are the exact values productCategory and productSubcategory accept. Read from that endpoint rather than hardcoding values, so your mapping stays valid as the taxonomy grows.

What if I have thousands of products?

## Creating Product Records

Create them in batches. POST /products takes one product per request, so send them in chunks and pause between chunks. Because creating is idempotent on externalId and source, re-sending a product that already landed returns it with 200 rather than a duplicate. Products never expire, so you can build the catalog well ahead of your first transaction.

Do I need to update products if tax rules change?

No. Kintsugi tracks jurisdiction rule changes for you, and product records stay as they are. Update a product only when your own classification changes, for example when an item moves from one category or subcategory to another.

Can I delete products?

Yes. DELETE /products/{product_id} archives a product: it disappears from GET /products and every read returns 404. The identity stays taken, so creating a product again with the same externalId and source, or a transaction that references the same externalId, restores it. A restored product returns to PENDING and is not used in tax calculation until it is approved again.

## Verifying Product Records

Confirm your catalog with GET /products. The endpoint is cursor-paginated ( limit up to 100, default 50, and the cursor from a prior response's nextCursor or previousCursor) and supports:

search over product id, externalId, name, and description. The id and externalId must match exactly; name and description match a case-insensitive substring

productCategory and productSubcategory to check classification coverage

status (comma-separated) to surface anything still PENDING

source (comma-separated) to scope results, and orderBy with order to sort them

To fetch one product directly, use GET /products/{product_id} with the Kintsugi product ID returned at creation.

Look up by your own ID: search matches externalId exactly, so GET /products?search=sku-1001 finds the product you created as sku-1001. Saving the id from your create response still gives you the most direct lookup.

Product Creation Workflow

Products carry the tax category that drives every rate lookup. Create them before the first transaction.

1

Prepare and validate the payload

Five fields are required before you send anything.

externalId name productCategory productSubcategory taxExempt

Pull the category and subcategory values from GET /products/categories rather than hardcoding them.

2

Create the product

POST /products Returns the product id

Non-2xx? See error handling below.

3

Verify it exists

GET /products Optional, recommended

4

Product is ready for tax calculations

Reference it by its externalId, as externalProductId, in estimates and transactions.

## Understanding Customer Records

A customer record identifies a buyer and gives exemptions something to attach to. Create customer records when you sell to:

Nonprofit organizations

Government agencies

Resellers holding valid exemption certificates

Any other exempt entity

Exemptions themselves are separate records created against a customer through Create an exemption. When a tax estimate's customer.externalId matches a customer Kintsugi holds, that customer's exemptions and tax registrations are applied to the estimate.

When you don't need customer records: Selling only to ordinary consumers? Skip customer creation and pass the buyer's details inline on the transaction's customer object.

## Creating Customer Records

Create customers with POST /customers. Every field is optional, so send everything you have; in practice, exemption matching and address-based tax work depend on the fields below.

POST /customers

-H "Api-Key: ***"

-H "Api-Version: 2026-07-21"

{

"externalId": "cust-1001",

"name": "Acme Corp",

"email": "jane.doe@example.com",

"source": "API",

"street1": "123 Main St",

"street2": "Suite 400",

"city": "San Francisco",

"state": "CA",

"postalCode": "94105",

"country": "US"

}

A new customer answers 201 and is always ACTIVE. Creating is idempotent on externalId and source, and on connectionId when you send one: sending the same values again returns the existing customer unchanged with 200.

Fields to Send

externalId: Your stable identifier for the customer (for example, "cust-1001")

name: Customer name

email: Contact email address

Address fields: street1, street2, city, county, state, postalCode, and country (ISO 3166-1 alpha-2)

Other Optional Fields

companyName: Registered or legal business name, when it differs from name

phone: Contact phone number

source: Where the record originated. Defaults to OTHER

connectionId: The connection to attribute the customer to

externalFriendlyId: A human-facing identifier from your source system

taxRegistrations: The customer's tax registrations, each with a countryCode, taxType, and taxId

Customer Addresses

A customer record carries one address, written as flat fields on the record itself rather than as a list. That address identifies the customer; it does not decide the tax jurisdiction on its own.

## Creating Customer Records

Jurisdiction comes from the addresses on the transaction or estimate, where each entry has a type of SHIP_TO, BILL_TO, SHIP_FROM, or BILL_FROM. Tax is sourced to the SHIP_TO address when one is supplied, and to BILL_TO otherwise.

Adding Exemptions

With the customer created, attach the exemption using POST /exemptions. That request needs:

exemptionType: What the exemption applies to: customer, wholesale, transaction, or reverse_charge

startDate: First day the exemption is in force ( YYYY-MM-DD)

customerId: The Kintsugi customer ID from your create response

Add endDate, countryCode, jurisdiction, reseller, fein, salesTaxId, and transactionId where they apply. status defaults to ACTIVE, the only status tax calculation applies. Upload the certificate itself, a PDF of at most 10 MB, with POST /exemptions/{exemption_id}/certificates.

## Verifying Customer Records

Confirm your customers with GET /customers. The endpoint is cursor-paginated ( limit up to 100, default 50, plus cursor) and supports:

search over customer id, name, email, externalId, and externalFriendlyId. The id, externalId, and externalFriendlyId must match exactly; name and email match a case-insensitive substring

country and state (comma-separated) to scope results by geography

source and connectionId (comma-separated) to filter, and sort with order to sort

For an exact lookup by your own identifier, use GET /customers?search=<externalId>. With the Kintsugi customer ID, use GET /customers/{customer_id}.

Customer Creation Workflow

A customer record is only required when exemptions are involved. Everyone else can be passed inline.

Q Does this customer hold an exemption?

NO Skip the customer record

Pass customer data inline on the transaction

The address on the transaction is enough to source the sale.

YES Create the record so exemptions can attach to it

1

Prepare and validate the payload

Every field is optional, so send everything you have. Exemption matching and address-based tax depend on these.

externalId name email

Plus the address: street1, city, state, postalCode and country. Run it through address validation first, since a bad address means a wrong rate.

2

Create the customer

POST /customers Returns the customer id

Non-2xx? See error handling below.

3

Attach the exemption

Send the customer id as customerId.

POST /exemptions Needs the customer id

Then upload the certificate itself to POST /exemptions/{exemption_id}/certificates.

4

Verify it exists

GET /customers Optional, recommended

5

Customer is ready

Reference the customer by externalId on tax estimates and transactions.

## Using Products and Customers in Transactions

With records in place, reference them from your tax estimates and transactions.

Referencing Products

Each transaction line points at a product through externalProductId:

{
"items": [
{
"externalId": "item-1",
"externalProductId": "SKU-ABC",
"date": "2026-01-15T14:30:00Z",
"quantity": "2",
"amount": "100.00"
}
]
}

On a tax estimate the lines live in transactionItems and take the same externalProductId. Each line on a transaction response reports, as productId, the Kintsugi product it resolved to when one was matched.

Referencing Customers

Transactions and estimates carry the buyer on a customer object. Send your externalId there:

{
"customer": {
"externalId": "cust-1001",
"name": "Acme Corp",
"email": "jane.doe@example.com"
}
}

On a tax estimate, when the externalId matches a customer on file, Kintsugi applies that customer's exemptions and tax registrations. On a transaction, omit customer entirely for a sale with no customer identity, such as a marketplace or point-of-sale sale: the transaction is attributed to your organization's shared unattributed-sales customer.

## Updating Product and Customer Records

Update with PATCH /products/{product_id} and PATCH /customers/{customer_id}. Both are partial updates: only the fields you send change. Typical cases:

Products: Reclassifying category or subcategory, changing the taxExempt flag, revising name or description

Customers: Correcting an address, updating contact details, adding tax registrations

Recategorizing sets the exemption for you: On a product update, taxExempt is honored only when the category is unchanged. When you recategorize, the exemption is derived from the new category and the taxExempt you send is ignored. source is not editable, and reusing another product's externalId returns 409.

On a customer, sending any address field resets addressStatus to UNVERIFIED, and the new address is validated the next time the customer is processed. taxRegistrations upserts each entry on its countryCode and taxType pair and cannot remove one. To retire a customer, DELETE /customers/{customer_id} archives it; creating a customer again with the same externalId and source restores it with its transactions and exemptions attached.

When to update versus create new: If an item's tax treatment fundamentally changes, for example moving from physical goods to a digital download, create a new product under a new externalId instead of editing the old one. That keeps a clean audit trail of when the classification changed.

## Best Practices

Product Management

Build the catalog first: Have products in place before you wire up tax calculation or transaction sync

Read categories from the API: Source values from List the product category catalog instead of hardcoding them

Use consistent external IDs: Pick one convention, such as always the SKU, and hold it across every system

Batch creation: Send products in chunks rather than all at once

Verify before you rely on them: Confirm products exist before referencing them in transactions

Customer Management

Create records where exemptions live: Ordinary consumers can travel inline on the transaction

Validate addresses: Run addresses through address validation before you save them

Store Kintsugi customer IDs: You need the id to attach exemptions and for direct lookups

Handle exemptions as a second step: Create the customer, then attach exemptions through Create an exemption

## Error Handling

Same policy for products and customers. Every error comes back in one envelope, { "code", "message", "requestId", "errors": [...] }, where errors holds one entry per request field that failed validation, each with a field, code, and message. Read it, then decide whether the failure is worth retrying.

RETRYABLE 5xx · 429

Back off, then re-send

Send the identical payload. Creating a product or customer is idempotent on externalId and source, so a retry of a request that already landed returns the existing record with 200 rather than a duplicate.

NOT RETRYABLE Other 4xx

Fix the data, then re-send

The errors array names the offending field. Correct it, then re-send. Retrying unchanged will fail the same way.

Cap retries. Three attempts is plenty. After that, log the payload, the response, and its requestId, and surface it for a human rather than looping.

Common Failures

What actually goes wrong when creating products and customers:

Invalid category or subcategory: An unrecognized pair returns 400. Match values to List the product category catalog

Missing required fields: Products need externalId, name, productCategory, productSubcategory, and taxExempt

Duplicate externalId on update: Changing a product's externalId to one another product uses returns 409

Invalid address: Validate addresses before saving them

Missing or invalid API key: Every request needs a valid Api-Key header, or it returns 401

For the full status-code reference and retry strategies, see the Error Handling guide.

## Integration Checklist

Before you wire up tax calculation or transaction sync:

[ ] Created product records for every item in your catalog

[ ] Verified products exist and carry the classification you expect

[ ] Created customer records for exempt entities (if applicable)

[ ] Attached exemptions to those customers and uploaded certificates (if applicable)

[ ] Tested product lookup in a sample tax estimate request

[ ] Tested customer lookup in a sample tax estimate request

## Next Steps

With products and customers in place:

Start calculating tax: Reference products in POST /tax-estimations requests. See the Sales Tax Calculations guide.

Sync transactions: Reference products and customers in POST /transactions requests. See the Syncing Transaction Records guide.

Handle updates: Set up workflows to push catalog and customer changes through to Kintsugi.

For endpoint-level detail, see:

Create a product

List products

List the product category catalog

Create a customer

List customers

Create an exemption

---

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