> This page is for version v5.0.
> For other versions, use one of these documentation indexes:
> - v6.0 (default): https://docs.zip.tax/v-6-0/llms.txt
> - v5.0: https://docs.zip.tax/v-5-0/llms.txt

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.zip.tax/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.zip.tax/_mcp/server.

# Response Codes

Every Ziptax response carries an application-level response code in
addition to the HTTP status. The code tells you what happened in
business terms (success, bad input, plan-gated feature, quota
exhausted, and so on) and is the signal your integration should
branch on.

## Response envelope

Both success and error responses use the same envelope. The code lives
at `metadata.response`:

```json
{
  "metadata": {
    "version": "v60",
    "response": {
      "code": 100,
      "name": "RESPONSE_CODE_SUCCESS",
      "message": "Successful API Request.",
      "definition": "http://api.zip-tax.com/request/v60/schema"
    }
  }
}
```

> **Info**
>
> Legacy versions (v50 and earlier) return the same fields at the top
> level as `rCode`, `rName`, and `rMessage` instead of nested under
> `metadata.response`. The numeric codes are identical across all
> versions.

## Full list

|    Code | Name                                      | HTTP | Message                                                                                                   |
| ------: | ----------------------------------------- | ---: | --------------------------------------------------------------------------------------------------------- |
| **100** | `RESPONSE_CODE_SUCCESS`                   |  200 | Successful API Request.                                                                                   |
| **101** | `RESPONSE_CODE_INVALID_KEY`               |  401 | Key format is not valid or key not found.                                                                 |
| **102** | `RESPONSE_CODE_INVALID_STATE`             |  422 | The provided State is not in a valid format parsable by the API.                                          |
| **103** | `RESPONSE_CODE_INVALID_CITY`              |  422 | The provided City is not in a valid format parsable by the API.                                           |
| **104** | `RESPONSE_CODE_INVALID_POSTAL_CODE`       |  422 | The provided Postal Code is not in a valid format parsable by the API.                                    |
| **105** | `RESPONSE_CODE_INVALID_FORMAT`            |  422 | Query string format is not valid.                                                                         |
| **106** | `RESPONSE_CODE_API_ERROR`                 |  500 | Unknown API error.                                                                                        |
| **107** | `RESPONSE_CODE_FEATURE_NOT_ENABLED`       |  405 | Requested feature or version not enabled for your current plan. Upgrade your plan to access this feature. |
| **108** | `RESPONSE_CODE_REQUEST_LIMIT_MET`         |  429 | API request limit met.                                                                                    |
| **109** | `RESPONSE_CODE_ADDRESS_INCOMPLETE`        |  422 | The provided address is missing, incomplete, or not a valid address.                                      |
| **110** | `RESPONSE_CODE_NO_RESULT`                 |  422 | Query parameters valid but no result found.                                                               |
| **111** | `RESPONSE_CODE_INVALID_HISTORICAL`        |  422 | The provided historical parameter is not in a valid format.                                               |
| **112** | `RESPONSE_CODE_INTERNATIONAL_NOT_ENABLED` |  403 | International rates not enabled for this key.                                                             |
| **113** | `RESPONSE_CODE_PRODUCT_RULES_NOT_ENABLED` |  403 | Product rate rules not enabled for this key.                                                              |

## When you'll see each

### 100, Success

The lookup completed and the response contains rate data. Always check
for `100` before reading `baseRates` or `taxSummaries`.

### 101, Invalid key

The `X-API-KEY` header (or `key=` query parameter) is missing,
malformed, or doesn't match a key in our database. Check for trailing
whitespace, encoding issues, or using the wrong environment's key.

### 102 to 105, Input validation

The state, city, postal code, or overall query string isn't in a shape
Ziptax can parse. These are deterministic, so re-sending the same
request will always fail the same way. Fix the input before retrying.

### 106, Unknown API error

Something went wrong on our end. Safe to retry with exponential backoff.
If you see these persistently, email [support@zip.tax](mailto:support@zip.tax).

### 107, Feature not enabled

The API version or feature you requested isn't available on your plan
(for example, calling `/request/v60` on a plan that only includes v40).
Upgrade your plan or use a supported version.

### 108, Rate limit

You've sent more requests than your per-minute `request_rate`
entitlement allows within the current 60-second sliding window. The
response includes `X-RateLimit-Limit` and `X-RateLimit-Remaining`
headers. See [Rate Limiting & Errors](./rate-limiting-errors) for
backoff guidance.

### 109, Address incomplete

The address (or lat/lng, or postal code) you sent couldn't be resolved
to a real location. Common causes: missing street number, obviously
wrong ZIP for the city, coordinates in the middle of the ocean, or a
typo that leaves the geocoder unable to disambiguate.

### 110, No result

Parameters were valid but nothing matched. Most common on historical
lookups where the date precedes our coverage, or niche international
territories.

### 111, Invalid historical

The `historical` parameter wasn't accepted. Use the format `YYYYMM`
(6 digits, no separator, e.g. `202401` for January 2024). The API also
rejects the current month, any future month, and months older than the
service's historical coverage window.

### 112, International not enabled

You passed `countryCode=CAN` (or another non-USA country) but your
account doesn't have the `rate_loc_can` entitlement. Upgrade to Pro or
Enterprise to unlock Canadian lookups.

### 113, Product rules not enabled

You passed `taxabilityCode=...` but your account doesn't have the
`product_rates` entitlement. Upgrade to Pro or Enterprise to unlock
product-specific rate rules. See [Taxability Information Codes](../product-rules/taxability-information-codes)
for what this parameter does.

## Handling codes programmatically

Branch on the numeric `code`, not the HTTP status or message text. The
messages are documented here for humans but may be refined over time.
The codes are stable.

#### Python

```python
import requests

res = requests.get(
    "https://api.zip-tax.com/request/v60",
    headers={"X-API-KEY": "YOUR_API_KEY"},
    params={"address": "200 Spectrum Center Dr, Irvine CA"},
)
data = res.json()
code = data["metadata"]["response"]["code"]

if code == 100:
    rate = data["taxSummaries"][0]["rate"]
elif code == 108:
    # back off, respect X-RateLimit-* headers
    ...
elif code in (112, 113):
    # feature not on this plan; show an upsell or skip silently
    ...
elif code == 109:
    # address didn't resolve; prompt the user to fix it
    ...
else:
    # log, alert, and fail closed
    ...
```

#### Node.js

```javascript
const res = await fetch(
  "https://api.zip-tax.com/request/v60?address=" +
    encodeURIComponent("200 Spectrum Center Dr, Irvine CA"),
  { headers: { "X-API-KEY": "YOUR_API_KEY" } }
);
const data = await res.json();
const code = data.metadata.response.code;

switch (code) {
  case 100: // success
    break;
  case 108: // rate limit; back off
    break;
  case 112:
  case 113: // plan-gated feature
    break;
  case 109: // bad address
    break;
  default:  // log + alert
}
```

#### Go

```go
type Response struct {
    Metadata struct {
        Response struct {
            Code int    `json:"code"`
            Name string `json:"name"`
        } `json:"response"`
    } `json:"metadata"`
}

var r Response
_ = json.NewDecoder(res.Body).Decode(&r)

switch r.Metadata.Response.Code {
case 100:
    // success
case 108:
    // rate limit
case 112, 113:
    // plan-gated
case 109:
    // bad address
default:
    // log + alert
}
```

## Retry guidance at a glance

| Code                 | Retry safe? | Notes                                                    |
| -------------------- | ----------- | -------------------------------------------------------- |
| 100                  | n/a         | Success. No retry needed.                                |
| 101                  | No          | Fix the key and retry once.                              |
| 102 to 105, 109, 111 | No          | Input is bad; retrying won't change anything.            |
| 106                  | Yes         | Transient server error. Exponential backoff.             |
| 107, 112, 113        | No          | Plan-gated. Upgrade the plan or skip the call.           |
| 108                  | Yes         | Back off until `X-RateLimit-Remaining` resets.           |
| 110                  | No          | Try a different query (broader address, different date). |

## Related

#### [Rate Limiting & Errors](rate-limiting-errors)

Deeper dive on 429/108 behavior, headers, and backoff.

#### [Taxability Information Codes](../product-rules/taxability-information-codes)

What `taxabilityCode` does and why code 113 shows up.

#### [REST API](../rest-api/overview)

How the endpoints that return these codes are called.