> ## Documentation Index
> Fetch the complete documentation index at: https://docs.numeral.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Error Codes

> Complete list of error codes and their meanings for API version 2026-03-01

# Error Codes

Starting with API version `2026-01-01`, error responses use a simplified, consistent format. Version `2026-03-01` adds IP resolution error types.

## Error Response Format

All errors return a JSON object with three fields:

```json theme={null}
{
  "code": 400,
  "type": "ZIP_STATE_MISMATCH",
  "message": "Unable to create calculation. address_zip_code 92037 not found in the address_province TN. Ensure zip is up to date and formed correctly."
}
```

| Field     | Type    | Description                                                      |
| --------- | ------- | ---------------------------------------------------------------- |
| `code`    | integer | HTTP status code                                                 |
| `type`    | string  | Machine-readable error type (use this for programmatic handling) |
| `message` | string  | Human-readable description of the error                          |

<Note>
  Previous API versions used a nested `error` object. The 2026-01-01+ format is flattened for easier parsing.
</Note>

***

## Error Types Reference

### Validation Errors

These errors occur when request data is invalid or malformed.

| Type                       | Description                                  |
| -------------------------- | -------------------------------------------- |
| `ERROR`                    | Generic error                                |
| `MISSING_FIELD`            | A required field was not provided            |
| `INCORRECT_TYPE`           | A field has the wrong data type              |
| `UNRECOGNIZED_FIELD`       | An unknown field was included in the request |
| `NEGATIVE_NUMBER_REQUIRED` | Field requires a negative number             |
| `POSITIVE_NUMBER_REQUIRED` | Field requires a positive number             |
| `INVALID_EMAIL`            | Email address format is invalid              |

### Address Errors

These errors relate to address validation issues.

| Type                     | Description                                                                  |
| ------------------------ | ---------------------------------------------------------------------------- |
| `MALFORMED_ADDRESS`      | Address format is invalid or incomplete                                      |
| `ZIP_STATE_MISMATCH`     | ZIP/postal code does not match the provided state/province                   |
| `MISSING_ORIGIN_ADDRESS` | Origin address is required but not provided (check merchant default address) |
| `INVALID_COUNTRY_CODE`   | Country code is not recognized (use ISO 3166-1 alpha-2)                      |

### IP Resolution Errors

These errors relate to IP-based tax resolution (new in 2026-03-01).

| Type                            | HTTP Code | Description                                                                                                                                  |
| ------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `INVALID_IP_FORMAT`             | 400       | `ip.value` must be a valid IPv4 or IPv6 address                                                                                              |
| `IP_RESOLUTION_FAILED`          | 422       | Unable to resolve IP address to a country. Provide a full address in `customer.address`.                                                     |
| `IP_RESOLUTION_INSUFFICIENT_US` | 422       | IP resolved to a US state but could not determine a postal code. Provide `address_postal_code` and `address_province` in `customer.address`. |
| `IP_RESOLUTION_INSUFFICIENT_CA` | 422       | IP resolved to CA but could not determine a province. Provide `address_province` in `customer.address`.                                      |

<Note>
  IP resolution errors only occur when using `customer.ip` with `resolution: "strict"` (the default). Use `"best_effort"` or `"zero"` to avoid these errors and receive zero-rate responses instead.
</Note>

### Product Errors

These errors relate to product operations.

| Type                       | Description                                     |
| -------------------------- | ----------------------------------------------- |
| `PRODUCT_NOT_FOUND`        | The specified product ID does not exist         |
| `DUPLICATE_PRODUCT`        | A product with this reference ID already exists |
| `INVALID_TAX_CODE`         | The product tax code is not valid               |
| `INVALID_PRODUCT_CATEGORY` | The product category is not recognized          |

### Customer Errors

These errors relate to customer operations.

| Type                 | Description                                                         |
| -------------------- | ------------------------------------------------------------------- |
| `CUSTOMER_NOT_FOUND` | The specified customer ID does not exist                            |
| `DUPLICATE_CUSTOMER` | A customer with this reference ID already exists (returns HTTP 400) |

### Merchant Errors

These errors relate to merchant operations (new in 2026-01-01).

| Type                       | Description                                      |
| -------------------------- | ------------------------------------------------ |
| `MERCHANT_NOT_FOUND`       | The specified merchant ID does not exist         |
| `DUPLICATE_MERCHANT`       | A merchant with this reference ID already exists |
| `MERCHANT_CREATION_FAILED` | Failed to create the merchant                    |
| `MERCHANT_UPDATE_FAILED`   | Failed to update the merchant                    |

### Calculation Errors

These errors relate to tax calculation operations.

| Type                    | Description                                                                         |
| ----------------------- | ----------------------------------------------------------------------------------- |
| `CALCULATION_NOT_FOUND` | The specified calculation ID does not exist                                         |
| `CALCULATION_EXPIRED`   | The calculation has expired and can no longer be used                               |
| `INVALID_CURRENCY_CODE` | Currency code is not supported (see [supported currencies](/essentials/currencies)) |

### Transaction Errors

These errors relate to transaction operations.

| Type                                | Description                                               |
| ----------------------------------- | --------------------------------------------------------- |
| `TRANSACTION_NOT_FOUND`             | The specified transaction ID does not exist               |
| `TRANSACTION_ALREADY_EXISTS`        | A transaction with this calculation ID already exists     |
| `REFERENCE_ORDER_ID_ALREADY_EXISTS` | A transaction with this reference order ID already exists |

### Certificate Errors

These errors relate to exemption certificate operations.

| Type                    | Description                                                                     |
| ----------------------- | ------------------------------------------------------------------------------- |
| `CERTIFICATE_NOT_FOUND` | The specified certificate ID does not exist (or belongs to a different account) |

### Certificate Request Errors

These errors relate to certificate-request operations.

| Type                            | HTTP Code | Description                                                                                                                                |
| ------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `CERTIFICATE_REQUEST_NOT_FOUND` | 404       | The specified certificate request ID does not exist (or belongs to a different account)                                                    |
| `REQUEST_ALREADY_FULFILLED`     | 409       | Cannot cancel a request that has already been fulfilled. Fetch the resulting certificate via `/tax/certificates/{certificate_id}` instead. |
| `REQUEST_INVALID`               | 409       | The certificate request is in a terminal `invalid` state and cannot be canceled.                                                           |

***

## HTTP Status Codes

| Code  | Meaning                                                                                                                            |
| ----- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `400` | Bad Request - Invalid parameters, validation error, or resource already exists (duplicates)                                        |
| `401` | Unauthorized - Invalid or missing API key                                                                                          |
| `404` | Not Found - Resource does not exist                                                                                                |
| `409` | Conflict - the resource is in a state that cannot accept this operation (e.g., canceling an already-fulfilled certificate request) |
| `422` | Unprocessable Entity - Request understood but cannot be processed (includes IP resolution errors)                                  |
| `429` | Too Many Requests - Rate limit exceeded                                                                                            |
| `500` | Internal Server Error - Something went wrong on our end                                                                            |

***

## Handling Errors

### Example Error Handling

```javascript theme={null}
try {
  const response = await fetch('https://api.numeralhq.com/tax/calculations', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer sk_test_xxx',
      'X-API-Version': '2026-03-01',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(calculationData)
  });

  if (!response.ok) {
    const error = await response.json();

    switch (error.type) {
      case 'ZIP_STATE_MISMATCH':
        // Prompt user to verify their address
        break;
      case 'PRODUCT_NOT_FOUND':
        // Create the product first
        break;
      case 'CALCULATION_EXPIRED':
        // Request a new calculation
        break;
      case 'IP_RESOLUTION_FAILED':
        // Fall back to asking for a full address
        break;
      case 'IP_RESOLUTION_INSUFFICIENT_US':
        // Ask for ZIP code and state
        break;
      case 'IP_RESOLUTION_INSUFFICIENT_CA':
        // Ask for province
        break;
      case 'INVALID_IP_FORMAT':
        // Check IP address format
        break;
      case 'CERTIFICATE_NOT_FOUND':
      case 'CERTIFICATE_REQUEST_NOT_FOUND':
        // Resource doesn't exist or belongs to another account
        break;
      case 'REQUEST_ALREADY_FULFILLED':
        // Fetch the resulting certificate instead of canceling
        break;
      case 'REQUEST_INVALID':
        // The request is in a terminal invalid state — start over
        break;
      default:
        console.error(`Error: ${error.message}`);
    }
  }
} catch (err) {
  // Handle network errors
}
```

### Best Practices

1. **Always check the `type` field** for programmatic error handling
2. **Display the `message` field** to users when appropriate
3. **Log the full error response** for debugging
4. **Handle specific error types** rather than just checking status codes
5. **Use `resolution: "best_effort"`** if you want to avoid IP resolution errors and prefer zero-rate fallbacks
