> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.taxcloud.com/api-v-3/guides/getting-started/migrating-from-api-v-1-to-v-3/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.taxcloud.com/_mcp/server. # Migrating from API v1 to v3 This guide covers the key changes between API v1 and API v3 so you can update your integration efficiently. If you are building a new integration from scratch, skip this page and start with the [Welcome to the TaxCloud API](https://docs.taxcloud.com/guides/getting-started/welcome-to-tax-cloud-api) guide instead. ## What Changed at a Glance | Area | API v1 | API v3 | | :---- | :---- | :---- | | Protocol | SOAP/XML or JSON/REST | REST + JSON only | | Base URL | `api.taxcloud.net/1.0/TaxCloud/{method}` | `api.v3.taxcloud.com/tax/connections/{connectionId}/...` | | Authentication | `apiLoginID` + `apiKey` in the request body | `X-API-KEY` header + `connectionID` in the URL path | | Field naming | PascalCase (`ItemID`, `Qty`, `Zip5`) | camelCase (`itemId`, `quantity`, `zip`) | | Tax calculation | `Lookup` endpoint | `POST /carts` endpoint | | Order completion | `Authorized` / `Captured` / `AuthorizedWithCapture` | `POST /carts/orders` with `completed: true` or deferred via `PATCH /orders/{orderId}` | | Returns | `Returned` endpoint | `POST /orders/refunds/{orderId}` (standard) or `POST /orders` with `kind: "credit"` (standalone) | | Error reporting | `ResponseType` field (3 = success) | Standard HTTP status codes (200, 201, 400, 422, 500) | | Tax response | Tax amount only | Tax amount and rate per line item | | Address verification | `VerifyAddress` with credentials in body | Verify Address endpoint under `/tax/connections/{connectionId}/...` | ## Authentication **v1** passed `apiLoginID` and `apiKey` inside every request body: ```json { "apiLoginID": "XXXXXXX", "apiKey": "XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", ... } ``` **v3** uses an `X-API-KEY` header for authentication. The `connectionID` (which replaces `apiLoginID`) is part of the URL path: ```shell curl -X POST "https://api.v3.taxcloud.com/tax/connections/{connectionId}/carts" \ -H "X-API-KEY: your-api-key" \ -H "Content-Type: application/json" \ -d '{ ... }' ``` ### Migration Steps 1. Generate a new API key in the TaxCloud portal under **Developer > API**. 2. Locate your existing `connectionID` (your v1 connection works in v3) or create a new Custom API Connection under **Integrations > Custom API**. 3. Remove `apiLoginID` and `apiKey` from all request bodies. 4. Add the `X-API-KEY` header to every request. 5. Insert the `connectionID` into each endpoint URL. For full setup details, see [Setup and Authentication](https://docs.taxcloud.com/guides/getting-started/setup-and-authentication). ## Tax Calculation: Lookup to Carts The v1 `Lookup` endpoint is replaced by the v3 `POST /carts` endpoint. The core concept is the same (send items and addresses, receive tax amounts), but the request structure and field names have changed. ### v1 Request ```bash POST api.taxcloud.net/1.0/TaxCloud/Lookup ``` ```json { "apiLoginID": "XXXXXXX", "apiKey": "XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", "customerID": "customer-33", "cartID": "B0DABCEE-34EE-4A76-B4C5-B5F32F430B74", "deliveredBySeller": false, "origin": { "Address1": "162 East Ave", "City": "Norwalk", "State": "CT", "Zip5": "06851", "Zip4": "5715" }, "destination": { "Address1": "255 S King St", "City": "Seattle", "State": "WA", "Zip5": "98104", "Zip4": "2832" }, "cartItems": [ { "Index": 0, "ItemID": "prod23523", "TIC": 20010, "Price": 21.95, "Qty": 3 } ] } ``` ### v3 Request ```bash POST https://api.v3.taxcloud.com/tax/connections/{connectionId}/carts ``` ```json { "items": [ { "currency": { "currencyCode": "USD" }, "customerId": "customer-33", "origin": { "line1": "162 East Ave", "city": "Norwalk", "state": "CT", "zip": "06851-5715" }, "destination": { "line1": "255 S King St", "city": "Seattle", "state": "WA", "zip": "98104-2832" }, "lineItems": [ { "index": 0, "itemId": "prod23523", "tic": 20010, "price": 21.95, "quantity": 3 } ] } ] } ``` ### Key Differences | v1 Field | v3 Field | Notes | | :---- | :---- | :---- | | `cartItems` | `items[].lineItems` | Line items are nested inside an `items` array | | `cartID` (body) | `cartId` (response) | Both versions support auto-generated cart IDs. In v3 the `cartId` is always returned in the response | | `customerID` (body) | `items[].customerId` | Same concept; now camelCase and nested inside each item object | | `Address1` / `Zip5` / `Zip4` | `line1` / `zip` | camelCase; `zip` combines 5-digit and plus-4 codes (e.g., `"98104-2832"`) | | `ItemID` | `itemId` | camelCase | | `TIC` | `tic` | camelCase | | `Qty` | `quantity` | Renamed and camelCase | | Not returned | `tax.rate` | v3 responses include both rate and amount per line item | ### v3 Response (excerpt) ```json { "items": [ { "cartId": "ce4a...ccefdd", "customerId": "customer-33", "lineItems": [ { "itemId": "prod23523", "price": 21.95, "quantity": 3, "tax": { "rate": 0.1025, "amount": 6.75 } } ] } ] } ``` > **Tip:** v3 returns the tax rate alongside the amount for each line item. v1 only returned the tax amount. ## Order Completion Both v1 and v3 require you to authorize/capture a tax lookup to create an order. The core workflow is the same; the main change is terminology and endpoint structure. What v1 called `AuthorizedWithCapture` is now "creating an order from a cart" in v3. ### v1: AuthorizedWithCapture ```bash POST api.taxcloud.net/1.0/TaxCloud/AuthorizedWithCapture ``` ```json { "apiLoginID": "XXXXXXX", "apiKey": "XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", "customerID": "customer-33", "cartID": "B0DABCEE-34EE-4A76-B4C5-B5F32F430B74", "orderID": "order-123" } ``` ### v3: Convert Cart to Order ```bash POST https://api.v3.taxcloud.com/tax/connections/{connectionId}/carts/orders ``` ```json { "cartId": "ce4a...ccefdd", "orderId": "order-123", "completed": true } ``` ### Key Differences * **Unified endpoint.** v1 had three separate endpoints (`Authorized`, `Captured`, `AuthorizedWithCapture`). v3 consolidates these into a single `POST /carts/orders` endpoint that handles all three cases. The number of API calls in a given workflow stays the same. * **Flexible completion.** Set `completed: false` at creation and `PATCH /orders/{orderId}` with a `completedDate` later, or pass `completedDate` directly on the `POST /carts/orders` request when the order is already complete. The inline date must be at or before the request time. Deferring completion supports cash-basis accounting, fulfillment-based workflows, and pre-orders. * **No `customerID` needed.** Customer data is already captured in the cart. For the full workflow, see [Convert Carts to Orders](https://docs.taxcloud.com/guides/workflows/real-time-api/convert-carts-to-orders). ## Returns and Refunds v1 used a single `Returned` endpoint. v3 introduces a dedicated Refund API and adds standalone credits for adjustments not tied to an existing order. ### v1: Returned ```bash POST api.taxcloud.net/1.0/TaxCloud/Returned ``` ```json { "apiLoginID": "XXXXXXX", "apiKey": "XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", "orderID": "order-123", "returnedDate": "2025-08-01" } ``` For partial returns, you included a `cartItems` array with the items being returned and adjusted `Qty` values. ### v3: Refund Order ```bash POST https://api.v3.taxcloud.com/tax/connections/{connectionId}/orders/refunds/{orderId} ``` **Full return** (empty body): ```json {} ``` **Partial return** (specify items): ```json { "items": [ { "itemId": "prod23523", "quantity": 1 } ] } ``` ### Key Differences | v1 | v3 | | :---- | :---- | | `cartItems` array with full item details (`Price`, `Index`, etc.) | `items` array with only `itemId` and `quantity` | | Full return requires `orderID` only | Full return uses an empty request body | | Single `Returned` call per order | Multiple returns allowed against the same order | | No standalone credits | Standalone credits via `POST /orders` with `kind: "credit"` | | Partial return adjusts `Qty` | Partial return specifies the `quantity` to return | > **Note:** Standalone credits let you reduce tax liability without referencing an original order. Set `kind: "credit"` on the [Create Order](https://docs.taxcloud.com/api-reference/api-reference/sales-tax-api/orders/create-order) endpoint. See [Standalone Credits](https://docs.taxcloud.com/guides/workflows/processing-returns/standalone-credits). ## Exemptions The approach to exemptions has been simplified in v3. ### v1 Pass an `exemptCert` object inside the `Lookup` request, containing either a `CertificateID` (for a previously saved certificate) or a full `Detail` object to create a new certificate inline. ### v3 Add an `exemption` object to the cart or order payload: **Direct attach (recommended):** ```json { "exemption": { "exemptionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" } } ``` **Auto-match:** ```json { "exemption": { "isExempt": true } } ``` ### Key Differences * v3 does not support creating certificates inline during tax calculation. Create certificates separately using the [Create Exemption Certificate](https://docs.taxcloud.com/api-reference/api-reference/sales-tax-api/exemption-certificate/create-exemption-certificate) endpoint, then reference them by ID. * Auto-match (`isExempt: true`) searches by `customerID`, `connectionID`, and destination state. If no match is found, the order is flagged **Exempt--No certificate** and requires manual resolution before filing. * Direct attach by `exemptionId` is the recommended approach for production integrations. For details, see [Managing Tax Exemptions](https://docs.taxcloud.com/guides/core-concepts/managing-tax-exemptions). ## Error Handling v1 returned HTTP 200 for every response, using a `ResponseType` field to indicate success or failure. v3 uses standard HTTP status codes. | v1 | v3 | | :---- | :---- | | `ResponseType: 3` = success | `200` or `201` = success | | `ResponseType: 0` = error with `Messages` array | `400` = malformed request | | Same pattern for all endpoints | `422` = valid structure but invalid content | | | `500` = transient server error (retry with exponential backoff) | ### Migration Steps 1. Replace any logic that checks `ResponseType === 3` with standard HTTP status code checks. 2. Parse error details from the JSON response body instead of the `Messages` array. 3. Implement retry logic with exponential backoff for `500` errors. See [Handling Errors](https://docs.taxcloud.com/guides/workflows/handling-errors) for a sample pattern. ## Address Format Address fields have been renamed and simplified. | v1 Field | v3 Field | | :---- | :---- | | `Address1` | `line1` | | `Address2` | `line2` | | `City` | `city` | | `State` | `state` | | `Zip5` + `Zip4` (separate fields) | `zip` (single field, e.g., `"98104-2832"`) | > **Note:** v3 still requires two-character state abbreviations. Do not pass full state names. > **Note:** The plus-4 extension is optional. If you only have the 5-digit ZIP, pass it as-is (e.g., `"zip": "98104"`). TaxCloud will still calculate tax correctly. ## Testing and Environments The testing and environment model is largely the same between v1 and v3. The main difference is that v3 uses a `connectionID` instead of `apiLoginID` to identify the environment. Create a dedicated test connection for development and QA. When you go live, switch to your production `connectionID`. Archive the test connection afterward to prevent accidental use. For details, see [Testing and Going Live](https://docs.taxcloud.com/guides/getting-started/testing-and-going-live). ## New in v3 These capabilities are new or significantly improved in v3: * **Order Upload flow.** A significantly improved version of the v1 `AddTransactions` capability. Submit pre-existing or historical orders directly, bypassing the cart step. See [Order Upload Overview](https://docs.taxcloud.com/guides/workflows/order-upload/overview). * **Flexible order completion.** v1 supported a two-step flow via separate `Authorized` and `Captured` endpoints. v3 streamlines this into a single endpoint. Create the order with `completed: false` and finalize later with a `completedDate` via PATCH, or set `completedDate` inline at creation when the order is already complete. The inline date must be at or before the request time. * **Standalone credits.** Issue tax credits not tied to a specific order. See [Standalone Credits](https://docs.taxcloud.com/guides/workflows/processing-returns/standalone-credits). * **`excludeFromFiling` flag.** Mark orders that should not be included in TaxCloud's filed returns (e.g., orders already filed elsewhere). * **Management API.** A separate set of endpoints for account and connection management. * **Tax rate in responses.** Every tax calculation now returns both the rate and the amount per line item. ## Migration Checklist Use this checklist to track your migration progress: 1. Generate a new `X-API-KEY` and create a test `connectionID` in the TaxCloud portal. 2. Update your HTTP client to send `X-API-KEY` as a header and remove credentials from request bodies. 3. Replace `Lookup` calls with `POST /carts`. 4. Update address objects to use camelCase fields and the combined `zip` format. 5. Update line item fields: `ItemID` to `itemId`, `TIC` to `tic`, `Qty` to `quantity`. 6. Replace `AuthorizedWithCapture` (or `Authorized` + `Captured`) with `POST /carts/orders`. 7. Replace `Returned` calls with `POST /orders/refunds/{orderId}`. 8. Update exemption handling to use the `exemption` object with `exemptionId` or `isExempt`. 9. Replace `ResponseType` checks with HTTP status code handling. 10. Test the full flow (cart, order, refund) against your test connection. 11. Switch to your production `connectionID` and verify end-to-end. ## Need Help? If you run into issues during migration, reach out to the TaxCloud support team or explore the full [API Reference](https://docs.taxcloud.com/api-reference).