# Antidumping Duty Checker, AD/CVD Orders & Case Status (`scrapemint/antidumping-duty-tracker`) Actor

Check whether a product is under a US antidumping or countervailing duty order, keyless. Search by product, country or case number, get the current status of each case with the notice that set it, and track orders, reviews, revocations and sunset determinations as they publish.

- **URL**: https://apify.com/scrapemint/antidumping-duty-tracker.md
- **Developed by:** [Ken M](https://apify.com/scrapemint) (community)
- **Categories:** Business, News
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

## 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

## Antidumping Duty Checker, AD/CVD Orders & Case Status

Find out whether a product is subject to a **US antidumping or countervailing duty order** before you place the order, not after the entry summary comes back. Search by product, country or case number, get where each case stands right now, and track orders, reviews and revocations as they publish.

No login, no API key, no proxy. The actor reads the official keyless Federal Register API, so runs are fast and cheap.

### Why this matters more than the tariff rate

AD/CVD duties routinely run **20% to over 400%** and sit **on top of** the tariff-schedule rate. An importer who prices a shipment off the HTS line at 3.7% and misses a 86% antidumping margin does not have a rounding error.

Commerce publishes no status field. A case is a stream of notices spanning decades, and whether an order is actually in force has to be derived from them. That derivation is what this actor does.

### The distinctions it gets right

Three phrases look almost identical and mean opposite things. Measured across 3,000 real Commerce notices:

| Phrase in the title | What it does | Count |
| --- | --- | --- |
| "Rescission, in Part, of ... **Administrative Review**" | Ends a **review**. Order stays in force, duties keep being collected | 398 |
| "Revocation of the ... Orders, **in Part**" | Narrows the **order**, dropping some products or exporters. Order survives | 10 |
| "... and **Revocation of Antidumping Duty Order**" | Ends the **order**. Duties stop | 9 |

A classifier that treats the word "revocation" as terminal reports **more than half of them** as killing an order that is still collecting duties. One that also catches "rescission" in the same net reports 398 more.

So each notice carries an explicit `stage` plus an `endsOrder` flag, and only 9 of those 3,000 notices set it:

```json
{
  "title": "Crystalline Silicon Photovoltaic Cells ... From the People's Republic of China: Final Results of Changed Circumstances Reviews, and Revocation of the Antidumping and Countervailing Duty Orders, in Part",
  "stage": "orderRevokedInPart",
  "endsOrder": false
}
```

#### Joint proceedings are not attributed by guesswork

Commerce runs cases jointly, so one notice can name several case numbers and do different things to each. `A-583-853` is a **Taiwan** case whose notices are shared with China, and reading the first country in the title puts the wrong country on it.

Two rules handle this: the case number's country segment decides whose case it is, and a joint notice only sets status when its title names exactly one duty type ("Revocation of **Antidumping** Duty Order" is singular). When a joint notice still disagrees, the case says so rather than picking:

```json
{
  "currentStatus": "revoked",
  "statusConfidence": "conflicted",
  "conflictingNoticeDate": "2026-06-23",
  "conflictingNoticeTitle": "... From the People's Republic of China and Taiwan: ..."
}
```

#### Multi-case round-up notices never set a status

Commerce publishes periodic notices listing dozens of unrelated cases: scope ruling round-ups and the monthly "Opportunity To Request Administrative Review". They are part of a case's paper trail but are not a determination about any one case, so they are flagged `isOmnibusNotice` and excluded from status derivation. A case mentioned in an "opportunity to request a review" notice did not have a review.

They also matter for retrieval: filtering by the API's structured docket field on `A-570-135` returns 11 documents, while a full-text search for the case number returns **25**. The missing 14 are exactly these omnibus notices, which carry no docket of their own. Case mode searches full text so the history is complete.

### Modes

**`notices`** — one row per Commerce publication, newest first. A feed of what changed.

**`cases`** — one row per case, resolved across its whole paper trail:

```json
{
  "caseNumber": "A-580-903",
  "dutyType": "antidumping",
  "country": "South Korea",
  "product": "Polyethylene Terephthalate Sheet",
  "currentStatus": "revoked",
  "statusConfidence": "stated",
  "statusSetByTitle": "... Final Results of Sunset Review and Revocation of Antidumping Duty Order",
  "statusAsOf": "2026-01-12",
  "orderIssuedDate": "2020-11-06",
  "revokedDate": "2026-01-12",
  "noticeCount": 31,
  "caseSpecificNoticeCount": 18,
  "omnibusNoticeCount": 13
}
```

`statusConfidence` separates what was stated from what was read off surrounding activity. `stated` means a notice said so outright. `inferred` means only reviews were found, which prove an order existed without naming it. `conflicted` means a joint notice disagrees.

### Input

| Field | Description |
| --- | --- |
| `mode` | `notices` (default) or `cases` |
| `searchTerms` | Product or company, e.g. `aluminum extrusions`. Empty sweeps every AD/CVD notice in range |
| `caseNumbers` | Commerce case numbers, e.g. `A-570-135`, `C-570-946` |
| `countries` | Filter by origin, e.g. `China`, `Vietnam`. Commerce's naming variants are normalised first |
| `dutyType` | `both`, `antidumping` or `countervailing` |
| `stages` | Narrow to specific actions, e.g. only `orderIssued` and `orderRevoked` |
| `dateFrom` / `dateTo` | `YYYY-MM-DD` |
| `onlyActiveOrders` | Cases mode: keep only cases costing money today |
| `includeOmnibusNotices` | Include the multi-case round-ups |
| `newOnly` | Monitor mode: only what has not been returned before |
| `maxRows` | Stop after N rows (default 100) |

### Examples

**Is my product covered, and by which cases?**

```json
{ "mode": "cases", "searchTerms": ["aluminum extrusions"], "onlyActiveOrders": true }
```

**Everything that ended an order this year**

```json
{ "mode": "notices", "stages": ["orderRevoked"], "dateFrom": "2026-01-01" }
```

**Watch for new action on your suppliers' countries**

```json
{ "mode": "notices", "countries": ["Vietnam", "Thailand"], "newOnly": true }
```

Run it daily. With newest-first ordering it stops at the first notice it already knows, so a quiet week costs nothing.

### Who it's for

Importers and sourcing teams checking exposure before a purchase order, customs brokers and trade compliance staff, trade attorneys tracking case dockets, and analysts covering steel, aluminium, chemicals and solar where these cases decide the margin.

### Pricing

Pay per row. The first 3 rows of every run are free. Case rows cost more because each is built from several searches across the full case history. Rows removed by your filters are never charged.

### Limits worth knowing

- **This is not customs or legal advice.** Whether your specific goods fall within an order's scope is a legal question decided by scope rulings, and a product can be covered without matching the description in the title.
- **Rates are not in these rows.** Cash deposit rates are set per exporter in tables inside each notice and change at every administrative review, so the actor points at the notice at `lastRateActionDate` rather than inventing one number for the case.
- **Effective dates differ from publication dates.** A revocation is often effective retroactively to the start of a review period. Read the notice.
- **The country map is a cross-check, not a source.** It was derived from 3,000 notices by majority vote and only reports whether the case number agrees with the title. Where Commerce's own title has a typo, `countryMatchesCaseNumber` goes false rather than the title being silently rewritten.
- **A narrow date range can hide the order notice**, which shows up honestly as `activeOrderInferred` rather than a confident `activeOrder`.
- The Federal Register API caps any one search at 10,000 results; narrow the date range to reach past it.

### Related products

- **[Import Duty & Tariff Calculator](https://apify.com/scrapemint/import-duty-tariff-calculator)** — the general rate and Chapter 99 tariffs. AD/CVD is the third layer on top of both
- **[Customs Ruling Finder](https://apify.com/scrapemint/customs-ruling-finder)** — how CBP has classified the product, which decides whether an order reaches it
- **[Federal Register Monitor](https://apify.com/scrapemint/federal-register-monitor)** — the same source without the case model, for tracking any agency by keyword
- **[Sanctions & Watchlist Screening](https://apify.com/scrapemint/sanctions-watchlist-scraper)** — screen the supplier before the shipment moves

# Actor input Schema

## `mode` (type: `string`):

Notices returns one row per Commerce publication, newest first. Cases resolves a whole proceeding into one row: where it stands now, which notice said so, and the full history.

## `searchTerms` (type: `array`):

What to look for, for example "aluminum extrusions" or "solar cells". Leave empty with no case numbers to sweep every AD/CVD notice in the date range.

## `caseNumbers` (type: `array`):

Commerce case numbers such as A-570-135 or C-570-946. A is antidumping, C is countervailing, and the middle three digits are the country.

## `countries` (type: `array`):

Filter to goods from these countries, for example China, Vietnam, South Korea. Commerce writes country names several ways and they are normalised before matching.

## `dutyType` (type: `string`):

Antidumping targets selling below fair value. Countervailing targets foreign subsidies. Many products are subject to both at once.

## `stages` (type: `array`):

Narrow to specific kinds of action. Leave empty for all of them. Note that reviewRescinded ends a review, not the order, while orderRevoked ends the order itself.

## `dateFrom` (type: `string`):

Earliest publication date as YYYY-MM-DD. In cases mode a narrow window can hide the order notice itself, which shows up as a status of activeOrderInferred.

## `dateTo` (type: `string`):

Latest publication date as YYYY-MM-DD.

## `onlyActiveOrders` (type: `boolean`):

Cases mode only. Drops revoked orders, negative determinations and open investigations, leaving the cases that cost money today.

## `includeOmnibusNotices` (type: `boolean`):

Commerce publishes round-up notices listing dozens of unrelated cases, such as scope ruling lists and the monthly opportunity to request a review. They are part of a case history but never set its status.

## `newOnly` (type: `boolean`):

Remember what has already been returned and emit only what is new. Run it daily to catch an order, revocation or rate change on your products the day it publishes. Quiet runs cost nothing.

## `maxRows` (type: `integer`):

Stop after this many rows. Case rows cost several requests each, so keep this modest in cases mode.

## Actor input object example

```json
{
  "mode": "notices",
  "searchTerms": [
    "aluminum extrusions"
  ],
  "caseNumbers": [],
  "countries": [],
  "dutyType": "both",
  "stages": [],
  "onlyActiveOrders": false,
  "includeOmnibusNotices": false,
  "newOnly": false,
  "maxRows": 100
}
```

# 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 = {
    "mode": "notices",
    "searchTerms": [
        "aluminum extrusions"
    ],
    "caseNumbers": [],
    "countries": [],
    "dutyType": "both",
    "stages": [],
    "dateFrom": "",
    "dateTo": "",
    "maxRows": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapemint/antidumping-duty-tracker").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 = {
    "mode": "notices",
    "searchTerms": ["aluminum extrusions"],
    "caseNumbers": [],
    "countries": [],
    "dutyType": "both",
    "stages": [],
    "dateFrom": "",
    "dateTo": "",
    "maxRows": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("scrapemint/antidumping-duty-tracker").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "mode": "notices",
  "searchTerms": [
    "aluminum extrusions"
  ],
  "caseNumbers": [],
  "countries": [],
  "dutyType": "both",
  "stages": [],
  "dateFrom": "",
  "dateTo": "",
  "maxRows": 100
}' |
apify call scrapemint/antidumping-duty-tracker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapemint/antidumping-duty-tracker"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/c0CxQxEjceyGTU1xZ/builds/51abss55cswn5gOaO/openapi.json
