API 계약 읽기
아래 계약은 요청 패턴, 응답 구조, 오류 시맨틱, 속도 제한을 다룹니다. 20분의 독서가 며칠의 디버깅을 아껴 줍니다.
API 레퍼런스
HTS 품목분류와 관세 계산을 시스템에 직접 통합하세요. 제품 설명과 원산지를 전송하면, 단 한 번의 REST 호출로 HTS 코드와 완전한 관세 스택 내역을 받습니다.
성능
수백 개 SKU? 수천 개? Ginger가 모두 몇 분 안에 분류합니다.
한 번의 API 호출로 단일 제품을 분류합니다.
응답 시간은 프로덕션 트래픽 전반에서 측정되었습니다. 낮은 백분위수는 일반적인 경험을, 높은 백분위수는 최악의 경우 꼬리를 나타냅니다.
평균
36s
모든 프로덕션 요청에 걸친 평균 응답 시간.
중앙값 (p50)
30s
전체 요청의 절반이 이 시간 안에 완료됩니다.
p95
79s
요청의 95%가 이 시간 안에 완료되며, 일반적인 최악의 경우입니다.
p99
108s
부하가 걸려도 요청의 99%가 이 시간 안에 완료됩니다.
한 번의 API 호출로 최대 200개 제품을 분류합니다.
대규모 카탈로그를 위해 설계되었습니다. 한 번의 요청이 전체 배치를 병렬로 처리하여 몇 분 안에 완료합니다.
호출당 항목 수
200
일괄 API 호출당 최대 제품 수.
완료 시간
3-5분
전체 배치를 처음부터 끝까지 처리하는 일반적인 시간.
일일 처리 용량
200K+
프로덕션 등급 일일 분류 처리량. 맞춤형 엔터프라이즈 등급은 시간당 10만 건까지 확장됩니다.
손목시계와 같은 91류 제품은 단일 단위가 아니라 구성 요소별로 관세가 부과됩니다. API는 이를 자동으로 구성 부분으로 분할하고, 각 부분이 고유한 HTS 코드와 관세 계산을 갖는 components 배열을 반환합니다. 대부분의 분류 API는 이를 그냥 건너뛰지만, 진정한 무역 컴플라이언스란 모든 제품이 예외 없이 올바른 관세 처리를 받는 것을 의미합니다.
GingerControl OpenAPI는 자동화된 HTS 품목분류와 관세 계산을 위한 REST 인터페이스입니다. 제품 설명과 원산지를 전송하면, 한 번의 호출로 HTS 코드와 완전한 관세 내역을 반환합니다.
분류 결과는 귀사 팀을 위한 리서치 산출물입니다. 1,000개 이상의 제품에 걸친 내부 벤치마크에서 이 엔진은 99.86% 정확도에 도달했으며, 모든 결과는 신고 전에 관세사의 검토를 받도록 설계되었습니다.
단일 제품 엔드포인트
요청당 제품 하나, 전체 관세 상세와 함께.
일괄 엔드포인트
요청당 최대 200개 제품.
분할 코드 지원
분할 코드 제품에 대한 구성 요소별 관세.
전체 관세 스택
General(MFN) 및 Special 세율, Section 301, 232, 122, 그리고 적용되는 모든 99류 항목.
아래 계약은 요청 패턴, 응답 구조, 오류 시맨틱, 속도 제한을 다룹니다. 20분의 독서가 며칠의 디버깅을 아껴 줍니다.
문의해 주시면 이메일과 같은 오프라인 채널을 통해 테스트 키를 전달해 드립니다.
주의
테스트 키는 소량의 할당량을 가지며 7~30일 후에 만료됩니다. 개발과 디버깅 전용이며, 프로덕션에는 절대 사용하지 마세요.
대부분의 팀은 기본 통합을 빠르게 완료한 다음, 남은 시간을 반환된 데이터를 자체 시스템에 연결하는 데 씁니다.
실서비스에 나갈 준비가 되면 프로덕션 키를 요청하세요. 귀사의 호출 패턴, IP 허용 목록, 최대 QPS에 맞춰 크기를 조정해 드립니다.
주의
프로덕션 API 키를 안전하게 보관하세요. 현재 단계에서 API 키는 과금의 유일한 근거입니다.
Method: POST
Path: /openapi/v1/tariff
Base URL: https://api.gingercontrol.com
| Header | Required | Description |
|---|---|---|
Content-Type | Yes | Must be application/json |
X-Api-Key | Yes | Caller credential issued offline by GingerControl. Used for authentication, rate limiting, and quota control. |
X-Request-Id | No | Request trace identifier for troubleshooting and log tracing. Server generates one if omitted. |
| Header | Description | Purpose |
|---|---|---|
Content-Type | Always application/json | Indicates the response body format |
X-Request-Id | Echoes the caller-provided value, or a server-generated value | Recommended for logging and troubleshooting |
Retry-After | Returned only with 429 Too Many Requests | Tells the caller how many seconds to wait before retrying |
| Field | Type | Required | Description |
|---|---|---|---|
description | string | Yes | Product description. Must not be empty; max 10,000 characters. |
country_of_origin | string | Yes | ISO 3166-1 alpha-2 country code. EU (European Union) and UK (United Kingdom) are also accepted; GB is accepted and processed as UK. |
extra | object | No | Additional input. The current version only consumes steel_pour_country and aluminum_pour_country; all other fields are ignored. |
extra.steel_pour_country | string | No | Steel pour country. Same rules as country_of_origin. |
extra.aluminum_pour_country | string | No | Aluminum pour country. Same rules as country_of_origin. |
Request Example
{
"description": "Cotton knit short sleeve T-shirt",
"country_of_origin": "DE",
"extra": {
"steel_pour_country": "IT",
"aluminum_pour_country": "FR"
}
}Response Example
{
"hts_code": "6109.10.0012",
"tariffs": {
"general_rate": "16.5%",
"special_rate": "Free",
"Section 301": [],
"Section 232 - Metals": [],
"Section 122": [
{
"code": "9903.03.01",
"rate": "10%"
}
]
}
}| Field | Type | Meaning | Notes |
|---|---|---|---|
hts_code | string | The HTS code determined for the product | Normally a 10-digit code; a split-code product may return an 8-digit parent code such as 9101.11.40 |
tariffs | object | null | The set of tariff-related data for the product | May be null for split-code products |
tariffs.general_rate | string | null | General rate | This may also be understood as MFN |
tariffs.special_rate | string | null | Special rate | The raw text is lightly normalized, for example by removing a trailing parenthetical note |
tariffs.<module_key> | array | List of Chapter 99 entries for the module | Each element is {code, rate} |
tariffs.<module_key>[].code | string | Chapter 99 code | For example, 9903.85.08 |
tariffs.<module_key>[].rate | string | Rate | Percentage string such as 25% |
components | array | Component list for a split-code product | Omitted for ordinary products |
components[].hts_code | string | Component HTS code | Always 10 digits |
components[].tariffs | object | null | Tariff data for the component |
| Field | Type | Meaning | Notes |
|---|---|---|---|
detail | object | Error object | |
detail.code | string | Error code | Intended for programmatic handling |
detail.message | string | Error message | Intended for logging and troubleshooting |
Error Response Example
{
"detail": {
"code": "invalid_request",
"message": "Invalid request body."
}
}| HTTP Status | Code | Description |
|---|---|---|
401 | missing_api_key | X-Api-Key was not provided |
401 | invalid_api_key | API key validation failed |
403 | api_key_revoked | The API key has been revoked |
403 | client_disabled | The caller account has been disabled |
422 | invalid_request | Request body is malformed or fields do not satisfy the contract |
429 | request_rate_limited | Request-level protection was triggered |
429 | item_rate_limited | Item-level quota protection was triggered |
500 | classification_failed | HTS identification failed |
500 | calculator_failed | Tariff calculation failed |
500 | internal_error | An unclassified internal error occurred |
Replace YOUR_API_KEY with the key issued to you, then run:
curl -X POST 'https://api.gingercontrol.com/openapi/v1/tariff' \
-H 'Content-Type: application/json' \
-H 'X-Api-Key: YOUR_API_KEY' \
-H 'X-Request-Id: manual-single-001' \
-d '{
"description": "Cotton knit short sleeve T-shirt",
"country_of_origin": "DE",
"extra": {
"steel_pour_country": "IT",
"aluminum_pour_country": "FR"
}
}'Method: POST
Path: /openapi/v1/tariff/batch
Base URL: https://api.gingercontrol.com
Request and response headers are identical to the Single-Product Endpoint: Content-Type, X-Api-Key, and optional X-Request-Id on the request; X-Request-Id and Retry-After (on 429) on the response.
| Field | Type | Required | Description |
|---|---|---|---|
items | array | Yes | List of products. Up to 200 items per request. |
items[].item_id | string | Yes | Caller-defined unique identifier for result reconciliation. Must be unique within the request. |
items[].description | string | Yes | Product description. Must not be empty; max 10,000 characters. |
items[].country_of_origin | string | Yes | Same rules as the single-product country_of_origin. |
items[].extra | object | No | Same rules as the single-product extra object. |
Request Example
{
"items": [
{
"item_id": "SKU-DE-001",
"description": "Cotton knit short sleeve T-shirt",
"country_of_origin": "DE",
"extra": {
"steel_pour_country": "IT"
}
},
{
"item_id": "SKU-FR-002",
"description": "Cotton crew neck T-shirt",
"country_of_origin": "FR",
"extra": {}
}
]
}Response Example
{
"items": [
{
"item_id": "SKU-DE-001",
"status": "ok",
"hts_code": "6109.10.0012",
"tariffs": {
"general_rate": "16.5%",
"special_rate": "Free",
"Section 301": [],
"Section 232 - Metals": [],
"Section 122": [
{ "code": "9903.03.01", "rate": "10%" }
]
}
},
{
"item_id": "SKU-FR-002",
"status": "ok",
"hts_code": "6109.10.0004",
"tariffs": {
"general_rate": "16.5%",
"special_rate": "Free",
"Section 301": [],
"Section 232 - Metals": [],
"Section 122": [
{ "code": "9903.03.01", "rate": "10%" }
]
}
}
],
"summary": {
"total": 2,
"succeeded": 2,
"failed": 0
}
}| Field | Type | Meaning | Notes |
|---|---|---|---|
items | array | List of batch processing results | The response order matches the request order |
items[].item_id | string | Caller-provided unique identifier | Used for result reconciliation |
items[].status | string | Processing status | Either ok or failed |
items[].hts_code | string | HTS code for a successful item | Normally a 10-digit code; a split-code product may return an 8-digit parent code; present only when status = ok |
items[].tariffs | object | null | Tariff data for a successful item | May be null for split-code products; present only when status = ok |
items[].tariffs.general_rate | string | null | General rate | This may also be understood as MFN |
items[].tariffs.special_rate | string | null | Special rate | Lightly normalized before being returned |
items[].tariffs.<module_key> | array | Module entries | Each element is {code, rate} |
items[].tariffs.<module_key>[].code | string | Chapter 99 code | |
items[].tariffs.<module_key>[].rate | string | Rate | |
items[].components | array | Component list for a split-code product | Omitted for ordinary products; present only when status = ok |
items[].components[].hts_code | string | Component HTS code | Always 10 digits |
items[].components[].tariffs | object | null | Tariff data for the component | |
items[].code | string | Failure code for a failed item | Present only when status = failed |
summary | object | Summary information for the batch request | |
summary.total | integer | Total number of items in this request | |
summary.succeeded | integer | Number of successful items | |
summary.failed | integer | Number of failed items |
| Field | Type | Meaning | Notes |
|---|---|---|---|
detail | object | Error object | |
detail.code | string | Error code | Intended for programmatic handling |
detail.message | string | Error message | Intended for logging and troubleshooting |
Error Response Example
{
"detail": {
"code": "item_rate_limited",
"message": "Item quota exceeded."
}
}Batch-Level Error Codes
| HTTP Status | Code | Description |
|---|---|---|
401 | missing_api_key | X-Api-Key was not provided in the request headers |
401 | invalid_api_key | API key validation failed |
403 | api_key_revoked | The API key has been revoked |
403 | client_disabled | The caller account has been disabled |
422 | invalid_request | The top-level structure is invalid, item_id values are duplicated, fields are missing, field types are incorrect, or field values do not satisfy the contract |
429 | request_rate_limited | Request-level protection was triggered |
429 | item_rate_limited | Item-level quota protection was triggered |
500 | internal_error | An unclassified batch-level internal error occurred |
Item-Level Failure Codes
| Code | Description |
|---|---|
classification_failed | HTS identification failed for that item |
calculator_failed | Tariff calculation failed for that item |
internal_error | An unclassified internal error occurred for that item |
Replace YOUR_API_KEY with the key issued to you, then run:
curl -X POST 'https://api.gingercontrol.com/openapi/v1/tariff/batch' \
-H 'Content-Type: application/json' \
-H 'X-Api-Key: YOUR_API_KEY' \
-H 'X-Request-Id: manual-batch-001' \
-d '{
"items": [
{
"item_id": "SKU-DE-001",
"description": "Cotton knit short sleeve T-shirt",
"country_of_origin": "DE",
"extra": { "steel_pour_country": "IT" }
},
{
"item_id": "SKU-FR-002",
"description": "Cotton crew neck T-shirt",
"country_of_origin": "FR",
"extra": {}
}
]
}'429 Too Many Requests.Validate request bodies
If you receive 422, the request body structure, field types, or field values usually do not match the contract. Check the request body first.
Handle rate limits gracefully
If you receive 429, implement retry behavior using the Retry-After response header.
Log request IDs
Keep request logs and record the X-Request-Id for each call. This significantly reduces troubleshooting time.
Configure timeouts and retries
Configure reasonable timeouts, retries, and failure alerts so that network fluctuations can be handled robustly.
Do not embed your API key in frontend code, browser code, or any environment exposed to end users.
Do not use production API keys in test, development, or temporary debugging environments.
Store your API key in a secure configuration system, such as a secret manager or tightly controlled environment variables.
If an API key is lost, suspected to be leaked, or needs to be rotated, please contact us as soon as possible.
For integration support, testing, production rollout, or ongoing operations, please contact us:
Email: chen@gingercontrol.com
We use cookies to understand how visitors interact with our site. No personal data is shared with advertisers.