2. 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 itsnameanddescription - A tax classification (
productCategoryandproductSubcategory) - 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.
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 nameproductCategory: Top-level tax category:Digital,Misc,Physical, orServicesproductSubcategory: Subcategory label within that category, such asGeneral ClothingorB2B SaaS. An unrecognized category and subcategory pair returns400taxExempt: Whether tax calculation treats the product as exempt
Optional Fields
description: Product descriptionstatus: Approval status (APPROVED,PARTIALLY_APPROVED, orPENDING)source: Where the record originated, for exampleAPI. Defaults toOTHERsourceTaxExempt: The raw tax-exempt signal from your source system, stored for auditing.taxExemptis 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.
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:
searchover product id,externalId, name, and description. The id andexternalIdmust match exactly; name and description match a case-insensitive substringproductCategoryandproductSubcategoryto check classification coveragestatus(comma-separated) to surface anything stillPENDINGsource(comma-separated) to scope results, andorderBywithorderto 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.
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.
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 nameemail: Contact email address- Address fields:
street1,street2,city,county,state,postalCode, andcountry(ISO 3166-1 alpha-2)
Other Optional Fields
companyName: Registered or legal business name, when it differs fromnamephone: Contact phone numbersource: Where the record originated. Defaults toOTHERconnectionId: The connection to attribute the customer toexternalFriendlyId: A human-facing identifier from your source systemtaxRegistrations: The customer's tax registrations, each with acountryCode,taxType, andtaxId
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.
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, orreverse_chargestartDate: 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:
searchover customer id, name, email,externalId, andexternalFriendlyId. The id,externalId, andexternalFriendlyIdmust match exactly; name and email match a case-insensitive substringcountryandstate(comma-separated) to scope results by geographysourceandconnectionId(comma-separated) to filter, andsortwithorderto 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.
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
taxExemptflag, 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
idto 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.
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, andtaxExempt - Duplicate externalId on update: Changing a product's
externalIdto one another product uses returns409 - Invalid address: Validate addresses before saving them
- Missing or invalid API key: Every request needs a valid
Api-Keyheader, or it returns401
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-estimationsrequests. See the Sales Tax Calculations guide. -
Sync transactions: Reference products and customers in
POST /transactionsrequests. 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: