Clasificación aduanera UE y China
Conecte su sistema, inicie una clasificación UE o China y recupere el código, las fuentes y la versión arancelaria aplicada.
Esta API clasifica un producto en la nomenclatura de la jurisdicción solicitada:
| Jurisdicción | Resultado | Ruta |
|---|---|---|
| Unión Europea | NC de 8 dígitos y TARIC de 10 dígitos | /v1/classify |
| China | Código de mercancía GACC de 10 dígitos y sufijo CIQ de 3 dígitos | /v1/classify-china |
El procesamiento es asíncrono: cree un job, consulte su estado y lea result cuando haya terminado.
Referencias oficiales de 2026
| Jurisdicción | Referencia oficial | Aplicación |
|---|---|---|
| Unión Europea | Reglamento de Ejecución (UE) 2025/1926, NC 2026 | Desde el 1 de enero de 2026 |
| China | Plan de ajuste arancelario de 2026, anuncio n.º 11 de 2025 | Desde el 1 de enero de 2026 |
| China | Consulta arancelaria de la Administración General de Aduanas | Verificación operativa de códigos y tipos |
La respuesta es el registro técnico de cada expediente: consulte siempre provenance.applied_tariff_date, provenance.tariff_date_basis y provenance.corpus_versions. latest_available_snapshot indica que se aplicó la última instantánea disponible durante un cambio de versión arancelaria.
Inicio en 3 llamadas
1. Configure la clave
Abra su organización desde el espacio Organizaciones, cree una clave en la sección Desarrollador y asígnele el scope necesario:
| Ruta | Scope requerido |
|---|---|
/v1/classify/... | classify |
/v1/classify-china/... | classify_china |
Conserve la clave en su servidor. No la exponga en el navegador ni en una aplicación móvil.
export TTH_API_KEY="th_live_su_clave_api"2. Cree un job
curl -sS -X POST "https://api.thetradehub.eu/v1/classify/jobs" \
-H "X-API-Key: $TTH_API_KEY" \
-H "Idempotency-Key: producto-4821-ue-20260910" \
-H "Content-Type: application/json" \
-d '{
"content": "Auriculares Bluetooth inalámbricos con reducción activa de ruido y carga USB-C",
"analysis_mode": "operational",
"locale": "es",
"classification_date": "2026-09-10"
}'Una nueva solicitud devuelve 202 Accepted. Repetirla con el mismo Idempotency-Key devuelve el job existente con 200 OK.
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "pending",
"analysis_mode": "operational",
"created_at": "2026-09-10T10:30:00Z",
"updated_at": "2026-09-10T10:30:00Z"
}3. Recupere el resultado
Utilice la misma familia de rutas empleada para crear el job.
curl -sS "https://api.thetradehub.eu/v1/classify/jobs/a1b2c3d4-e5f6-7890-abcd-ef1234567890" \
-H "X-API-Key: $TTH_API_KEY"Consulte el job después de 1, 2, 4 y luego cada 5 segundos hasta obtener completed o failed.
Ejemplo completo
import os
import time
import uuid
import httpx
BASE_URL = "https://api.thetradehub.eu"
API_KEY = os.environ["TTH_API_KEY"]
ROUTES = {"eu": "classify", "china": "classify-china"}
def classify_product(
content: str,
jurisdiction: str = "eu",
analysis_mode: str = "operational",
classification_date: str | None = None,
) -> dict:
route = ROUTES[jurisdiction]
timeout_seconds = 12 * 60 if analysis_mode == "operational" else 18 * 60
headers = {
"X-API-Key": API_KEY,
"Idempotency-Key": str(uuid.uuid4()),
}
payload = {
"content": content,
"analysis_mode": analysis_mode,
"locale": "es",
}
if classification_date:
payload["classification_date"] = classification_date
with httpx.Client(base_url=BASE_URL, headers=headers, timeout=30) as client:
response = client.post(f"/v1/{route}/jobs", json=payload)
response.raise_for_status()
job_id = response.json()["id"]
deadline = time.monotonic() + timeout_seconds
delay = 1
while time.monotonic() < deadline:
response = client.get(f"/v1/{route}/jobs/{job_id}")
response.raise_for_status()
job = response.json()
if job["status"] == "completed":
return job["result"]
if job["status"] == "failed":
raise RuntimeError(job.get("error", "Classification failed"))
time.sleep(delay)
delay = min(delay * 2, 5)
raise TimeoutError(f"El job {job_id} sigue en curso")
result = classify_product(
"Bomba centrífuga de acero inoxidable para líquidos alimentarios",
jurisdiction="china",
classification_date="2026-09-10",
)
decision = result["classification"]
china = result.get("china") or decision.get("china")
print(china.get("code13") or china["code10"])
print(decision["provenance"]["applied_tariff_date"])Dónde se encuentra cada dato
| Dato | UE | China |
|---|---|---|
| Código recomendado | result.classification.recommended_code | result.china.code13 o result.china.code10 |
| Código SH común | Primeros 6 dígitos | result.china.hs6 |
| Confianza | result.classification.candidates[0].confidence | result.china.confidence |
| Justificación | result.classification.candidates[0].legal_position | result.china.justification |
| Estado jurídico | result.classification.status | misma ruta |
| Fecha arancelaria aplicada | result.classification.provenance.applied_tariff_date | misma ruta |
| Versiones de los corpus | result.classification.provenance.corpus_versions | misma ruta |
| Identificador del expediente | result.session_id | result.session_id |
Si result.classification.status es review_required, el motor ha entregado una clasificación utilizable, pero requiere validación humana antes de su uso declarativo.
Estructura de un resultado UE
{
"status": "completed",
"result": {
"session_id": "run_abc123",
"classification": {
"jurisdiction": "eu",
"status": "completed",
"recommended_code": "8518300090",
"candidates": [
{
"rank": 1,
"code": "8518300090",
"description": "Auriculares",
"confidence": 0.94,
"legal_position": "Clasificación según las RGI y las notas aplicables"
}
],
"provenance": {
"applied_tariff_date": "2026-09-10T00:00:00Z",
"tariff_date_basis": "request",
"corpus_versions": {}
}
}
}
}Estructura de un resultado China
{
"status": "completed",
"result": {
"session_id": "run_def456",
"classification": {
"jurisdiction": "china",
"status": "completed",
"recommended_code": "8413709990999",
"provenance": {
"applied_tariff_date": "2026-09-10T00:00:00Z",
"tariff_date_basis": "request",
"corpus_versions": {}
}
},
"china": {
"code10": "8413709990",
"code13": "8413709990999",
"hs6": "841370",
"description_zh": "离心泵",
"confidence": 0.91,
"justification": "Clasificación según el arancel chino y las notas nacionales",
"ciq_candidates": [],
"selected_ciq": "999",
"declaration_elements": [],
"supervision_codes": [],
"quarantine_categories": [],
"units": "",
"mfn_rate": "",
"vat_rate": "",
"validated": true,
"verification_status": "operational",
"warnings": []
}
}
}Los valores anteriores solo ilustran la estructura. No constituyen una decisión de clasificación para los productos descritos.
Campos aceptados
| Campo | Tipo | Obligatorio | Uso |
|---|---|---|---|
content | string | Condicional | Descripción detallada, ficha de producto o datos estructurados |
image_urls | string[] | Condicional | Hasta 5 imágenes HTTPS |
image_base64 | string | Condicional | Imagen codificada en base64 |
image_media_type | string | Con image_base64 | Tipo MIME |
analysis_mode | operational o legal_deep | No | operational por defecto |
locale | fr, en, es o de | No | Idioma de respuesta |
classification_date | fecha ISO YYYY-MM-DD | No | Fecha arancelaria que debe aplicarse |
product_identity | object | No | Fabricante, nombre, modelo y referencia |
technical_facts | object[] | No | Características técnicas con fuente |
transaction_context | object | No | Destino, usuario final y uso conocido |
taric_code | string | Solo China | Indicio comparativo, nunca conversión automática |
Debe proporcionar al menos content, image_urls o image_base64.
Estados y tiempos máximos
| Nivel | Valores |
|---|---|
| Job | pending, processing, completed, failed |
| Decisión | completed, review_required |
| Elemento de lote | completed, failed, timeout |
El gateway permite hasta 11 minutos para operational y 17 minutos para legal_deep. Configure 12 y 18 minutos en el cliente. Un 202 significa que el job fue aceptado, no que haya terminado.
Lotes, historial y fuentes
Use /v1/classify/batch para la UE o /v1/classify-china/batch para China. Después consulte GET /v1/{route}/batch/{batch_id}.
Cada solicitud contiene de 1 a 1.000 filas y devuelve un único identificador de lote padre. El servicio distribuye el trabajo en sublotes duraderos de 100, con un máximo de 32 clasificaciones activas. Un archivo de 500 filas produce 5 sublotes internos y uno de 1.000 filas produce 10. Conserve un id estable por fila. Tras un fallo parcial, cree un lote nuevo que contenga únicamente las filas fallidas y use un nuevo Idempotency-Key de lote.
Sustituya {route} por classify o classify-china.
| Necesidad | Solicitud |
|---|---|
| Listar historial | GET /v1/{route}/history?page=1&per_page=20 |
| Leer una clasificación | GET /v1/{route}/history/{log_id} |
| Exportar CSV | GET /v1/{route}/history/export?from=2026-09-01&to=2026-09-30 |
| Listar fuentes congeladas | GET /v1/{route}/runs/{run_id}/sources |
| Leer una fuente | GET /v1/{route}/runs/{run_id}/source?source_id={source_id} |
Errores y reintentos
{
"error": "descripción explícita del error"
}| HTTP | Acción |
|---|---|
400 | Corrija la solicitud y no la repita sin cambios |
401 | Compruebe X-API-Key |
403 | Añada el scope o active el módulo |
404 | Compruebe el identificador y la organización |
429 | Respete Retry-After y reutilice el mismo Idempotency-Key |
502, 503, 504 | Reintente con backoff y el mismo Idempotency-Key |
Nunca registre la clave API, las imágenes en base64 ni los datos comerciales sensibles.
Last updated on