> This page is for version v6.0 (default).
> 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.

# Product Codes

Ziptax offers two endpoints for mapping product descriptions to Taxability Information Codes (TICs):

* **[Product Code Search](#product-code-search)** — returns a ranked list of all applicable TICs matching a natural language description, each with a relevance score.
* **[Product Code Recommendation](#product-code-recommendation)** — uses the same natural language input, plus an AI-powered model, to return the single best TIC match for your product.

> **Tip**
>
> Use **Search** when you want to present multiple options (e.g. in a merchant-facing UI). Use **Recommendation** when you want the system to pick the best TIC automatically.

---

## Product Code Search

The Product Code Search endpoint returns a ranked list of all applicable Product Codes (TICs) that match a natural language product description. Each result includes a relevance score so you can surface the best matches in your application.

### Endpoint

### Request

POST [https://api.zip-tax.com/search/tic](https://api.zip-tax.com/search/tic)

**`Ranked matches (first three results)`**

```curl Ranked matches (first three results)
curl -X POST https://api.zip-tax.com/search/tic \
     -H "X-API-KEY: <apiKey>" \
     -H "Content-Type: application/json" \
     -d '{
  "query": "baked bread in plastic packaging"
}'
```

**`Ranked matches (first three results)`**

```python Ranked matches (first three results)
import requests

url = "https://api.zip-tax.com/search/tic"

payload = { "query": "baked bread in plastic packaging" }
headers = {
    "X-API-KEY": "<apiKey>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

**`Ranked matches (first three results)`**

```javascript Ranked matches (first three results)
const url = 'https://api.zip-tax.com/search/tic';
const options = {
  method: 'POST',
  headers: {'X-API-KEY': '<apiKey>', 'Content-Type': 'application/json'},
  body: '{"query":"baked bread in plastic packaging"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

**`Ranked matches (first three results)`**

```go Ranked matches (first three results)
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.zip-tax.com/search/tic"

	payload := strings.NewReader("{\n  \"query\": \"baked bread in plastic packaging\"\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("X-API-KEY", "<apiKey>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

**`Ranked matches (first three results)`**

```ruby Ranked matches (first three results)
require 'uri'
require 'net/http'

url = URI("https://api.zip-tax.com/search/tic")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["X-API-KEY"] = '<apiKey>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"query\": \"baked bread in plastic packaging\"\n}"

response = http.request(request)
puts response.read_body
```

**`Ranked matches (first three results)`**

```java Ranked matches (first three results)
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.zip-tax.com/search/tic")
  .header("X-API-KEY", "<apiKey>")
  .header("Content-Type", "application/json")
  .body("{\n  \"query\": \"baked bread in plastic packaging\"\n}")
  .asString();
```

**`Ranked matches (first three results)`**

```php Ranked matches (first three results)
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.zip-tax.com/search/tic', [
  'body' => '{
  "query": "baked bread in plastic packaging"
}',
  'headers' => [
    'Content-Type' => 'application/json',
    'X-API-KEY' => '<apiKey>',
  ],
]);

echo $response->getBody();
```

**`Ranked matches (first three results)`**

```csharp Ranked matches (first three results)
using RestSharp;

var client = new RestClient("https://api.zip-tax.com/search/tic");
var request = new RestRequest(Method.POST);
request.AddHeader("X-API-KEY", "<apiKey>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"query\": \"baked bread in plastic packaging\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

**`Ranked matches (first three results)`**

```swift Ranked matches (first three results)
import Foundation

let headers = [
  "X-API-KEY": "<apiKey>",
  "Content-Type": "application/json"
]
let parameters = ["query": "baked bread in plastic packaging"] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.zip-tax.com/search/tic")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### Header Parameters

**`X-API-KEY`** `string` — required

Your Ziptax API key.

---

### Body Parameters

**`query`** `string` — required

A full-text product description. The API returns all applicable product codes matching this description, ranked by relevance.

---

### Example

#### cURL

```bash
curl -X POST https://api.zip-tax.com/search/tic \
  -H "X-API-KEY: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "baked bread in plastic packaging"
  }'
```

#### Python

```python
import requests

response = requests.post(
    "https://api.zip-tax.com/search/tic",
    headers={"X-API-KEY": "YOUR_API_KEY"},
    json={"query": "baked bread in plastic packaging"},
)

print(response.json())
```

#### Go

```go
package main

import (
    "bytes"
    "encoding/json"
    "net/http"
)

func main() {
    body, _ := json.Marshal(map[string]string{
        "query": "baked bread in plastic packaging",
    })

    req, _ := http.NewRequest("POST",
        "https://api.zip-tax.com/search/tic",
        bytes.NewBuffer(body))
    req.Header.Set("X-API-KEY", "YOUR_API_KEY")
    req.Header.Set("Content-Type", "application/json")

    client := &http.Client{}
    resp, _ := client.Do(req)
    defer resp.Body.Close()
}
```

#### Example Response

The following excerpt shows the first three ranked results. Results and relevance scores may vary.

```json
{
  "$schema": "https://api.zip-tax.com/schemas/ticsearch",
  "nextCursor": "eyJxdWVyeV9oYXNoIjoiYmFrZWQtYnJlYWQtaW4tcGxhc3RpYy1wYWNrYWdpbmciLCJvZmZzZXQiOjEwfQ==",
  "query": "baked bread in plastic packaging",
  "results": [
    {
      "ticId": 41030,
      "label": "Bakery Items",
      "naturalLabel": "Bakery Items",
      "description": "Bakery items sold without eating utensils provided by the seller, including bread, rolls, buns, biscuits, bagels, croissants, pastries, donuts, Danish, cakes, tortes, pies, tarts, muffins, bars, cookies, tortillas ",
      "documentation": "Bakery items sold without eating utensils provided by the seller, including bread, rolls, buns, biscuits, bagels, croissants, pastries, donuts, Danish, cakes, tortes, pies, tarts, muffins, bars, cookies, and tortillas.",
      "rank": 1,
      "score": 0.891025641025641
    },
    {
      "ticId": 0,
      "label": "General",
      "naturalLabel": "Uncategorized tangilble personal property",
      "description": "Uncategorized tangilble personal property",
      "documentation": "Any tangible personal property that does not fit within the other defined categories. This TIC defaults to taxable in all states. For uncategorized services, use TIC 00001.",
      "rank": 2,
      "score": 0.8249269005847953
    },
    {
      "ticId": 40030,
      "label": "Food and Food ingredients",
      "naturalLabel": "Food and food ingredients excluding alcoholic beverages and tobacco",
      "description": "Food and food ingredients excluding alcoholic beverages and tobacco",
      "documentation": "Food and food ingredients means substances, whether in liquid, concentrated, solid, frozen, dried, or dehydrated form, that are sold for ingestion or chewing by humans and are consumed for their taste or nutritional value. Note: Excludes alcoholic beverages and tobacco.",
      "rank": 3,
      "score": 0.7809034572733202
    }
  ]
}
```

---

## Product Code Recommendation

The Product Code Recommendation endpoint accepts the same natural language input as Product Code Search, but adds an AI-powered model that selects the single best TIC match for your product. Use this endpoint when you need the most accurate automatic recommendation for a given product description.

### Endpoint

### Request

POST [https://api.zip-tax.com/search/tic/recommend](https://api.zip-tax.com/search/tic/recommend)

**`Recommended TIC for packaged bread`**

```curl Recommended TIC for packaged bread
curl -X POST https://api.zip-tax.com/search/tic/recommend \
     -H "X-API-KEY: <apiKey>" \
     -H "Content-Type: application/json" \
     -d '{
  "query": "baked bread in plastic packaging"
}'
```

**`Recommended TIC for packaged bread`**

```python Recommended TIC for packaged bread
import requests

url = "https://api.zip-tax.com/search/tic/recommend"

payload = { "query": "baked bread in plastic packaging" }
headers = {
    "X-API-KEY": "<apiKey>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

**`Recommended TIC for packaged bread`**

```javascript Recommended TIC for packaged bread
const url = 'https://api.zip-tax.com/search/tic/recommend';
const options = {
  method: 'POST',
  headers: {'X-API-KEY': '<apiKey>', 'Content-Type': 'application/json'},
  body: '{"query":"baked bread in plastic packaging"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

**`Recommended TIC for packaged bread`**

```go Recommended TIC for packaged bread
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.zip-tax.com/search/tic/recommend"

	payload := strings.NewReader("{\n  \"query\": \"baked bread in plastic packaging\"\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("X-API-KEY", "<apiKey>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

**`Recommended TIC for packaged bread`**

```ruby Recommended TIC for packaged bread
require 'uri'
require 'net/http'

url = URI("https://api.zip-tax.com/search/tic/recommend")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["X-API-KEY"] = '<apiKey>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"query\": \"baked bread in plastic packaging\"\n}"

response = http.request(request)
puts response.read_body
```

**`Recommended TIC for packaged bread`**

```java Recommended TIC for packaged bread
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.zip-tax.com/search/tic/recommend")
  .header("X-API-KEY", "<apiKey>")
  .header("Content-Type", "application/json")
  .body("{\n  \"query\": \"baked bread in plastic packaging\"\n}")
  .asString();
```

**`Recommended TIC for packaged bread`**

```php Recommended TIC for packaged bread
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.zip-tax.com/search/tic/recommend', [
  'body' => '{
  "query": "baked bread in plastic packaging"
}',
  'headers' => [
    'Content-Type' => 'application/json',
    'X-API-KEY' => '<apiKey>',
  ],
]);

echo $response->getBody();
```

**`Recommended TIC for packaged bread`**

```csharp Recommended TIC for packaged bread
using RestSharp;

var client = new RestClient("https://api.zip-tax.com/search/tic/recommend");
var request = new RestRequest(Method.POST);
request.AddHeader("X-API-KEY", "<apiKey>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"query\": \"baked bread in plastic packaging\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

**`Recommended TIC for packaged bread`**

```swift Recommended TIC for packaged bread
import Foundation

let headers = [
  "X-API-KEY": "<apiKey>",
  "Content-Type": "application/json"
]
let parameters = ["query": "baked bread in plastic packaging"] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.zip-tax.com/search/tic/recommend")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### Header Parameters

**`X-API-KEY`** `string` — required

Your Ziptax API key.

---

### Body Parameters

**`query`** `string` — required

A full-text product description. The model returns the best matching TIC for this description.

---

### Example

#### cURL

```bash
curl -X POST https://api.zip-tax.com/search/tic/recommend \
  -H "X-API-KEY: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "baked bread in plastic packaging"
  }'
```

#### Python

```python
import requests

response = requests.post(
    "https://api.zip-tax.com/search/tic/recommend",
    headers={"X-API-KEY": "YOUR_API_KEY"},
    json={"query": "baked bread in plastic packaging"},
)

print(response.json())
```

#### Go

```go
package main

import (
    "bytes"
    "encoding/json"
    "net/http"
)

func main() {
    body, _ := json.Marshal(map[string]string{
        "query": "baked bread in plastic packaging",
    })

    req, _ := http.NewRequest("POST",
        "https://api.zip-tax.com/search/tic/recommend",
        bytes.NewBuffer(body))
    req.Header.Set("X-API-KEY", "YOUR_API_KEY")
    req.Header.Set("Content-Type", "application/json")

    client := &http.Client{}
    resp, _ := client.Do(req)
    defer resp.Body.Close()
}
```

#### Example Response

```json
{
    "predictions": [
        {
            "status": "success",
            "error": null,
            "ticId": "41030",
            "label": "Bakery Items",
            "naturalLabel": "Bakery Items",
            "tic_description": "Bakery items sold without eating utensils provided by the seller, including bread, rolls, buns, biscuits, bagels, croissants, pastries, donuts, Danish, cakes, tortes, pies, tarts, muffins, bars, cookies, tortillas ",
            "product_description": "baked bread in plastic packaging"
        }
    ]
}
```