KintsugiKintsugi

Integrating Kintsugi's API

A Kintsugi integration is smaller than it first looks. Four surfaces in your product each make one call, two of them before a sale and two of them at it. This guide is the map: what talks to what, in what order, and why. For request shapes and endpoint details, each section links down to the guide that covers it.

This page covers the Tenanted API, release 2026-07-21. Send Api-Key: <key> on every request, and pin Api-Version: 2026-07-21 so your integration never depends on a default. Paths carry no /v1 prefix, and every field is camelCase.

Understanding Your Integration Context

Three questions shape everything that follows.

Core Integration Architecture

Every integration comes down to four touchpoints. Nothing else in your stack needs to know Kintsugi exists.

In your productThe call it makes
Customer managementSignup, account settings, address edits
Create and update customersReference dataBefore the sale
Product catalogNew SKUs, category and description changes
Create and update productsReference dataBefore the sale
CheckoutCart totals, before payment
Estimate taxAt the saleNothing stored
Order processingOnce payment clears
Create a transactionAt the saleThe record of what you owe
What Kintsugi does with it
Tax calculationNexus trackingFiling preparation
Build the two reference-data rows first, so customers and products exist before the first sale names them.

Customer and Product Records

Customers and products are the same problem twice: a record in your system that Kintsugi needs a copy of, keyed on your own identifier. Learn the pattern once, then read the two differences.

Something changed on your side
A customer signs up or edits an address; a SKU is created or its classification changes. Fire on the write rather than on a nightly job, because tax depends on current data.
Create it, keyed on your externalId
POST /customers and POST /products are idempotent on externalId and source, so a retry is safe.
NEW →CreatedKintsugi stores the record and returns it with its id.
SEEN BEFORE →Existing record returned200 instead of a duplicate. A match you previously deleted is restored rather than duplicated.
Update it with PATCH
Create never changes an existing record. To change one, send only the fields that moved to PATCH /customers/{customerId} or PATCH /products/{productId}.
Store the Kintsugi id
Keep the returned id on your own record. It is what you address the PATCH to, and what you pass as customerId when you create an exemption.
Delta · customersExemptionsA separate object on its own schedule, since a buyer often sends a certificate long after signup.
When a certificate arrives
Create the exemptionAttach the certificate PDF to it
Watch forThe exemption takes the customer's customerId, the id you stored in step 4.
Delta · productsClassificationYou pick the category and subcategory from Kintsugi's catalog. Both are required on create.
Re-send with PATCH when
It moves to a different category or subcategory
Watch forA pair the catalog does not recognize returns 400. On a recategorize, taxExempt is derived from the new category.

For exemptions, the two calls are Create an exemption and Upload an exemption certificate. For products, productCategory and productSubcategory come from Kintsugi's catalog.

Reference by your own IDs. An estimate names products with externalProductId on each line and the buyer with externalId on the customer object. A transaction names products with externalProductId on each item and the buyer with customer.externalId. A stable identifier on your side is what holds the whole integration together. Full request shapes are in Product and Customer Records.

Exemptions without a customer record. For a one-off that belongs to no customer, set exempt: true on the estimate line instead.

For the initial load, run the sync as a batch job with retries. Because create is idempotent on externalId and source, a retried request never leaves you with a duplicate. Every error comes back in one envelope with a code, a message, a requestId and a list of field errors, so log the requestId with each failure.

Tax Estimation Integration

Tax estimation runs during checkout, where the customer needs an accurate total before they pay. It is usually the most latency-sensitive call in the integration, and the only one that stores nothing.

Cart and shipping address
Tax needs both. The line items decide taxability, the address decides the rate, and until you have an address there is no estimate to show.
Resolve the address first
Rates go down to the local level, so an unresolved address gives a rate you cannot defend. Validate, then estimate against the corrected version.
INVALID →Surface the correction to the buyer at checkout rather than silently substituting it. They are the only one who knows where the parcel goes.
Estimate the tax
Send the line items and the resolved address. You get amounts broken out by jurisdiction.
Display it and take payment
Charge the buyer the estimated tax. Re-estimate if anything in the cart or the address moves between display and payment.
Payment clears, so record it
Now create the transaction. That is the next section, and it is the only step that changes what you owe.
If payment fails, stop. No transaction, no liability: an abandoned checkout leaves nothing behind in Kintsugi.

Estimates are safe to repeat. POST /tax-estimations stores nothing and the estimate is not retrievable afterwards, so you can call it every time the cart or the address changes. Debounce address input, and reuse a result while both are unchanged. The estimate validates its addresses as it runs: one that cannot be validated returns 400, and an address-validation outage returns 503, which you can retry. Sales Tax Calculations covers the request, the response breakdown, and the zero-tax cases.

Transaction Reporting Integration

Once payment clears, the sale becomes a transaction record. This is the call that changes what you owe.

What goes in
The customercustomer.externalId, plus name, email and companyName where you hold them. Omit customer and the sale goes to the organization's shared unattributed-sales customer.
Line itemsEach names the product by externalProductId, with its date, quantity and amount.
AddressesJurisdiction is resolved from these, so send a complete SHIP_TO.
Tax chargedWhat the buyer actually paid, as taxAmountImported on each item.
Create the transactionPOST /transactions once per order, keyed on your order ID as externalId. It answers 202 Accepted. Re-sending the same externalId updates the existing transaction rather than creating a second.
What comes back
Recorded nowThe transaction is stored immediately, with processingStatus QUEUED.Tax calculated afterwardsThe first response shows the calculated tax at "0.00".
Sales you never send are sales Kintsugi cannot see. Exempt, zero-tax and marketplace orders all belong here too.
POST /transactions HTTP/1.1
Host: api.trykintsugi.com
Content-Type: application/json
Api-Key: <your-api-key>
Api-Version: 2026-07-21

{
  "externalId": "order-2001",
  "date": "2026-01-15T14:30:00Z",
  "type": "SALE",
  "currency": "USD",
  "totalAmount": "100.00",
  "source": "API",
  "description": "Order 2001",
  "addresses": [
    {
      "type": "SHIP_TO",
      "street1": "123 Main St",
      "city": "San Francisco",
      "state": "CA",
      "postalCode": "94107",
      "country": "US"
    }
  ],
  "items": [
    {
      "externalProductId": "SKU-ABC",
      "date": "2026-01-15T14:30:00Z",
      "product": "Widget",
      "quantity": "2",
      "amount": "100.00"
    }
  ]
}

The first response looks like this:

{
  "id": "tran_12345",
  "externalId": "order-2001",
  "status": "COMMITTED",
  "processingStatus": "QUEUED",
  "totalAmount": "100.00",
  "totalTaxAmountCalculated": "0.00",
  "totalTaxLiabilityAmount": "0.00",
  "addressStatus": "UNVERIFIED"
}

The returned id is not fetchable straight away. GET /transactions/{transactionId} answers 404 until processing completes, so poll it rather than treating the first 404 as a failure.

Flag a marketplace order with marketplace: true; its tax liability is excluded. Whether its gross sales count toward a state's nexus threshold depends on the state, and each nexus period's includeMarketplaceTransactions says which.

Reconciling later. The transaction is keyed on your order ID, which is also how you find it again: the search filter on List transactions matches externalId. Syncing Transaction Records covers status and backfill, and Handling Refund Transactions covers credit notes.

Common Integration Patterns

Where you place these four calls depends on what you are building.

  • E-commerce: estimate tax during checkout, create the transaction as soon as payment clears. The most common shape.
  • SaaS and subscriptions: estimate per billing cycle rather than per page view, and create transactions in a batch after the billing run.
  • Marketplaces: calculate per seller, report centrally, and account for marketplace facilitator rules, which decide whether the tax is yours to collect at all. See US Sales Tax for Developers.

Whichever shape fits, the ordering constraint is the same: reference data first, then transactions, then live estimation on top.

Implementation Checklist

  • API keys created and authentication working end to end
  • Api-Version: 2026-07-21 sent on every request
  • An Organization-Id, Connection-Id or Entity-Id selector sent wherever your key reaches more than one organization
  • Customers synced, with exemption certificates attached where they exist
  • Product catalog synced, every item carrying a productCategory and productSubcategory
  • Kintsugi IDs stored against your own records
  • Address validation wired in ahead of estimation
  • Estimation called at checkout, with retry on 503 and graceful degradation
  • Transactions created on payment, keyed on your order ID, with the 202 handled as accepted rather than finished
  • Tested against exempt customers, zero-tax states, and multi-jurisdiction addresses

Transaction sync first, then estimation. Start with customers, products, and transaction reporting. Once that is stable, add the estimation workflow for real-time checkout totals. See Planning an Integration for the full model.

Next Steps

API Reference

Endpoint documentation, request formats, and response structures in the API Reference.

SDKs

Our SDKs for Python, TypeScript, Java, PHP, and Ruby cover the v1 API. For the Tenanted API, call the HTTP endpoints directly.