API changelog
Every change to the Kintsugi API and every release, newest first. Breaking changes carry the Breaking change mark. Tenanted releases are dated, and you choose one with the Api-Version header.
Changes
2026-10-07
Recalculates a filing's amounts on requestFilings
POST /filings/{filing_id}/recalculate queues a recalculation of a filing's amounts from its transactions and answers 202 with filingId, countryCode and status QUEUED. The recalculation runs in the background, so read the filing again for the new amounts. Only US and Canadian filings that are not in FILING, SUBMITTED or FILED status can be recalculated; others answer 400 with code invalid_request. It is available only for organizations that file their own returns, to their Owners and Admins, their API keys and the portfolio that manages them; other callers receive 403. A filing that does not exist or belongs to an organization you cannot access answers 404. Send an Organization-Id, Connection-Id or Entity-Id selector to say which organization the filing belongs to.
- After the
202, readGET /filings/{filing_id}to see the recalculated amounts.
2026-10-06
Returns a US filing's tax liability by local jurisdictionFilings
GET /filings/{filing_id}/enhanced-data returns a US filing's actual tax liability: summary totals, jurisdictionBreakdown per local jurisdiction, deductions and exemptions, refunds, and state-specific breakdowns such as county groupings and use tax where the state reports them. Send the filing's two-letter state as jurisdiction. The data is built on request. When it is ready the response is 200 with status DONE and the data in data; while it builds the response is 202 with IN_PROGRESS, so poll until it is DONE. A failed build answers 200 with FAILED and is not retried until you ask. A filing with no transactions answers DONE with data set to null. POST /filings/{filing_id}/enhanced-data/rebuild starts a fresh build even when one is stored and answers 202, or reports the build already running. Rebuilding is open to the same callers as PUT /filings/{filing_id}/submission, for organizations that file their own returns; others receive 403. It allows 10 requests a minute per portfolio, or per organization outside a portfolio, then answers 429. Both endpoints answer 404 for a filing you cannot access, 400 with code invalid_request when jurisdiction does not match the filing, and 400 with the new code unsupported_jurisdiction for a state without this data.
- Poll the GET endpoint while it answers
202, and call rebuild after aFAILEDresult. - If your client accepts only known error
codevalues, addunsupported_jurisdiction.
2026-10-05
Breaking changesLimits pausing a filing to the window before its due dateFilingsBreaking change
Pausing a filing now follows the same window as the Kintsugi app. After the 15th of the month a filing is due, it can no longer be paused with any pauseIntent, including assistance and skip, which were accepted before. A review pause also needs a pausedUntilDate from today through the 15th of the due month; a date in the past, accepted before, is now refused. A date that is still today anywhere in the world counts as today. POST /filings/{filing_id}/pause answers a refused pause with 400 and code invalid_request, and POST /filings/bulk/pause still answers 200, listing each refused filing in failed.
- Pause a filing no later than the 15th of the month it is due.
- For a
reviewpause, send apausedUntilDateno earlier than today and no later than the 15th of the due month. - After a bulk pause, check
failedfor filings that were not paused.
Records the confirmation and documents for a return you file yourselfFilings
Two endpoints let an organization that files its own returns record each one in Kintsugi. PUT /filings/{filing_id}/submission takes an action of save_draft, which saves the confirmation details and keeps the filing in FILING, or mark_filed, which saves them and marks the filing FILED. Its optional fields are returnConfirmationId, paymentConfirmationId, amountAdjusted, amountFees, amountPenalties and amountDiscounts, with amounts as decimal strings; a field you leave out is unchanged and a field sent as null is cleared. It returns the updated filing, or 409 when the filing is not in FILING. PUT /filings/{filing_id}/artifacts/{artifact_type} stores the RETURN or PAYMENT confirmation as a PDF of up to 10 MB, sent in the file part of a multipart/form-data body, replacing any document already stored for that type. It answers 409 unless the filing is FILING or FILED, 413 for a larger file and 422 for a file that is not a PDF. Both endpoints are available only for organizations set up to file their own returns, to their Owners and Admins, their API keys and the portfolio that manages them; other callers receive 403.
- Upload the return and payment confirmations while the filing is in
FILING, then call the submission endpoint withaction: "mark_filed". - Download a stored document with
GET /attachments/{attachment_id}/download.
2026-10-02
Checks the length of a pause reason before pausingFilings
A pauseReason is saved in a note on the filing, and the note, including a short label Kintsugi adds, holds up to 500 characters. A longer reason used to fail with a server error, sometimes after the filing was already paused. It now answers 400 with code invalid_request before anything changes, and POST /filings/bulk/pause refuses the whole request.
- Keep
pauseReasoncomfortably under 500 characters.
2026-09-30
Requests back filings for past periods through v1Filings
Three v1 endpoints, now documented, let you ask Kintsugi to file returns for periods before your regular filing schedule began. GET /v1/filings/back-filing-request/options lists each active US registration with the periods it can request: periods that have ended, start on or after the registration's tax collection start, end before its first regular filing period, and are not already covered by a filing. Each period has a start_date, an end_date and a label, and each registration a remittance_tag (Paid with return, State bills you later or null) saying how the state collects penalties and interest. POST /v1/filings/back-filing-request takes requests, each a registration_id with its periods, and optional notes. It creates one BACK_FILING filing with status UNFILED per period and returns them in created_filings, with their count in total_created, and 200. Every period is checked before anything is created, so one invalid period refuses the whole request with 400. An unknown registration_id answers 404, an organization without a payment method on file receives 402, and an organization without back filing available receives 404 from both request endpoints. Nothing is filed until each filing is approved with the current terms from GET /v1/filings/back-filing-terms/current, which returns their id, version and text.
- Request only the
start_dateandend_datepairs that the options endpoint lists for each registration. - Show the current terms to the person approving, then approve each filing with
PUT /v1/filings/{filing_id}/approve, sending the termsidasback_filing_terms_id. Missing or outdated terms answer400.
Releases
2026-10-06
LatestTenanted APIConsistent country codes, empty values and status casing
2026-10-06 makes the Tenanted API more predictable to build on. Every country code is now countryCode, a value that is not set is null rather than an empty string, and status and type values are uppercase throughout. Integrations pinned to 2026-07-21 are unaffected until you choose to move, and the table below lists everything that changes when you do.
Compared with 2026-07-21
| Change | Applies to | 2026-07-21 | 2026-10-06 |
|---|---|---|---|
| Country code field | Addresses, customers, transactions, tax estimates and billing usage, in requests and responses | country | countryCode. Query parameters named country keep their name. |
| State on nexus exposure events | GET /nexus/{nexus_id}/exposure-history | state | stateCode, always present |
| State of a country-level filing | stateCode and stateName on every filing | Empty string | null |
| Organization state and country when not set | state and countryCode on organizations, and state in organization lists | Empty string, always present | null, and may be omitted |
| Exemption with no match on a certificate upload | exemptionId on missing-certificate upload results | Empty string | null |
| Missing-certificate status values | Upload, upload status and public confirm-upload results | Lowercase: processing, satisfied, rejected | Uppercase: PROCESSING, SATISFIED, REJECTED, plus PENDING on the public landing page |
| Exemption type when approving certificate imports | POST /certificate-imports/{certificate_import_id}/approve and POST /certificate-imports/bulk-approve | Any text, defaulting to customer | CUSTOMER, WHOLESALE, TRANSACTION or REVERSE_CHARGE, defaulting to CUSTOMER. Any other value returns 422. |
| Security questions in a credential reveal | fields on POST /registrations/{registration_id}/credentials/reveal | security_questions | securityQuestions |
| Line item with no product name | productName on transaction lines | null | Empty string |
| Help article label on back-filing options | GET /filings/backFilingRequest/options | Text or null | Always text |
| Job ID on bulk filing results | POST /filings/bulk/approve and POST /filings/bulk/pause | jobId, always null | Removed |
Moving an integration from 2026-07-21
- Send
Api-Version: 2026-10-06with each request you move. Requests without it keep running against 2026-07-21. - Rename
countrytocountryCodewherever you send or read an address, customer, transaction or tax estimate. - Treat
nullas "not set" for filing and organization locations and for an unmatchedexemptionId, and an emptyproductNameas "no product name". - Compare missing-certificate statuses in uppercase, and send
exemptionTypein uppercase when you approve certificate imports. - Read
stateCodeon nexus exposure events, requestsecurityQuestionswhen you reveal registration credentials, and stop readingjobIdon bulk filing results.
2026-07-21
Tenanted APIIntroducing the Tenanted API
A fresh foundation for building on Kintsugi. The Tenanted API is versioned by date, and you choose the release you build against. It speaks one consistent dialect from end to end: clean paths, camelCase fields, exact decimal amounts, and a single error format. And it is built for scale, with one credential reaching every organization it owns.
Compared with v1
| Topic | v1 | 2026-07-21 |
|---|---|---|
| Versioning | The /v1 path prefix | The Api-Version header, dated YYYY-MM-DD. Optional; without it, a request runs against the launch release |
| Paths | /v1/transactions | /transactions |
| Authentication | x-api-key | Api-Key. Endpoints that manage people accept a signed-in session token instead |
| Choosing an organization | x-organization-id, required on almost every request | One credential reaches every organization it owns. Narrow a request with Organization-Id, Connection-Id, or Entity-Id |
| Field names | snake_case | camelCase |
| Money and rates | Decimal strings out, numbers or strings in | Decimal strings at a fixed scale: amounts to 2 places, rates to 9 |
| Timestamps | No single documented format | RFC 3339 in UTC, always ending in Z |
| Errors | Shapes vary by endpoint | One envelope everywhere: code, message, requestId, and errors |
| Portfolio | Not available | Portfolio and Portfolio Reseller endpoints, for partner accounts |
Moving an integration from v1
- Send
Api-Versionwith every request, pinned to the release you build against (the newest is2026-10-06), so your integration stays on it until you decide to move. - Drop
/v1from your paths. - Send your key as
Api-Key, and replacex-organization-idwithOrganization-Idwherever you target one organization. - Rename fields to camelCase, and read every amount as a decimal string, never a float.
- Branch on the error
code, not the message or the HTTP status, and quoterequestIdwhen you contact support.
Creating a transaction answers 202 Accepted straight away, and tax is calculated just after. Check processingStatus before you read the tax totals.
v1
LegacyThe original Kintsugi API, versioned in the path. It is documented exactly as before, so existing integrations can keep running with confidence. New integrations should start on the newest Tenanted API release.