KintsugiKintsugi
API Guides

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, status
  • Line items that reference your products
  • Customer details and addresses
  • Tax amounts, when tax was calculated 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: /v1/transactions records sales; it does not calculate tax. With the tax engine (L2) enabled, Kintsugi prices tax at checkout 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 cuts request volume and 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 is the only thing that decides whether a transaction affects your compliance position.

COMMITTED
Counts toward nexus thresholds at its full amount and appears in filing preparation. The end state for a sale that stands.
PENDING
Stored, but excluded from both. A holding state, not an end state.
CANCELLED
Excluded permanently, and kept on record so the order history stays complete.
FULLY_REFUNDED
The sale was refunded in full, so it nets to nothing for compliance. Kintsugi sets this as credit notes cover the full amount, and you can send it yourself on a historical import that is already refunded.
PARTIALLY_REFUNDED
Part of the sale was refunded. It still counts, reduced by the credited amount. Set the same two ways as FULLY_REFUNDED.

COMMITTED is the default when you omit status. Every value above is accepted on both create and update, refunded states included, so a historical import can land a sale directly in its end state instead of replaying the sale and then its credit note. Kintsugi also uses INVALID and ARCHIVED for records it sets aside itself; you would not normally send either.

status and refund_status are different fields: status is the transaction's overall state, and it is what compliance reads. refund_status is a narrower field that only ever holds FULLY_REFUNDED or PARTIALLY_REFUNDED, and Kintsugi maintains it as credit notes arrive. Both are writable on create and update; see Handling Refund Transactions for how credit notes drive them.

Only COMMITTED transactions count in full: Transactions with status: "COMMITTED" feed nexus calculations and filing preparation at their full amount. PENDING transactions are stored but sit out of compliance processing until they are committed, and refunded states count net of what was credited.

Choosing a Sync Pattern

There are two ways to get a sale into Kintsugi, and they are alternatives rather than consecutive steps. The difference is when you first call Kintsugi, before the payment clears or after. Both end in the same place.

PATTERN ASimplest
Sync after payment
One call, sent once the payment clears. Failed orders never reach Kintsugi at all.
Best when
Payment settles in one step, at checkout. Nothing to reconcile later.
PATTERN BFull lifecycle
Create pending, then update
Record the sale immediately as PENDING, then commit or cancel it on the outcome.
Best when
Payment is asynchronous: invoices, terms, authorizations captured later.

Pattern A: Sync After Payment

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 cancel or reverse.
Assemble and check the payload
typecustomeraddressestransaction_items
Every product must already exist as a product record, and every address must validate. Both are the usual cause of a rejected sync.
Send the transaction, already committed
POST/v1/transactionsstatus: COMMITTED
COMMITTED is the default, so omitting status lands here too. Send it anyway: it makes the intent explicit at the call site.
Synced and counting toward nexus
Nothing further to do. The sale is filing-ready.

Pattern B: Create Pending, Then Update

Two calls. The first records the sale, the second resolves it. Status is what makes it count.

Record the sale up front
POST/v1/transactionsstatus: PENDING
Same payload as pattern A, but status is not optional here: it defaults to COMMITTED, so leaving it out commits the sale immediately. A pending transaction is stored but excluded from nexus and filings.
Wait for the payment outcome
Minutes or weeks. The transaction sits in PENDING until you know.
Update the status to match
PUT/v1/transactions/{transaction_id}Kintsugi id, not external_id
PAID→ COMMITTED
Now counted in nexus calculations and pulled into filing preparation.
DECLINED→ CANCELLED
Excluded from compliance tracking. Keep the record; don't delete it.
This is a full replace, not a patch: external_id, date, customer, addresses and transaction_items all have to come back with the new status. Store the id from step 1, or resolve it with GET /v1/transactions/external/{external_id}.
A transaction left in PENDING is invisible to nexus and filings. If step 3 never runs, the sale silently goes unreported. Poll GET /v1/transactions?status=PENDING to catch records that have gone stale.

Beyond payment confirmation, creating as PENDING is also how you reserve an external_id before an order is final. Cancel rather than commit when the order is voided, payment fails and will not be retried, or the sale falls through: cancelled transactions stay on record for audit purposes and are excluded from nexus calculations and filings.

Creating Transactions

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

Required Fields

  • external_id: Your unique identifier for the transaction (for example, "TXN-2026-001")
  • date: Transaction date and time in ISO 8601 format
  • type: Transaction type. Use SALE for sales
  • currency: ISO 4217 currency code, for example USD
  • customer: The buyer, either matched by external_id or described inline
  • addresses: At least one address
  • transaction_items: The line items sold
  • status: Defaults to COMMITTED. Send it explicitly when you sync orders before payment clears
  • total_amount: Defaults to 0.00, so send the real total
  • source: Where the sale originated, for example API. Defaults to OTHER
  • description: A human-readable label that pays for itself when reconciling

Your organization is read from the header: x-organization-id scopes every request, and the organization_id field in the request body is deprecated. Send both authentication headers, x-api-key and x-organization-id, and let the body describe the sale.

Transaction Items

Each line item points at a product:

  • external_product_id (required): The product's identifier in your system
  • date (required): Item date, normally matching the transaction date
  • external_id: Your identifier for the line item
  • quantity: Defaults to 1.0
  • amount: Line item subtotal. Defaults to 0.00, so send the real figure

Addresses

Every address entry needs a type of SHIP_TO, BILL_TO, SHIP_FROM, or BILL_FROM, plus the address itself: street_1, street_2, city, county, state, postal_code, and country (ISO 3166-1 alpha-2). A single full_address string can stand in for the components.

The SHIP_TO address sets the tax jurisdiction. When no SHIP_TO address is present, Kintsugi falls back to BILL_TO.

Transactions are processed asynchronously: POST /v1/transactions returns 202 Accepted with the queued record and a processing_status of QUEUED. A 202 means Kintsugi accepted the transaction, not that nexus and tax processing have finished. Read processing_status back through the GET endpoints to confirm it completed.

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 50 to 100 concurrently and pause between chunks
  3. Handle errors deliberately: Log failures, fix the data, replay the batch
  4. Verify completion: Reconcile with GET /v1/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 /v1/transactions. The endpoint is paginated (page, and size up to 100) and supports:

  • date__gte and date__lte for date ranges
  • status and processing_status__in to separate committed, pending, and still-processing records
  • search_query for a free-text search that covers your order identifiers
  • transaction_type, state, state_code, country, marketplace, exempt__in, and filing_id to narrow further
  • order_by to sort, prefixed with - for descending, for example -date

For exact lookups, use GET /v1/transactions/external/{external_id} with your own identifier, or GET /v1/transactions/{transaction_id} with the Kintsugi transaction ID.

Updating Transactions

Update with PUT /v1/transactions/{transaction_id}. Typical cases:

  • Status changes: Moving PENDING to COMMITTED after payment confirmation
  • Address corrections: Fixing incomplete or invalid addresses
  • Amount adjustments: Correcting totals or line items

Filed transactions lock: Once a transaction is included in a filing it is locked and can no longer be updated. Make corrections before the filing period closes.

Best Practices

Data Quality

  • Use consistent external IDs: One convention across every system
  • Validate before syncing: Confirm products exist and addresses are valid first
  • Send complete data: Fields with defaults, especially total_amount and item amount, will silently post as zero if you omit them
  • Get timezones right: Use ISO 8601 with timezone information on transaction dates

Sync Timing

  • Sync after payment confirmation: Only committed transactions count toward compliance
  • Sync in chronological order: Oldest first, especially on historical imports
  • Handle duplicates: Look up the transaction before creating it to avoid duplicate external_id errors
  • Monitor the pipeline: Track both request success and processing_status on the records you create

Error Handling

Common failures when syncing transactions:

  • Product not found: Create products before referencing them
  • Duplicate external_id: Check whether the transaction already exists
  • Invalid address: Validate addresses before syncing
  • Missing required fields: type and customer are required alongside external_id, date, currency, addresses, and transaction_items
  • Missing authentication headers: Every request needs both x-api-key and x-organization-id

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" and status: "COMMITTED"
  3. Include every line item with its product reference
  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" and status: "COMMITTED"
  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 Get Transactions API reference.

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

For endpoint-level detail, see: