KintsugiKintsugi

3. Syncing Transaction Records

Transaction sync (also called Level 1 or L1) creates the permanent record of your completed sales in Kintsugi. Those records drive nexus tracking, compliance reporting, and filing preparation. Every Kintsugi integration rests on them, whether you run L1 only, tax calculation only, or L2. This guide covers when to sync, how to shape the payload, and how to run a clean bulk import.

Understanding Transaction Sync

Each transaction represents one completed sale, carrying:

  • Transaction details: date, type, amount, currency
  • Line items that reference your products
  • Customer details and addresses
  • Tax amounts you already collected, when tax was charged at checkout

Kintsugi uses those records to:

  • Determine economic nexus by tracking sales volume and transaction counts by jurisdiction
  • Prepare filings by aggregating transactions per jurisdiction
  • Maintain an audit trail for compliance
  • Track refunds and credit notes against original sales

Transaction sync (L1) is the foundation: POST /transactions records sales; tax on them is calculated asynchronously afterwards. With the tax engine (L2) enabled, Kintsugi prices tax at checkout through POST /tax-estimations and you still sync the completed transaction afterward. Tax calculation without transaction sync is only viable when nexus and compliance are managed elsewhere. See Planning an Integration.

When to Sync Transactions

Sync once the sale is complete and payment is confirmed. The cadence is yours to choose.

Real-Time Sync

Sync immediately after order completion when you have:

  • High-volume e-commerce
  • A requirement for immediate compliance visibility
  • Real-time reporting needs

Real-time sync keeps your nexus status and compliance data current to the minute.

Batch Sync

Sync in batches when you have:

  • An accounting system integration
  • Periodic order exports
  • A daily or weekly operational rhythm

Batching suits systems that already process orders in groups.

Batch cadence: Sync at least daily. Economic nexus thresholds are evaluated over a rolling 12-month period or a calendar year depending on the state, so a daily rhythm keeps your tracking gap-free.

Transaction Statuses

Status decides whether a transaction affects your compliance position. A transaction's status reads back as one of PENDING, COMMITTED, CANCELLED, FULLY_REFUNDED, PARTIALLY_REFUNDED, or INVALID.

COMMITTED
Counts toward filed liability. A sale you record through POST /transactions is stored with this status.
PENDING
May still change, and does not count toward filed liability.

The create and update requests have no status field, so the Tenanted API does not let you record a sale as pending or move it between statuses yourself.

Refunds are tracked separately: A sale that has been credited keeps its own status, and its refund position is held apart from it. To find refunded sales, filter GET /transactions with refundStatus=FULLY_REFUNDED,PARTIALLY_REFUNDED. See Handling Refund Transactions for how credit notes drive it.

Choosing a Sync Pattern

Because a sale recorded through the API is stored as COMMITTED and counts at once, sync it after payment clears. The payment gate comes first: nothing is sent until you know the order is real.

Order placed, payment processes
Entirely in your system. No Kintsugi call yet.
DECLINED →Stop. Don't sync. There is no transaction in Kintsugi, so there is nothing to reverse.
Assemble and check the payload
externalIddatecurrencyaddressesitemscustomer
Every product should already exist as a product record, and every address should validate.
Send the transaction
POST/transactionstype: SALE
Answers 202 Accepted with the recorded transaction.
Synced and counting toward nexus
Tax is calculated asynchronously. Read the transaction back and watch processingStatus: PROCESSED means tax calculation has completed.
GET /transactions/{transaction_id} answers 404 until processing completes, so poll it rather than treating the first 404 as a failure.

No create-pending-then-commit pattern: The v1 API lets you record a sale as PENDING and commit or cancel it later. The Tenanted API has no status on create or update, so that pattern is not available here. Hold the sale in your own system until the payment outcome is known.

Creating Transactions

Create transactions with POST /transactions, one transaction per request.

POST /transactions
-H "Api-Key: ***"
-H "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"
}
]
}

Required Fields

  • externalId: Your stable identifier for the transaction (for example, "order-2001")
  • date: When the transaction occurred, as an RFC 3339 timestamp. It drives which filing period the sale lands in, so send the real transaction time, not the time of the call
  • currency: ISO 4217 currency code of every amount, for example USD
  • type: Transaction type. SALE records a sale and is the default
  • totalAmount: Defaults to "0.00", so send the real total
  • addresses: Jurisdiction is resolved from these, so an incomplete address means tax cannot be calculated accurately
  • items: The line items sold
  • customer: The buyer, with externalId, name, email, and companyName. Omit it for a sale with no customer identity, such as a marketplace or point-of-sale sale
  • source: Where the sale originated, for example API. Defaults to OTHER
  • description: A human-readable label that pays for itself when reconciling
  • marketplace: true for reseller or marketplace orders where tax was remitted by someone else. Tax liability is excluded. Whether gross sales count toward a state's nexus threshold depends on the state, as each nexus period's includeMarketplaceTransactions shows

Your organization comes from the credential: The request body carries no organization field. When your key can reach more than one organization, choose one with an Organization-Id, Connection-Id, or Entity-Id header, and let the body describe the sale.

Money fields are decimal strings, such as "100.00". Re-sending an externalId that already exists does not create a second transaction.

Transaction Items

Each line item points at a product:

  • externalProductId (required): The product's identifier in your system
  • date (required): Date and time of the line, normally matching the transaction date
  • externalId: Your identifier for the line item. Send it on every line: a credit note can only reverse a line by its externalId
  • quantity: Defaults to "1"
  • amount: Line amount before tax. Defaults to "0.00", so send the real figure
  • product and description: Product name and line description
  • taxAmountImported: Tax you already collected on this line, if any

Addresses

Every address entry needs a type of SHIP_TO, BILL_TO, SHIP_FROM, or BILL_FROM, plus the address itself: street1, street2, city, county, state, postalCode, and country (ISO 3166-1 alpha-2).

Tax jurisdiction usually follows the SHIP_TO address, or BILL_TO when there is no ship-to.

Transactions are processed asynchronously: POST /transactions returns 202 Accepted with the recorded transaction, a processingStatus of QUEUED, and tax totals of "0.00". totalTaxAmountCalculated and the per-line taxItems populate shortly afterwards. The returned id is not fetchable straight away either: GET /transactions/{transaction_id} answers 404 until processing completes, so poll it rather than treating the first 404 as a failure.

Historical Transaction Sync

Transaction sync integrations start with a historical import covering the previous full calendar year through today. This one-time operation sets your nexus tracking baseline.

Historical Data Requirements

Cover:

  • Start date: January 1st of the previous calendar year
  • End date: Today, or your integration start date
  • Scope: All completed sales in that window

Bulk Import Strategy

For large historical imports:

  1. Chunk by date range: Work month by month or week by week
  2. Batch your requests: The endpoint takes one transaction per call, so send them in groups and pause between groups
  3. Handle errors deliberately: Log failures with their requestId, fix the data, replay the batch
  4. Verify completion: Reconcile with GET /transactions by date range against your source-of-truth counts

Order matters: Import oldest first. Nexus is evaluated against transaction dates, and a chronological import keeps threshold crossings accurate as they are calculated.

Verifying Transactions

Read transactions back with GET /transactions. The endpoint is cursor-paginated (limit up to 100, default 50, plus cursor) and supports:

  • startDate and endDate (YYYY-MM-DD) for date ranges
  • status and processingStatus (comma-separated) to separate committed, pending, and still-processing records
  • search for a free-text search over transaction id, externalId, externalFriendlyId, description, and customer name
  • type, country, state, marketplace, exempt, source, and filingId to narrow further
  • sort and order to sort. The default is date, descending, so newest first

For a direct lookup, use GET /transactions/{transaction_id} with the Kintsugi transaction ID. The Tenanted API has no lookup by externalId; use search instead.

Updating Transactions

Update with PUT /transactions/{transaction_id}. It is a replace: send externalId, date, and currency on every call, and the scalar fields and the customer are overwritten with what you send. Typical cases:

  • Address corrections: Addresses are replaced per type, so a SHIP_TO you send replaces the stored ship-to and a type you omit is left as it was
  • Amount adjustments: Correcting totals or line items. Lines are matched by externalId: a new externalId is added, and a stored line whose externalId you do not send is removed

The transaction's type cannot be changed, and tax is recalculated asynchronously after the update. Credit notes have their own update, PATCH /transactions/{transaction_id}.

Filed transactions lock: A locked or already-filed transaction answers 409 and can no longer be updated. Make corrections before the filing period closes.

To remove a sale entirely, Archive a transaction. Archiving is one-way: the transaction disappears from every read, cannot be restored, and stops counting toward nexus. A locked or already-filed transaction cannot be archived.

Best Practices

Data Quality

  • Use consistent external IDs: One convention across every system, on the transaction and on every line
  • Validate before syncing: Confirm products exist and addresses are valid first
  • Send complete data: Fields with defaults, especially totalAmount and item amount, will silently post as zero if you omit them
  • Get timestamps right: Send the real transaction time on date, as an RFC 3339 timestamp

Sync Timing

  • Sync after payment confirmation: A synced sale is committed and counts at once
  • Sync in chronological order: Oldest first, especially on historical imports
  • Store Kintsugi transaction IDs: You need the id for updates, credit notes, and direct lookups
  • Monitor the pipeline: Track both request success and processingStatus on the records you create

Error Handling

Common failures when syncing transactions:

  • Invalid address: Validate addresses before syncing
  • Missing required fields: externalId, date, and currency are required. The error's errors array names each field that failed
  • Locked transaction: Updating or archiving a filed transaction returns 409
  • Missing or invalid API key: Every request needs a valid Api-Key header, or it returns 401

See the Error Handling guide for detailed strategies.

Integration Patterns

E-Commerce Platforms

E-commerce platforms typically sync the moment an order completes:

  1. Order is placed and payment confirmed
  2. Create the transaction with type: "SALE"
  3. Include every line item with its product reference and line externalId
  4. Include the shipping address so the jurisdiction resolves correctly

Subscription Platforms

Subscription platforms sync per billing cycle:

  1. The subscription invoice is generated
  2. Create the transaction once the invoice is paid
  3. Reference the subscription product and the customer
  4. Include the billing address

Accounting Systems

Accounting systems sync in batches:

  1. Export completed invoices and sales
  2. Create transactions with type: "SALE"
  3. Process in date order, oldest first
  4. Retry failures after correcting the underlying data

Next Steps

With transaction sync running:

  1. Handle refunds: Record credit notes against original sales. See the Handling Refund Transactions guide.

  2. Query transactions: Use the GET endpoints for reporting and reconciliation. See the List transactions API reference.

  3. Monitor sync health: Watch request success rates and processingStatus so failures surface early.

For endpoint-level detail, see: