Batches
Classify a file of products - upload an .xlsx or .csv file, choose the columns, start it, follow its progress and download the results.
A batch classifies every row of a spreadsheet. The flow has five steps:
- Upload the file (
POST /api/batches). The answer lists the columns found, a suggested mapping and a preview. Nothing is classified yet. - Optionally check the rows with your column mapping (
POST /api/batches/{batch_id}/validate). - Start it (
POST /api/batches/{batch_id}/start) with the column mapping. The start can answer402when the account cannot be charged for the rows. - Poll
GET /api/batches/{batch_id}/progressuntil the status iscompletedorcompleted_with_errors, or wait for thebatch.completedwebhook (Asynchronous work). - Read the rows (
GET /api/batches/{batch_id}/rows) or download the results as Excel (GET /api/batches/{batch_id}/export).
Each row that is classified becomes a lookup of the kind batch (Lookups) and can be charged (Rate limits and quotas). Rows
send no lookup.completed event: the batch sends batch.completed when it is done. Batches need the plan
feature feature.batch, and the number of rows is limited by the plan
(Rate limits and quotas).
An .xlsx or .csv file whose first row holds the column names. GET /api/batches/template gives a file to
start from, with the columns description, material, use, composition, origin, notes, sku and
hts_code. Your own column names work too: the column mapping says which column holds which field. Only
description is required.
| Mapping field | Column that holds |
|---|---|
description |
The product description. Required |
material, use, composition, origin, notes |
The same fields as on a lookup |
sku |
Your SKU code. Needed for save_to_catalog |
existing_code |
The code in use today. It is checked against the tariff schedule and compared with the suggestion |
| Field | Type | Meaning |
|---|---|---|
id |
string | The id of the batch |
created_at, updated_at |
string | ISO 8601, UTC |
filename |
string | The name of the uploaded file |
status |
string | uploaded, queued, running, completed, completed_with_errors or error |
columns |
array | The column names found in the file |
column_mapping |
object | The mapping the batch was started with |
market, dataset_version |
string | The market and tariff version of the batch |
validation |
object | The suggested mapping and the result of the row check |
total_rows, processed_rows, failed_rows |
integer | Counters |
counts |
object | Rows per row status |
error |
string or null | The message of a batch that failed as a whole |
save_to_catalog |
boolean | Whether rows are saved to the SKU catalog |
preview |
array | The first rows of the file: after an upload, and on GET /api/batches/{batch_id} with preview=true |
| Field | Type | Meaning |
|---|---|---|
row_index |
integer | The row number in the file. The first data row is 2 |
raw |
object | The cells of the row, by column name |
status |
string | pending, processing, done, error, skipped or duplicate (the same product as an earlier row, named in duplicate_of, whose result it reuses) |
issues |
array | What the row check found |
duplicate_of |
integer or null | The row_index it duplicates |
lookup_id |
string or null | The lookup of the row |
attempts |
integer | How often it was tried |
error |
string or null | Why it failed |
result_status, recommended_code, confidence |
- | The outcome of the lookup |
code_check |
object | The check of the existing code, when a column was mapped to existing_code |
final_code |
string or null | The reviewer's code, once decided |
GET /api/batches/template
An .xlsx file with the columns description, material, use, composition, origin, notes, sku and hts_code, example rows and a guide sheet.
Returns 200 with a file (application/vnd.openxmlformats-officedocument.spreadsheetml.sheet).
Errors: 401 No valid API key was sent; 403 The role of the key, or the plan of the account, does not allow this call; 422 The request is not valid; 500 An unexpected failure.
curl "https://htspilot.com/api/batches/template" \
-H "X-API-Key: hts_EXAMPLE_KEY_REPLACE_ME" \
-o "hts_lookup_template.xlsx"import json
import os
import urllib.request
request = urllib.request.Request(
"https://htspilot.com/api/batches/template",
headers={"X-API-Key": os.environ["HTS_PILOT_API_KEY"]},
method="GET",
)
with urllib.request.urlopen(request) as response, open("hts_lookup_template.xlsx", "wb") as out:
out.write(response.read())import { writeFile } from "node:fs/promises";
const response = await fetch("https://htspilot.com/api/batches/template", {
headers: { "X-API-Key": process.env.HTS_PILOT_API_KEY },
});
await writeFile("hts_lookup_template.xlsx", Buffer.from(await response.arrayBuffer()));200{
"file": true,
"content_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"content_disposition": "attachment; filename=\"hts_lookup_template.xlsx\"",
"bytes": 11735
}
POST /api/batches
Changes data in your account when executed. Send the file as multipart/form-data in the field file. The first row holds the column names; GET /api/batches/template gives a file to start from. The answer lists the columns found, a suggested mapping and a preview; nothing is classified until the batch is started.
Request body (multipart/form-data)
| Name | Type | Required | Description |
|---|---|---|---|
file |
file | Yes | - |
Returns 200 with BatchOut.
Errors: 401 No valid API key was sent; 403 The role of the key, or the plan of the account, does not allow this call; 422 The request is not valid; 500 An unexpected failure.
curl -X POST https://htspilot.com/api/batches \
-H "X-API-Key: hts_EXAMPLE_KEY_REPLACE_ME" \
-F "file=@products.csv"
curl -X POST "https://htspilot.com/api/batches" \
-H "X-API-Key: hts_EXAMPLE_KEY_REPLACE_ME" \
-F "file=@products.csv"import json
import os
import urllib.request
boundary = "hts-pilot-example"
data = b""
for field, name in [["file", "products.csv"]]:
with open(name, "rb") as f:
data += (f"--{boundary}\r\nContent-Disposition: form-data; name=\"{field}\"; filename=\"{name}\"\r\n"
"Content-Type: application/octet-stream\r\n\r\n").encode() + f.read() + b"\r\n"
data += f"--{boundary}--\r\n".encode()
request = urllib.request.Request(
"https://htspilot.com/api/batches",
data=data,
headers={"X-API-Key": os.environ["HTS_PILOT_API_KEY"], "Content-Type": f"multipart/form-data; boundary={boundary}"},
method="POST",
)
with urllib.request.urlopen(request) as response:
print(json.load(response))import { readFile } from "node:fs/promises";
const form = new FormData();
form.append("file", new Blob([await readFile("products.csv")]), "products.csv");
const response = await fetch("https://htspilot.com/api/batches", {
method: "POST",
headers: { "X-API-Key": process.env.HTS_PILOT_API_KEY },
body: form,
});
console.log(await response.json());200{
"id": "9058ee5650844af9b9d6f473bdf3c544",
"created_at": "2026-10-03T16:07:51.820019Z",
"updated_at": "2026-10-03T16:07:51.820019Z",
"filename": "products.csv",
"status": "uploaded",
"columns": [
"description",
"material"
],
"column_mapping": {
"description": "description",
"material": "material",
"origin": "origin",
"sku": "sku",
"existing_code": "hts_code"
},
"market": "",
"dataset_version": null,
"validation": {
"suggested_mapping": {
"description": "description",
"material": "material",
"origin": "origin",
"sku": "sku",
"existing_code": "hts_code"
},
"precheck": {
"total": 3,
"empty": 0,
"examples": 0,
"invalid": 0,
"duplicates": 0,
"valid": 3,
"warnings": 0,
"issues": []
}
},
"total_rows": 3,
"processed_rows": 0,
"failed_rows": 0,
"error": null,
"save_to_catalog": false,
"counts": {
"pending": 3
},
"preview": [
{
"row_index": 2,
"description": "Men's T-shirt, knitted, 100% cotton, short sleeves",
"material": "cotton",
"origin": "VN",
"sku": "EXAMPLE-TSH-001",
"hts_code": "6109.10.00.12"
},
{
"row_index": 3,
"description": "Cotton terry bath towel, 70 x 140 cm",
"material": "cotton",
"origin": "IN",
"sku": "EXAMPLE-TWL-014",
"hts_code": ""
}
]
}
POST /api/batches/{batch_id}/validate
Changes data in your account when executed.
Path parameters
| Name | Type | Description |
|---|---|---|
batch_id |
string | - |
Request body (application/json)
| Name | Type | Required | Description |
|---|---|---|---|
column_mapping |
ColumnMapping | Yes | - |
market |
string | No | Up to 8 characters |
tariff_version |
string or null | No | - |
save_to_catalog |
boolean | No | Save/update the SKU in the shared catalog (requires a sku column). Default false |
column_mapping: ColumnMapping
| Name | Type | Required | Description |
|---|---|---|---|
description |
string | Yes | - |
material |
string or null | No | - |
use |
string or null | No | - |
composition |
string or null | No | - |
origin |
string or null | No | - |
notes |
string or null | No | - |
sku |
string or null | No | - |
existing_code |
string or null | No | Column with the HTS code currently in use: it is checked for validity and compared with the suggestion |
Returns 200 with BatchOut.
Errors: 401 No valid API key was sent; 403 The role of the key, or the plan of the account, does not allow this call; 422 The request is not valid; 500 An unexpected failure.
curl -X POST "https://htspilot.com/api/batches/9058ee5650844af9b9d6f473bdf3c544/validate" \
-H "X-API-Key: hts_EXAMPLE_KEY_REPLACE_ME" \
-H "Content-Type: application/json" \
-d '{
"column_mapping": {
"description": "description",
"material": "material",
"origin": "origin",
"sku": "sku",
"existing_code": "hts_code"
},
"market": "US",
"save_to_catalog": false
}'import json
import os
import urllib.request
request = urllib.request.Request(
"https://htspilot.com/api/batches/9058ee5650844af9b9d6f473bdf3c544/validate",
data=json.dumps({
"column_mapping": {
"description": "description",
"material": "material",
"origin": "origin",
"sku": "sku",
"existing_code": "hts_code",
},
"market": "US",
"save_to_catalog": False,
}).encode(),
headers={"X-API-Key": os.environ["HTS_PILOT_API_KEY"], "Content-Type": "application/json"},
method="POST",
)
with urllib.request.urlopen(request) as response:
print(json.load(response))const response = await fetch("https://htspilot.com/api/batches/9058ee5650844af9b9d6f473bdf3c544/validate", {
method: "POST",
headers: { "X-API-Key": process.env.HTS_PILOT_API_KEY, "Content-Type": "application/json" },
body: JSON.stringify({
"column_mapping": {
"description": "description",
"material": "material",
"origin": "origin",
"sku": "sku",
"existing_code": "hts_code"
},
"market": "US",
"save_to_catalog": false
}),
});
console.log(await response.json());200{
"id": "9058ee5650844af9b9d6f473bdf3c544",
"created_at": "2026-10-03T16:07:51.820019",
"updated_at": "2026-10-03T16:07:51.820019",
"filename": "products.csv",
"status": "uploaded",
"columns": [
"description",
"material"
],
"column_mapping": {
"description": "description",
"material": "material",
"origin": "origin",
"sku": "sku",
"existing_code": "hts_code"
},
"market": "",
"dataset_version": null,
"validation": {
"suggested_mapping": {
"description": "description",
"material": "material",
"origin": "origin",
"sku": "sku",
"existing_code": "hts_code"
},
"precheck": {
"total": 3,
"empty": 0,
"examples": 0,
"invalid": 0,
"duplicates": 0,
"valid": 3,
"warnings": 0,
"issues": []
}
},
"total_rows": 3,
"processed_rows": 0,
"failed_rows": 0,
"error": null,
"save_to_catalog": false,
"counts": {
"pending": 3
},
"preview": [
{
"row_index": 2,
"description": "Men's T-shirt, knitted, 100% cotton, short sleeves",
"material": "cotton",
"origin": "VN",
"sku": "EXAMPLE-TSH-001",
"hts_code": "6109.10.00.12"
},
{
"row_index": 3,
"description": "Cotton terry bath towel, 70 x 140 cm",
"material": "cotton",
"origin": "IN",
"sku": "EXAMPLE-TWL-014",
"hts_code": ""
}
]
}
POST /api/batches/{batch_id}/start
Changes data in your account when executed. column_mapping names the column of the file for each field; only description is required. Spends credits for every row that is classified.
Path parameters
| Name | Type | Description |
|---|---|---|
batch_id |
string | - |
Request body (application/json)
| Name | Type | Required | Description |
|---|---|---|---|
column_mapping |
ColumnMapping | Yes | - |
market |
string | No | Up to 8 characters |
tariff_version |
string or null | No | - |
save_to_catalog |
boolean | No | Save/update the SKU in the shared catalog (requires a sku column). Default false |
column_mapping: ColumnMapping
| Name | Type | Required | Description |
|---|---|---|---|
description |
string | Yes | - |
material |
string or null | No | - |
use |
string or null | No | - |
composition |
string or null | No | - |
origin |
string or null | No | - |
notes |
string or null | No | - |
sku |
string or null | No | - |
existing_code |
string or null | No | Column with the HTS code currently in use: it is checked for validity and compared with the suggestion |
Returns 200 with BatchOut.
Errors: 401 No valid API key was sent; 403 The role of the key, or the plan of the account, does not allow this call; 422 The request is not valid; 500 An unexpected failure.
A batch can be started once, from the status uploaded; a second start answers 409.
curl -X POST "https://htspilot.com/api/batches/9058ee5650844af9b9d6f473bdf3c544/start" \
-H "X-API-Key: hts_EXAMPLE_KEY_REPLACE_ME" \
-H "Content-Type: application/json" \
-d '{
"column_mapping": {
"description": "description",
"material": "material",
"origin": "origin",
"sku": "sku",
"existing_code": "hts_code"
},
"market": "US",
"save_to_catalog": false
}'import json
import os
import urllib.request
request = urllib.request.Request(
"https://htspilot.com/api/batches/9058ee5650844af9b9d6f473bdf3c544/start",
data=json.dumps({
"column_mapping": {
"description": "description",
"material": "material",
"origin": "origin",
"sku": "sku",
"existing_code": "hts_code",
},
"market": "US",
"save_to_catalog": False,
}).encode(),
headers={"X-API-Key": os.environ["HTS_PILOT_API_KEY"], "Content-Type": "application/json"},
method="POST",
)
with urllib.request.urlopen(request) as response:
print(json.load(response))const response = await fetch("https://htspilot.com/api/batches/9058ee5650844af9b9d6f473bdf3c544/start", {
method: "POST",
headers: { "X-API-Key": process.env.HTS_PILOT_API_KEY, "Content-Type": "application/json" },
body: JSON.stringify({
"column_mapping": {
"description": "description",
"material": "material",
"origin": "origin",
"sku": "sku",
"existing_code": "hts_code"
},
"market": "US",
"save_to_catalog": false
}),
});
console.log(await response.json());200{
"id": "9058ee5650844af9b9d6f473bdf3c544",
"created_at": "2026-10-03T16:07:51.820019",
"updated_at": "2026-10-03T16:07:51.835161Z",
"filename": "products.csv",
"status": "queued",
"columns": [
"description",
"material"
],
"column_mapping": {
"description": "description",
"material": "material",
"origin": "origin",
"sku": "sku",
"existing_code": "hts_code"
},
"market": "US",
"dataset_version": "2026-SAMPLE",
"validation": {
"suggested_mapping": {
"description": "description",
"material": "material",
"origin": "origin",
"sku": "sku",
"existing_code": "hts_code"
},
"precheck": {
"total": 3,
"empty": 0,
"examples": 0,
"invalid": 0,
"duplicates": 0,
"valid": 3,
"warnings": 0,
"issues": []
},
"final": {
"total": 3,
"empty": 0,
"examples": 0,
"invalid": 0,
"duplicates": 0,
"valid": 3,
"warnings": 0,
"issues": []
},
"lang": "en"
},
"total_rows": 3,
"processed_rows": 0,
"failed_rows": 0,
"error": null,
"save_to_catalog": false,
"counts": {
"pending": 3
},
"preview": []
}
GET /api/batches/{batch_id}/progress
The status, the counters and version, a token that changes whenever the batch or its rows changed. Poll this and read the rows again only when version differs from the one last seen. The token is opaque: compare it, do not parse it.
Path parameters
| Name | Type | Description |
|---|---|---|
batch_id |
string | - |
Returns 200 with BatchProgressOut.
Errors: 401 No valid API key was sent; 403 The role of the key, or the plan of the account, does not allow this call; 422 The request is not valid; 500 An unexpected failure.
curl "https://htspilot.com/api/batches/9058ee5650844af9b9d6f473bdf3c544/progress" \
-H "X-API-Key: hts_EXAMPLE_KEY_REPLACE_ME"import json
import os
import urllib.request
request = urllib.request.Request(
"https://htspilot.com/api/batches/9058ee5650844af9b9d6f473bdf3c544/progress",
headers={"X-API-Key": os.environ["HTS_PILOT_API_KEY"]},
method="GET",
)
with urllib.request.urlopen(request) as response:
print(json.load(response))const response = await fetch("https://htspilot.com/api/batches/9058ee5650844af9b9d6f473bdf3c544/progress", {
headers: { "X-API-Key": process.env.HTS_PILOT_API_KEY },
});
console.log(await response.json());200{
"id": "9058ee5650844af9b9d6f473bdf3c544",
"status": "completed",
"updated_at": "2026-10-03T16:07:52.103466",
"total_rows": 3,
"processed_rows": 3,
"failed_rows": 0,
"error": null,
"counts": {
"done": 3
},
"version": "f3bb25533d548f36"
}
GET /api/batches/{batch_id}
Path parameters
| Name | Type | Description |
|---|---|---|
batch_id |
string | - |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
preview |
boolean | No | Default false |
Returns 200 with BatchOut.
Errors: 401 No valid API key was sent; 403 The role of the key, or the plan of the account, does not allow this call; 422 The request is not valid; 500 An unexpected failure.
curl "https://htspilot.com/api/batches/9058ee5650844af9b9d6f473bdf3c544" \
-H "X-API-Key: hts_EXAMPLE_KEY_REPLACE_ME"import json
import os
import urllib.request
request = urllib.request.Request(
"https://htspilot.com/api/batches/9058ee5650844af9b9d6f473bdf3c544",
headers={"X-API-Key": os.environ["HTS_PILOT_API_KEY"]},
method="GET",
)
with urllib.request.urlopen(request) as response:
print(json.load(response))const response = await fetch("https://htspilot.com/api/batches/9058ee5650844af9b9d6f473bdf3c544", {
headers: { "X-API-Key": process.env.HTS_PILOT_API_KEY },
});
console.log(await response.json());200{
"id": "9058ee5650844af9b9d6f473bdf3c544",
"created_at": "2026-10-03T16:07:51.820019",
"updated_at": "2026-10-03T16:07:51.820019",
"filename": "products.csv",
"status": "uploaded",
"columns": [
"description",
"material"
],
"column_mapping": {
"description": "description",
"material": "material",
"origin": "origin",
"sku": "sku",
"existing_code": "hts_code"
},
"market": "",
"dataset_version": null,
"validation": {
"suggested_mapping": {
"description": "description",
"material": "material",
"origin": "origin",
"sku": "sku",
"existing_code": "hts_code"
},
"precheck": {
"total": 3,
"empty": 0,
"examples": 0,
"invalid": 0,
"duplicates": 0,
"valid": 3,
"warnings": 0,
"issues": []
}
},
"total_rows": 3,
"processed_rows": 0,
"failed_rows": 0,
"error": null,
"save_to_catalog": false,
"counts": {
"pending": 3
},
"preview": []
}
GET /api/batches
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
limit |
integer | No | Minimum 1, maximum 100, default 20 |
Returns 200 with BatchOut[].
Errors: 401 No valid API key was sent; 403 The role of the key, or the plan of the account, does not allow this call; 422 The request is not valid; 500 An unexpected failure.
curl "https://htspilot.com/api/batches" \
-H "X-API-Key: hts_EXAMPLE_KEY_REPLACE_ME"import json
import os
import urllib.request
request = urllib.request.Request(
"https://htspilot.com/api/batches",
headers={"X-API-Key": os.environ["HTS_PILOT_API_KEY"]},
method="GET",
)
with urllib.request.urlopen(request) as response:
print(json.load(response))const response = await fetch("https://htspilot.com/api/batches", {
headers: { "X-API-Key": process.env.HTS_PILOT_API_KEY },
});
console.log(await response.json());200[
{
"id": "9058ee5650844af9b9d6f473bdf3c544",
"created_at": "2026-10-03T16:07:51.820019",
"updated_at": "2026-10-03T16:07:52.103466",
"filename": "products.csv",
"status": "completed",
"columns": [
"description",
"material"
],
"column_mapping": {
"description": "description",
"material": "material",
"origin": "origin",
"sku": "sku",
"existing_code": "hts_code"
},
"market": "US",
"dataset_version": "2026-SAMPLE",
"validation": {
"suggested_mapping": {
"description": "description",
"material": "material",
"origin": "origin",
"sku": "sku",
"existing_code": "hts_code"
},
"precheck": {
"total": 3,
"empty": 0,
"examples": 0,
"invalid": 0,
"duplicates": 0,
"valid": 3,
"warnings": 0,
"issues": []
},
"final": {
"total": 3,
"empty": 0,
"examples": 0,
"invalid": 0,
"duplicates": 0,
"valid": 3,
"warnings": 0,
"issues": []
},
"lang": "en"
},
"total_rows": 3,
"processed_rows": 3,
"failed_rows": 0,
"error": null,
"save_to_catalog": false,
"counts": {
"done": 3
},
"preview": []
}
]
GET /api/batches/{batch_id}/rows
Path parameters
| Name | Type | Description |
|---|---|---|
batch_id |
string | - |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
status |
string or null | No | - |
offset |
integer | No | Minimum 0, default 0 |
limit |
integer | No | Minimum 1, maximum 2000, default 200 |
Returns 200 with BatchRowOut[].
Errors: 401 No valid API key was sent; 403 The role of the key, or the plan of the account, does not allow this call; 422 The request is not valid; 500 An unexpected failure.
curl "https://htspilot.com/api/batches/9058ee5650844af9b9d6f473bdf3c544/rows" \
-H "X-API-Key: hts_EXAMPLE_KEY_REPLACE_ME"import json
import os
import urllib.request
request = urllib.request.Request(
"https://htspilot.com/api/batches/9058ee5650844af9b9d6f473bdf3c544/rows",
headers={"X-API-Key": os.environ["HTS_PILOT_API_KEY"]},
method="GET",
)
with urllib.request.urlopen(request) as response:
print(json.load(response))const response = await fetch("https://htspilot.com/api/batches/9058ee5650844af9b9d6f473bdf3c544/rows", {
headers: { "X-API-Key": process.env.HTS_PILOT_API_KEY },
});
console.log(await response.json());200[
{
"row_index": 2,
"raw": {
"description": "Men's T-shirt, knitted, 100% cotton, short sleeves",
"material": "cotton",
"origin": "VN",
"sku": "EXAMPLE-TSH-001",
"hts_code": "6109.10.00.12"
},
"status": "done",
"issues": [],
"duplicate_of": null,
"lookup_id": "e60be79fad914ec88b759a060b258de0",
"attempts": 1,
"error": null,
"result_status": "proposed",
"recommended_code": "6109.10.00.14",
"confidence": 0.75,
"code_check": {
"status": "valid",
"code": "6109.10.00.12",
"description": "Chapter 61: Articles of apparel and clothing accessories, knitted or crocheted > T-shirts, singlets, tank tops and similar garments, knitted or crocheted > Of cotton > Men's or boys' > T-shirts, all white, short hemmed sleeves, hemmed bottom, crew or round neckline, or V-neck, without pockets, trim or embroidery",
"detail": "Valid declarable code",
"comparison": "same_hs6"
},
"final_code": null
},
{
"row_index": 3,
"raw": {
"description": "Cotton terry bath towel, 70 x 140 cm",
"material": "cotton",
"origin": "IN",
"sku": "EXAMPLE-TWL-014",
"hts_code": ""
},
"status": "done",
"issues": [],
"duplicate_of": null,
"lookup_id": "f23fdb9bfa2e4c33930c1ac93418fd41",
"attempts": 1,
"error": null,
"result_status": "proposed",
"recommended_code": "6302.60.00.10",
"confidence": 0.74,
"code_check": {},
"final_code": null
}
]
PATCH /api/batches/{batch_id}/rows/{row_index}
Changes data in your account when executed. values maps column names of the file to their new text. row_index is the row number in the file (the first data row is 2).
Path parameters
| Name | Type | Description |
|---|---|---|
batch_id |
string | - |
row_index |
integer | - |
Request body (application/json)
| Name | Type | Required | Description |
|---|---|---|---|
values |
object | Yes | - |
Returns 200 with BatchOut.
Errors: 401 No valid API key was sent; 403 The role of the key, or the plan of the account, does not allow this call; 422 The request is not valid; 500 An unexpected failure.
curl -X PATCH "https://htspilot.com/api/batches/9058ee5650844af9b9d6f473bdf3c544/rows/2" \
-H "X-API-Key: hts_EXAMPLE_KEY_REPLACE_ME" \
-H "Content-Type: application/json" \
-d '{
"values": {
"description": "Men'\''s T-shirt, knitted, 100% cotton, short sleeves"
}
}'import json
import os
import urllib.request
request = urllib.request.Request(
"https://htspilot.com/api/batches/9058ee5650844af9b9d6f473bdf3c544/rows/2",
data=json.dumps({
"values": {"description": "Men's T-shirt, knitted, 100% cotton, short sleeves"},
}).encode(),
headers={"X-API-Key": os.environ["HTS_PILOT_API_KEY"], "Content-Type": "application/json"},
method="PATCH",
)
with urllib.request.urlopen(request) as response:
print(json.load(response))const response = await fetch("https://htspilot.com/api/batches/9058ee5650844af9b9d6f473bdf3c544/rows/2", {
method: "PATCH",
headers: { "X-API-Key": process.env.HTS_PILOT_API_KEY, "Content-Type": "application/json" },
body: JSON.stringify({
"values": {
"description": "Men's T-shirt, knitted, 100% cotton, short sleeves"
}
}),
});
console.log(await response.json());200{
"id": "9058ee5650844af9b9d6f473bdf3c544",
"created_at": "2026-10-03T16:07:51.820019",
"updated_at": "2026-10-03T16:07:52.058703Z",
"filename": "products.csv",
"status": "queued",
"columns": [
"description",
"material"
],
"column_mapping": {
"description": "description",
"material": "material",
"origin": "origin",
"sku": "sku",
"existing_code": "hts_code"
},
"market": "US",
"dataset_version": "2026-SAMPLE",
"validation": {
"suggested_mapping": {
"description": "description",
"material": "material",
"origin": "origin",
"sku": "sku",
"existing_code": "hts_code"
},
"precheck": {
"total": 3,
"empty": 0,
"examples": 0,
"invalid": 0,
"duplicates": 0,
"valid": 3,
"warnings": 0,
"issues": []
},
"final": {
"total": 3,
"empty": 0,
"examples": 0,
"invalid": 0,
"duplicates": 0,
"valid": 3,
"warnings": 0,
"issues": []
},
"lang": "en"
},
"total_rows": 3,
"processed_rows": 3,
"failed_rows": 0,
"error": null,
"save_to_catalog": false,
"counts": {
"done": 2,
"pending": 1
},
"preview": []
}
POST /api/batches/{batch_id}/retry
Changes data in your account when executed.
Path parameters
| Name | Type | Description |
|---|---|---|
batch_id |
string | - |
Returns 200 with BatchOut.
Errors: 401 No valid API key was sent; 403 The role of the key, or the plan of the account, does not allow this call; 422 The request is not valid; 500 An unexpected failure.
curl -X POST "https://htspilot.com/api/batches/9058ee5650844af9b9d6f473bdf3c544/retry" \
-H "X-API-Key: hts_EXAMPLE_KEY_REPLACE_ME"import json
import os
import urllib.request
request = urllib.request.Request(
"https://htspilot.com/api/batches/9058ee5650844af9b9d6f473bdf3c544/retry",
headers={"X-API-Key": os.environ["HTS_PILOT_API_KEY"]},
method="POST",
)
with urllib.request.urlopen(request) as response:
print(json.load(response))const response = await fetch("https://htspilot.com/api/batches/9058ee5650844af9b9d6f473bdf3c544/retry", {
method: "POST",
headers: { "X-API-Key": process.env.HTS_PILOT_API_KEY },
});
console.log(await response.json());200{
"id": "9058ee5650844af9b9d6f473bdf3c544",
"created_at": "2026-10-03T16:07:51.820019",
"updated_at": "2026-10-03T16:07:52.103466",
"filename": "products.csv",
"status": "completed",
"columns": [
"description",
"material"
],
"column_mapping": {
"description": "description",
"material": "material",
"origin": "origin",
"sku": "sku",
"existing_code": "hts_code"
},
"market": "US",
"dataset_version": "2026-SAMPLE",
"validation": {
"suggested_mapping": {
"description": "description",
"material": "material",
"origin": "origin",
"sku": "sku",
"existing_code": "hts_code"
},
"precheck": {
"total": 3,
"empty": 0,
"examples": 0,
"invalid": 0,
"duplicates": 0,
"valid": 3,
"warnings": 0,
"issues": []
},
"final": {
"total": 3,
"empty": 0,
"examples": 0,
"invalid": 0,
"duplicates": 0,
"valid": 3,
"warnings": 0,
"issues": []
},
"lang": "en",
"retried_rows": 0
},
"total_rows": 3,
"processed_rows": 3,
"failed_rows": 0,
"error": null,
"save_to_catalog": false,
"counts": {
"done": 3
},
"preview": []
}
GET /api/batches/{batch_id}/export
Path parameters
| Name | Type | Description |
|---|---|---|
batch_id |
string | - |
Returns 200 with a file (application/vnd.openxmlformats-officedocument.spreadsheetml.sheet).
Errors: 401 No valid API key was sent; 403 The role of the key, or the plan of the account, does not allow this call; 422 The request is not valid; 500 An unexpected failure.
The file is an Excel workbook in the language of the request (Languages).
curl "https://htspilot.com/api/batches/9058ee5650844af9b9d6f473bdf3c544/export" \
-H "X-API-Key: hts_EXAMPLE_KEY_REPLACE_ME" \
-o "products_hts_results.xlsx"import json
import os
import urllib.request
request = urllib.request.Request(
"https://htspilot.com/api/batches/9058ee5650844af9b9d6f473bdf3c544/export",
headers={"X-API-Key": os.environ["HTS_PILOT_API_KEY"]},
method="GET",
)
with urllib.request.urlopen(request) as response, open("products_hts_results.xlsx", "wb") as out:
out.write(response.read())import { writeFile } from "node:fs/promises";
const response = await fetch("https://htspilot.com/api/batches/9058ee5650844af9b9d6f473bdf3c544/export", {
headers: { "X-API-Key": process.env.HTS_PILOT_API_KEY },
});
await writeFile("products_hts_results.xlsx", Buffer.from(await response.arrayBuffer()));200{
"file": true,
"content_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"content_disposition": "attachment; filename=\"products_hts_results.xlsx\"",
"bytes": 6847
}