> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.taxcloud.com/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).