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.
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.
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.
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 callcurrency: ISO 4217 currency code of every amount, for exampleUSD
Recommended Fields
type: Transaction type.SALErecords a sale and is the defaulttotalAmount: Defaults to"0.00", so send the real totaladdresses: Jurisdiction is resolved from these, so an incomplete address means tax cannot be calculated accuratelyitems: The line items soldcustomer: The buyer, withexternalId,name,email, andcompanyName. Omit it for a sale with no customer identity, such as a marketplace or point-of-sale salesource: Where the sale originated, for exampleAPI. Defaults toOTHERdescription: A human-readable label that pays for itself when reconcilingmarketplace:truefor 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'sincludeMarketplaceTransactionsshows
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 systemdate(required): Date and time of the line, normally matching the transaction dateexternalId: Your identifier for the line item. Send it on every line: a credit note can only reverse a line by itsexternalIdquantity: Defaults to"1"amount: Line amount before tax. Defaults to"0.00", so send the real figureproductanddescription: Product name and line descriptiontaxAmountImported: 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:
- Chunk by date range: Work month by month or week by week
- Batch your requests: The endpoint takes one transaction per call, so send them in groups and pause between groups
- Handle errors deliberately: Log failures with their
requestId, fix the data, replay the batch - Verify completion: Reconcile with
GET /transactionsby 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:
startDateandendDate(YYYY-MM-DD) for date rangesstatusandprocessingStatus(comma-separated) to separate committed, pending, and still-processing recordssearchfor a free-text search over transaction id,externalId,externalFriendlyId, description, and customer nametype,country,state,marketplace,exempt,source, andfilingIdto narrow furthersortandorderto sort. The default isdate, 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 aSHIP_TOyou 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 newexternalIdis added, and a stored line whoseexternalIdyou 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
totalAmountand itemamount, 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
idfor updates, credit notes, and direct lookups - Monitor the pipeline: Track both request success and
processingStatuson the records you create
Error Handling
Common failures when syncing transactions:
- Invalid address: Validate addresses before syncing
- Missing required fields:
externalId,date, andcurrencyare required. The error'serrorsarray 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-Keyheader, or it returns401
See the Error Handling guide for detailed strategies.
Integration Patterns
E-Commerce Platforms
E-commerce platforms typically sync the moment an order completes:
- Order is placed and payment confirmed
- Create the transaction with
type: "SALE" - Include every line item with its product reference and line
externalId - Include the shipping address so the jurisdiction resolves correctly
Subscription Platforms
Subscription platforms sync per billing cycle:
- The subscription invoice is generated
- Create the transaction once the invoice is paid
- Reference the subscription product and the customer
- Include the billing address
Accounting Systems
Accounting systems sync in batches:
- Export completed invoices and sales
- Create transactions with
type: "SALE" - Process in date order, oldest first
- Retry failures after correcting the underlying data
Next Steps
With transaction sync running:
-
Handle refunds: Record credit notes against original sales. See the Handling Refund Transactions guide.
-
Query transactions: Use the GET endpoints for reporting and reconciliation. See the List transactions API reference.
-
Monitor sync health: Watch request success rates and
processingStatusso failures surface early.
For endpoint-level detail, see: