Classification API Documentation

Integrate HS code classification into your applications with the Import8 REST API. Classify products using image, text, or both.

Base URL https://import8.nl/api

Authentication

All API requests (except /health) require authentication via an API key. Generate API keys in your dashboard.

Pass your API key via the Authorization header using the Bearer scheme:

curl -H "Authorization: Bearer c8_your_api_key" \
  https://import8.nl/api/v1/me
import requests

response = requests.get(
    "https://import8.nl/api/v1/me",
    headers={"Authorization": "Bearer c8_your_api_key"}
)
print(response.json())
const response = await fetch('https://import8.nl/api/v1/me', {
  headers: { 'Authorization': 'Bearer c8_your_api_key' }
});
const data = await response.json();

Usage Tracking

All classification endpoints include a usage object in the response, so you can track your remaining credits without a separate API call.

"usage": {
  "credits_remaining": 47
}
Field Type Description
credits_remaining integer Number of credits remaining across all active balances
POST

/v1/classify

Submit a product for HS code classification. The classification is processed asynchronously -- you receive a 202 Accepted response with a classification ID. Poll for results or configure a webhook.

Request Body

Parameter Type Required Description
image_url string optional URL of a product image (up to 5 images supported)
image_base64 string optional Base64-encoded product image
description string optional Product text description
origin_country string optional 2-letter ISO country code of product origin
destination_country string optional 2-letter ISO country code (default: NL)
goods_value number optional Unit price of the goods (FOB). When provided, landed cost is calculated automatically after classification.
quantity integer optional Number of units (default: 1)
shipping_cost number optional Shipping / freight cost (default: 0)
insurance_cost number optional Insurance cost (default: 0)
currency string optional 3-letter currency code (default: EUR). Supported: EUR, USD, GBP, CNY.

Note: At least one of image_url, image_base64, or description is required.

Landed cost: When goods_value is provided, the classification result will include a landed_cost object with CIF value, duty, anti-dumping, VAT, and total landed cost. This uses the same calculation as the standalone POST /v1/landed-cost endpoint.

Risk grading & documents: A completed result also includes risk_grading (regulatory intensity level L0–L6 for the HS code, plus CBAM / anti-dumping / sanctions flags) and documents (the required import documents per applicable regime). Both carry an available boolean: true alongside the data, or false with a reason (no_hs_code or error), so you can distinguish "no obligations" from "could not be computed". These objects are returned by this endpoint and by GET /v1/classifications/{id} — the webhook itself only signals that the result is ready.

Example Request

curl -X POST https://import8.nl/api/v1/classify \
  -H "Authorization: Bearer c8_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "description": "Wireless bluetooth over-ear headphones with noise cancellation",
    "image_url": "https://example.com/product.jpg",
    "origin_country": "CN",
    "destination_country": "NL",
    "goods_value": 25.00,
    "quantity": 100,
    "shipping_cost": 150.00,
    "insurance_cost": 12.50,
    "currency": "EUR"
  }'
import requests

response = requests.post(
    "https://import8.nl/api/v1/classify",
    headers={"Authorization": "Bearer c8_your_api_key"},
    json={
        "description": "Wireless bluetooth over-ear headphones with noise cancellation",
        "image_url": "https://example.com/product.jpg",
        "origin_country": "CN",
        "destination_country": "NL",
        "goods_value": 25.00,
        "quantity": 100,
        "shipping_cost": 150.00,
        "insurance_cost": 12.50,
        "currency": "EUR"
    }
)

data = response.json()
classification_id = data["data"]["id"]
print(f"Classification queued: {classification_id}")
const response = await fetch('https://import8.nl/api/v1/classify', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer c8_your_api_key',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    description: 'Wireless bluetooth over-ear headphones with noise cancellation',
    image_url: 'https://example.com/product.jpg',
    origin_country: 'CN',
    destination_country: 'NL',
    goods_value: 25.00,
    quantity: 100,
    shipping_cost: 150.00,
    insurance_cost: 12.50,
    currency: 'EUR',
  }),
});

const { data } = await response.json();
console.log('Classification queued:', data.id);

Response 202 Accepted

{
  "success": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "status": "pending",
    "message": "Classification queued. Poll GET /v1/classifications/{id} for results, or configure a webhook to receive notifications."
  },
  "usage": {
    "credits_remaining": 47
  }
}
GET

/v1/classifications/{id}

Retrieve a classification result by its UUID. Poll this endpoint after submitting a classification request until the status changes from pending to completed.

Example Request

curl https://import8.nl/api/v1/classifications/550e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer c8_your_api_key"
import requests
import time

classification_id = "550e8400-e29b-41d4-a716-446655440000"

# Poll until completed (typically 25-35 seconds)
while True:
    response = requests.get(
        f"https://import8.nl/api/v1/classifications/{classification_id}",
        headers={"Authorization": "Bearer c8_your_api_key"}
    )
    data = response.json()["data"]

    if data["status"] == "completed":
        print(f"HS Code: {data['hs_code']['code_8']}")
        print(f"Confidence: {data['confidence']}%")
        break
    elif data["status"] == "failed":
        print("Classification failed")
        break

    time.sleep(5)
const classificationId = '550e8400-e29b-41d4-a716-446655440000';

// Poll until completed
async function pollResult() {
  const response = await fetch(
    `https://import8.nl/api/v1/classifications/${classificationId}`,
    { headers: { 'Authorization': 'Bearer c8_your_api_key' } }
  );
  const { data } = await response.json();

  if (data.status === 'completed') return data;
  if (data.status === 'failed') throw new Error('Classification failed');

  await new Promise(r => setTimeout(r, 5000));
  return pollResult();
}

Response 200 OK

{
  "success": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "status": "completed",
    "source": "api",
    "created_at": "2026-03-03T12:00:00+00:00",
    "hs_code": {
      "code_6": "8518.30",
      "code_8": "8518.30.00",
      "description": "Headphones and earphones",
      "chapter": "85"
    },
    "confidence": 92,
    "reasoning": "The product is wireless bluetooth headphones, which fall under HS heading 8518 for microphones, loudspeakers, and headphones.",
    "decision_tree": [
      {"level": "section", "code": "XVI", "description": "Machinery and mechanical appliances"},
      {"level": "chapter", "code": "85", "description": "Electrical machinery and equipment"},
      {"level": "heading", "code": "8518", "description": "Microphones, loudspeakers, headphones"}
    ],
    "alternative_codes": [
      {
        "code": "8518.10.00",
        "description": "Microphones",
        "reasoning": "Would apply if the product includes a built-in microphone as primary function"
      }
    ],
    "product_summary": "Wireless bluetooth over-ear headphones with noise cancellation",
    "ai_usage": {
      "input_tokens": 1234,
      "output_tokens": 567,
      "cost_usd": 0.00408
    },
    "completed_at": "2026-03-03T12:00:30+00:00",
    "landed_cost": {
      "cif_value": 2662.50,
      "duty": {
        "rate": "0.0%",
        "amount": 0,
        "type": "mfn"
      },
      "anti_dumping": {
        "rate": "0.0%",
        "amount": 0
      },
      "vat": {
        "rate": "21.00%",
        "amount": 559.13
      },
      "total_landed_cost": 3221.63,
      "currency": "EUR"
    },
    "risk_assessment": {
      "level": "medium",
      "reasons": ["Electronics — CE marking, RoHS, WEEE registration and EMC compliance required"],
      "should_warn": true,
      "recommended_action": "Re-run this classification in Audit mode for a defensible decision trail, or consult a customs broker."
    },
    "risk_grading": {
      "available": true,
      "overall_level": 2,
      "overall_label": "Conformity",
      "trade8_tier": "free",
      "cbam_applicable": false,
      "anti_dumping_applicable": false,
      "sanctions_applicable": false,
      "dual_use_applicable": false,
      "elements": [
        {
          "regime": "Electromagnetic Compatibility (EMC)",
          "level": 2,
          "label": "Conformity",
          "applies": true,
          "obligations": ["Affix CE marking and draw up an EU Declaration of Conformity"],
          "legal_ref": "Directive 2014/30/EU",
          "source_url": "https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:32014L0030",
          "verified_at": "2026-05-20",
          "national_authority": null
        }
      ],
      "rules_version": "v1.0.1"
    },
    "documents": {
      "available": true,
      "items": [
        {
          "name": "EU Declaration of Conformity (DoC)",
          "status": "verplicht-EU",
          "legal_ref": "Directive 2014/30/EU, Art. 14",
          "source_url": "https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:32014L0030",
          "source_quote": "The EU declaration of conformity shall state that the fulfilment of the essential requirements has been demonstrated.",
          "national_authority": null,
          "verified_at": "2026-05-20",
          "regime_code": "EMC_2014_30",
          "regime_name": "Electromagnetic Compatibility (EMC)"
        }
      ]
    }
  },
  "usage": {
    "credits_remaining": 47
  }
}
GET

/v1/classifications

List all classifications for your organization, sorted by newest first. Results are paginated.

Query Parameters

Parameter Type Default Description
per_page integer 20 Number of results per page (max 100)

Response 200 OK

{
  "success": true,
  "data": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "status": "completed",
      "product_summary": "Wireless bluetooth over-ear headphones",
      "hs_code": "8518.30.00",
      "confidence": 92,
      "created_at": "2026-03-03T12:00:00+00:00"
    }
  ],
  "meta": {
    "current_page": 1,
    "per_page": 20,
    "total": 42,
    "last_page": 3
  },
  "usage": {
    "credits_remaining": 47
  }
}
POST

/v1/classify/batch

Submit up to 100 products for classification in a single request. Each item is processed individually and asynchronously. Returns a batch ID to track overall progress.

Request Body

Parameter Type Required Description
items array required Array of classification requests (max 100). Each item has the same fields as POST /v1/classify.

Example Request

curl -X POST https://import8.nl/api/v1/classify/batch \
  -H "Authorization: Bearer c8_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      {"description": "Wireless bluetooth headphones", "origin_country": "CN"},
      {"description": "Stainless steel water bottle", "origin_country": "CN"},
      {"description": "Cotton t-shirt, men, crew neck", "origin_country": "BD"}
    ]
  }'
response = requests.post(
    "https://import8.nl/api/v1/classify/batch",
    headers={"Authorization": "Bearer c8_your_api_key"},
    json={
        "items": [
            {"description": "Wireless bluetooth headphones", "origin_country": "CN"},
            {"description": "Stainless steel water bottle", "origin_country": "CN"},
            {"description": "Cotton t-shirt, men, crew neck", "origin_country": "BD"}
        ]
    }
)
batch_id = response.json()["data"]["batch_id"]
const response = await fetch('https://import8.nl/api/v1/classify/batch', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer c8_your_api_key',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    items: [
      { description: 'Wireless bluetooth headphones', origin_country: 'CN' },
      { description: 'Stainless steel water bottle', origin_country: 'CN' },
      { description: 'Cotton t-shirt, men, crew neck', origin_country: 'BD' },
    ]
  }),
});

Response 202 Accepted

{
  "success": true,
  "data": {
    "batch_id": "batch_abc123",
    "total": 3,
    "classification_ids": [
      "550e8400-e29b-41d4-a716-446655440001",
      "550e8400-e29b-41d4-a716-446655440002",
      "550e8400-e29b-41d4-a716-446655440003"
    ]
  },
  "usage": {
    "credits_remaining": 47
  }
}
GET

/v1/classify/batch/{batch_id}

Check the status of a batch classification request. Returns the status of each individual classification in the batch.

Response 200 OK

{
  "success": true,
  "data": {
    "batch_id": "batch_abc123",
    "total": 3,
    "completed": 2,
    "pending": 1,
    "failed": 0,
    "classifications": [
      {
        "id": "550e8400-e29b-41d4-a716-446655440001",
        "status": "completed",
        "hs_code": "8518.30.00"
      },
      {
        "id": "550e8400-e29b-41d4-a716-446655440002",
        "status": "completed",
        "hs_code": "7323.93.00"
      },
      {
        "id": "550e8400-e29b-41d4-a716-446655440003",
        "status": "pending",
        "hs_code": null
      }
    ]
  },
  "usage": {
    "credits_remaining": 44
  }
}
POST

/v1/classifications/{id}/feedback

Submit feedback on a classification result. Confirm the classification was correct or provide the correct HS code. This helps improve the system over time.

Request Body

Parameter Type Required Description
status string required confirmed or corrected
corrected_code string if corrected The correct HS code (required when status is corrected)

Example: Confirm

curl -X POST https://import8.nl/api/v1/classifications/550e8400-.../feedback \
  -H "Authorization: Bearer c8_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"status": "confirmed"}'

Example: Correct

curl -X POST https://import8.nl/api/v1/classifications/550e8400-.../feedback \
  -H "Authorization: Bearer c8_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"status": "corrected", "corrected_code": "8518.10.00"}'
GET

/v1/usage

Get current usage statistics for your organization in the current billing period.

Response 200 OK

{
  "success": true,
  "data": {
    "plan": {
      "name": "Starter",
      "display_name": "Starter"
    },
    "classifications": {
      "current": 42,
      "limit": 500,
      "remaining": 458,
      "percentage": 8
    },
    "period": {
      "year": 2026,
      "month": 3
    }
  }
}
GET

/v1/me

Get account information for the authenticated API key, including organization details and credit balance.

Response 200 OK

{
  "success": true,
  "data": {
    "organization": {
      "name": "Acme Trading Co.",
      "email": "api@acmetrading.com",
      "country": "NL"
    },
    "credits": {
      "remaining": 247,
      "total_purchased": 250,
      "total_used": 3,
      "earliest_expiry": "2027-03-26T00:00:00+00:00"
    },
    "limits": {
      "rate_limit_per_minute": 20,
      "max_api_keys": 3
    }
  }
}
GET

/health

Check the API status. This endpoint does not require authentication.

curl https://import8.nl/api/health

# Response:
{
  "success": true,
  "data": {
    "status": "operational"
  }
}
GET

/v1/duty-rates/{hs_code}

Retrieve duty rates for a 10-digit HS code. Returns MFN duties, preferential duties, anti-dumping duties, and VAT rate.

Query Parameters

Parameter Type Description
origin string 2-letter ISO country code to filter preferential duties
destination string 2-letter ISO country code for VAT calculation (default: NL)

Example

curl "https://import8.nl/api/v1/duty-rates/8518300090?origin=CN&destination=NL" \
  -H "Authorization: Bearer c8_your_api_key"

Response 200 OK

{
  "success": true,
  "data": {
    "hs_code": "8518300090",
    "description": "Headphones and earphones",
    "mfn_duty": {
      "rate": "2.00%",
      "expression": "2.000 %"
    },
    "preferential_duties": [
      {
        "scheme": "GSP",
        "rate": "0.00%",
        "countries": ["CN", "VN", "BD"]
      }
    ],
    "anti_dumping": [],
    "vat_rate": "21.00%"
  }
}
POST

/v1/landed-cost

Calculate total landed cost for importing a product. Combines CIF value, duties, anti-dumping duties, and VAT.

Request Body

Parameter Type Required Description
hs_code string required 10-digit HS commodity code
origin_country string required 2-letter ISO country code
destination_country string optional Default: NL
value number required Product value (min: 0.01)
currency string optional Default: EUR
shipping number optional Shipping costs (default: 0)
insurance number optional Insurance costs (default: 0)

Response 200 OK

{
  "success": true,
  "data": {
    "cif_value": 31.50,
    "duty": {
      "rate": "0.00%",
      "amount": 0.00,
      "type": "preferential"
    },
    "anti_dumping": {
      "rate": "0.00%",
      "amount": 0.00
    },
    "vat": {
      "rate": "21.00%",
      "amount": 6.62
    },
    "total_landed_cost": 38.12,
    "currency": "EUR"
  }
}
PUT

/v1/webhook

Configure a webhook URL to receive push notifications when classifications complete or fail.

Note: The webhook is a notification only — it carries the classification id, not the result. Fetch the full data via GET /v1/classifications/{id}.

Example

curl -X PUT https://import8.nl/api/v1/webhook \
  -H "Authorization: Bearer c8_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/webhook"}'

Response 200 OK

{
  "success": true,
  "data": {
    "url": "https://example.com/webhook"
  }
}
DELETE

/v1/webhook

Remove the configured webhook. You will stop receiving notifications.

curl -X DELETE https://import8.nl/api/v1/webhook \
  -H "Authorization: Bearer c8_your_api_key"

# Response:
{
  "success": true,
  "message": "Webhook removed."
}

Webhook Events

When a classification finishes processing, Import8 sends a small POST notification to your webhook URL, with the event type in the X-Import8-Event header.

Event Description
classification.completed Classification finished successfully
classification.failed Classification failed due to an error

Headers

Header Description
X-Import8-Event Event type (e.g. classification.completed)
User-Agent Import8-Webhook/1.0

Example Payload

{
  "event": "classification.completed",
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "status": "completed"
  }
}

The webhook is a signal, not the data. It only tells you a classification is ready (or failed) and carries its id. Fetch the full result — HS code, risk grading, documents — via the authenticated GET /v1/classifications/{id}. Because the notification contains no sensitive data and the result sits behind your API key, the webhook is not signed.

Rate Limits

Rate limits are applied per API key and depend on your credit package tier. Every API response includes rate limit headers:

Header Description
X-RateLimit-Limit Max requests per window
X-RateLimit-Remaining Remaining requests in current window
X-RateLimit-Reset Unix timestamp when window resets

When exceeded, the API returns 429 Too Many Requests with a Retry-After header.

HTTP/1.1 429 Too Many Requests
Retry-After: 30
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0

{
  "success": false,
  "message": "Rate limit exceeded. Please retry after 30 seconds."
}

Error Codes

The API uses standard HTTP status codes:

Status Meaning
200 Success
202 Accepted -- classification queued
401 Invalid or missing API key
404 Resource not found
422 Validation error -- check request body
429 Rate limit or usage limit exceeded
500 Server error

Error Response Format

{
  "success": false,
  "message": "Description of the error"
}
Import8

Welcome back

Log in to your account

Forgot password?

Don't have an account?

Import8

Create your account

Start with 5 free credits

Already have an account?