# EU Binding Tariff Information (EBTI) Search & Monitor (`nordicdataforge/eu-binding-tariff-information-monitor`) Actor

Search and monitor official public EU customs-classification decisions by product, CN/TARIC code, country, reference, date, and status. Independent research tool; no login or EORI required.

- **URL**: https://apify.com/nordicdataforge/eu-binding-tariff-information-monitor.md
- **Developed by:** [Nordic Data Forge](https://apify.com/nordicdataforge) (community)
- **Categories:** Automation, Developer tools, E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 bti decisions

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## EU Binding Tariff Information (EBTI) Search & Monitor

Search, export, and monitor official public EU customs-classification decisions without manually paging through the European Commission's EBTI portal.

The Actor turns filtered EBTI search exports into normalized JSON, CSV, Excel, API, and webhook-ready records. It can detect new decisions, material updates, invalidations, and decisions that disappear from a stable complete search scope.

No login, EORI number, API key, proxy, or private EU Trader Portal access is required.

### Why use this Actor?

A Binding Tariff Information decision is an official customs decision about a product's tariff classification. The classification can affect customs duty, trade-defense measures, licences, restrictions, and other import or export requirements.

The public EBTI interface is useful for individual lookups, but repetitive research and monitoring are manual. This Actor adds:

- batch searches across multiple CN/TARIC code prefixes and issuing countries;
- structured output with consistent field names;
- deduplication when search scopes overlap;
- additional keyword, language, and status filters;
- persistent change monitoring between scheduled runs;
- spending-limit-aware pay-per-event delivery;
- an audit summary for every run.

### Quick start

Press **Start** with the default input. The Actor reads the official daily publication files and returns decisions published during the previous seven days, including valid and invalid decisions.

For a reusable code monitor, clear `issuedSince`, enter a narrow code such as `851762`, keep change monitoring enabled, and schedule the Actor daily or weekly.

#### Example input

```json
{
    "nomenclatureCodes": ["851762", "950300"],
    "issuingCountries": ["DE", "FR", "PL"],
    "issuedSince": "30 days",
    "includeInvalid": true,
    "statuses": ["valid", "invalid"],
    "keywords": ["router"],
    "keywordMatch": "any",
    "maxResults": 500,
    "enableChangeMonitoring": true,
    "outputMode": "new-updated-removed"
}
```

#### Example output

```json
{
    "id": "eu-bti:4b4cdd7ca95f8c11c06da81f",
    "recordType": "eu-binding-tariff-information",
    "btiReference": "DEBTI15138/25-1",
    "issuingCountry": "DE",
    "issueDate": "2025-06-29",
    "validFrom": "2025-06-30",
    "validUntil": "2028-06-29",
    "status": "valid",
    "nomenclatureCodeRaw": "8517620000************",
    "nomenclatureCode": "8517620000",
    "cnCode": "85176200",
    "taricCode": "8517620000",
    "language": "de",
    "placeOfIssue": "HANNOVER",
    "description": "Industrial data-transmission apparatus...",
    "keywords": ["ROUTER", "NETWORK"],
    "classificationJustification": "General Rules 1 and 6...",
    "invalidationReason": null,
    "invalidationJustification": null,
    "sourceLastUpdatedOn": "2026-07-31",
    "sourceDatabaseUrl": "https://ec.europa.eu/taxation_customs/dds2/ebti/ebti_consultation.jsp?Lang=en",
    "sourceSystem": "European Commission EBTI public database",
    "sourceAttribution": "European Commission — EBTI public decisions",
    "sourceLicenceUrl": "https://commission.europa.eu/legal-notice_en",
    "unofficialProduct": true,
    "firstSeenAt": "2026-08-01T09:00:00.000Z",
    "lastSeenAt": "2026-08-01T09:00:00.000Z",
    "changeType": "new",
    "changedFields": [],
    "collectedAt": "2026-08-01T09:00:00.000Z"
}
```

### Input reference

#### Source search

- `nomenclatureCodes`: up to 20 code prefixes containing 2–10 digits. Each code is queried independently.
- `descriptionSearch`: optional public EBTI full-text goods-description search.
- `reference`: optional complete or partial BTI reference.
- `issuingCountries`: up to 28 two-letter EBTI country codes. Each country is queried independently.
- `issuedSince`: absolute `YYYY-MM-DD` date or a relative value such as `7 days`, `4 weeks`, `3 months`, or `1 year`.
- `validityStartFrom` / `validityStartTo`: optional start-of-validity range.
- `includeInvalid`: asks the official source to include invalid decisions.

Codes and countries are combined. Two codes and three countries therefore produce six narrowly filtered official searches. The Actor refuses more than 40 combinations.

#### Result filters

- `statuses`: deliver valid, invalid, and/or unknown source statuses.
- `languages`: optional two-letter decision-language filters.
- `keywords`: optional terms matched locally across description, official keywords, code, reference, and classification reasoning.
- `keywordMatch`: require any or all local keywords.
- `maxResults`: maximum deduplicated decisions delivered, from 1 to 5,000.

#### Monitoring

- `enableChangeMonitoring`: stores a filter-specific snapshot in Apify Key-Value Store.
- `outputMode`: return all decisions, only changes, or only new decisions.

On the first run every record is `new`. Later runs can be `unchanged`, `updated`, or `removed`. `changedFields` identifies the material fields that changed.

Removed detection is intentionally disabled when:

- `issuedSince` is relative, because a moving date window would create false removals as old records age out; or
- `maxResults` caps the matching result set, because the omitted tail is not a complete comparison scope.

#### Safety controls

- `maxSourceRecordsPerQuery`: refuses an unexpectedly broad official export after safe bounded parsing; compressed and uncompressed size caps protect memory first.
- `requestTimeoutSecs`: per-request timeout.
- `maxRetries`: retries timeouts, rate limits, and temporary server errors.
- `minRequestIntervalMillis`: polite pacing between official requests.

The Actor never downloads the approximately 393 MB complete EBTI archive. It uses official daily publication files for an unfiltered recent window and official filtered search exports for targeted research.

### Output fields

The default dataset contains one record per deduplicated public BTI decision. Important fields include:

- decision identity: `btiReference`, `issuingCountry`, `issueDate`;
- classification: `nomenclatureCode`, `cnCode`, `taricCode`;
- validity: `validFrom`, `validUntil`, `status`;
- public decision content: `description`, `keywords`, `classificationJustification`;
- invalidation: `invalidationReason`, `invalidationJustification`;
- monitoring: `firstSeenAt`, `lastSeenAt`, `changeType`, `changedFields`;
- provenance: `sourceLastUpdatedOn`, `sourceDatabaseUrl`, attribution and legal-notice URL.

`RUN_SUMMARY` in the default Key-Value Store records source counts, downloaded bytes, delivery counts, change totals, safety decisions, licence information, and whether history was saved.

### Common use cases

- Customs brokers researching classification precedents.
- Importers monitoring new decisions for product categories.
- Trade-compliance teams watching invalidations and validity changes.
- Freight forwarders enriching internal tariff research tools.
- ERP, customs, and e-commerce developers integrating structured EBTI data.
- Customs lawyers and consultants building evidence collections for manual review.

### Pricing

The intended Apify Store pricing is pay per event:

- first 10 delivered decisions in every run: free;
- each additional delivered decision: **$0.01**;
- no charge for source matches that are filtered out, duplicate, invalid, or not delivered because of a spending limit;
- a small **$0.00005** synthetic start event (per GB of memory, minimum one event), which enables Apify's first-five-seconds usage waiver.

The default dataset synthetic event must remain priced at zero to prevent double charging. Platform usage is intended to be included in the event price.

### Responsible and legal use

This is an independent product and is not affiliated with or endorsed by the European Commission or any customs authority.

The Actor uses the European Commission's public EBTI consultation and its public filtered export function. It does not access the authenticated EU Customs Trader Portal, submit applications, use EORI credentials, bypass access controls, or solve CAPTCHAs.

The source CSV includes a `NAME_AND_ADDRESS` column. This Actor deliberately excludes that column from all datasets, snapshots, summaries, and logs. It also does not download or republish decision images. Only the public decision fields documented above are delivered.

European Commission attribution and the source legal-notice URL accompany every record. Users remain responsible for checking any source-specific third-party rights and for complying with applicable law.

### Important legal limitation

A BTI decision is binding on EU customs administrations and the holder of that decision. A decision issued to another holder is useful for research but does not automatically bind customs authorities for your goods.

This Actor provides research and monitoring data only. It does not classify your product, apply for a BTI, calculate duties, or provide legal, customs, tax, or tariff advice. Verify important decisions in the official EBTI database and obtain professional advice or your own BTI where appropriate.

### Data-quality notes

- Decision descriptions and reasoning remain in the original source language; the Actor does not translate or summarize them.
- Some source fields are blank by design.
- `nomenclatureCodeRaw` preserves the official asterisk-padded representation. Numeric `nomenclatureCode`, `cnCode`, and `taricCode` are derived without altering the published digits.
- The source can be temporarily unavailable or can change its export format. The Actor validates counts, ZIP signatures, CSV column alignment, and every normalized record, and fails instead of silently returning partial data.
- A zero-result search is successful and creates an empty dataset plus a complete run summary.

### FAQ

#### Do I need an EORI number or EU account?

No. The Actor only reads the public consultation export.

#### Can I rely on another company's decision for my import?

No. Use public decisions as research material. A BTI is binding for its holder and the customs administrations under the applicable rules.

#### Why was my broad search rejected?

The official full archive is hundreds of megabytes. Add a code, description, country, reference, or date and/or increase the advanced source limit only after narrowing the business need.

#### Why are there no `removed` events with `issuedSince: "7 days"`?

That window moves every day. Marking records as removed when they merely age past seven days would be misleading, so removed detection is disabled automatically.

#### How should I schedule monitoring?

Use a stable narrow code or description, clear `issuedSince`, keep `includeInvalid` and change monitoring enabled, select `new-updated-removed`, and schedule daily or weekly runs.

### Source and attribution

- Public database: <https://ec.europa.eu/taxation_customs/dds2/ebti/ebti_consultation.jsp?Lang=en>
- European Commission BTI information: <https://taxation-customs.ec.europa.eu/customs/common-customs-tariff-cct/tariff-classification-goods/eu-binding-tariff-information-bti_en>
- European Commission legal notice: <https://commission.europa.eu/legal-notice_en>

Source attribution: **European Commission — EBTI public decisions**.

### Support

When reporting a reproducible problem, include the Actor run ID and sanitized input. Do not send customs credentials, EORI login details, confidential product documents, or personal data.

# Actor input Schema

## `nomenclatureCodes` (type: `array`):

Optional code prefixes such as 851762 or 950300. Each code is searched independently and results are deduplicated.

## `descriptionSearch` (type: `string`):

Optional full-text product description with at least three characters, for example industrial router or ceramic plate.

## `reference` (type: `string`):

Optional complete or partial BTI reference, for example DEBTI15138/25-1.

## `issuingCountries` (type: `array`):

Optional two-letter EU country codes such as DE, FR, DK, PL, or XI. Countries are searched independently.

## `issuedSince` (type: `string`):

Use an absolute date or a relative period. Clear this field when you want the full history for a narrow code, reference, country, or description.

## `validityStartFrom` (type: `string`):

Optional lower bound for the BTI start date.

## `validityStartTo` (type: `string`):

Optional upper bound for the BTI start date.

## `includeInvalid` (type: `boolean`):

Include invalidated and expired decisions. Recommended for monitoring and precedent research.

## `statuses` (type: `array`):

Filter the delivered records after the official search completes.

## `languages` (type: `array`):

Optional ISO language codes such as en, de, fr, or pl.

## `keywords` (type: `array`):

Optional case-insensitive terms matched across the description, official keywords, code, reference, and classification justification.

## `keywordMatch` (type: `string`):

Require any or all additional keywords.

## `maxResults` (type: `integer`):

Maximum deduplicated decisions delivered by this run.

## `enableChangeMonitoring` (type: `boolean`):

Compare results with the prior successful run of exactly the same filters in persistent Apify storage.

## `outputMode` (type: `string`):

On the first run every result is new. Removed detection is automatically disabled for moving relative-date windows and capped result sets.

## `maxSourceRecordsPerQuery` (type: `integer`):

Safety limit enforced on every parsed official export. ZIP size is capped before parsing, and the Actor never requests the 393 MB full database.

## `requestTimeoutSecs` (type: `integer`):

Timeout for each official European Commission request.

## `maxRetries` (type: `integer`):

Retries temporary timeouts, rate limits, and server errors with exponential backoff.

## `minRequestIntervalMillis` (type: `integer`):

Polite minimum delay between requests to the official service.

## Actor input object example

```json
{
  "nomenclatureCodes": [],
  "descriptionSearch": "",
  "reference": "",
  "issuingCountries": [],
  "issuedSince": "7 days",
  "validityStartFrom": "",
  "validityStartTo": "",
  "includeInvalid": true,
  "statuses": [
    "valid",
    "invalid"
  ],
  "languages": [],
  "keywords": [],
  "keywordMatch": "any",
  "maxResults": 500,
  "enableChangeMonitoring": true,
  "outputMode": "all",
  "maxSourceRecordsPerQuery": 20000,
  "requestTimeoutSecs": 60,
  "maxRetries": 3,
  "minRequestIntervalMillis": 250
}
```

# Actor output Schema

## `results` (type: `string`):

References, CN/TARIC codes, product descriptions, validity, status, legal reasoning, and monitoring metadata.

## `summary` (type: `string`):

Query status, source counts, delivery status, attribution, privacy statement, and change totals.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("nordicdataforge/eu-binding-tariff-information-monitor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("nordicdataforge/eu-binding-tariff-information-monitor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call nordicdataforge/eu-binding-tariff-information-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=nordicdataforge/eu-binding-tariff-information-monitor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/2Op9sVyPlYzc8zKMo/builds/hVeTL8T6WICwO8neH/openapi.json
