<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: InvoiceTariff</title>
    <description>The latest articles on DEV Community by InvoiceTariff (@invoicetariff).</description>
    <link>https://dev.to/invoicetariff</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4104428%2Fcdbd76b6-700c-4b0b-9a42-c0b5dfafd98f.png</url>
      <title>DEV Community: InvoiceTariff</title>
      <link>https://dev.to/invoicetariff</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/invoicetariff"/>
    <language>en</language>
    <item>
      <title>Free Certificate of Origin Generator: General CoO + USMCA, Straight From Your Invoice Data</title>
      <dc:creator>InvoiceTariff</dc:creator>
      <pubDate>Sun, 01 Nov 2026 12:11:11 +0000</pubDate>
      <link>https://dev.to/invoicetariff/free-certificate-of-origin-generator-general-coo-usmca-straight-from-your-invoice-data-36m0</link>
      <guid>https://dev.to/invoicetariff/free-certificate-of-origin-generator-general-coo-usmca-straight-from-your-invoice-data-36m0</guid>
      <description>&lt;p&gt;If you sell across borders, you have probably hit this moment: the goods are packed, the commercial invoice is done, and then the consignee or customs broker asks for one more document — a certificate of origin.&lt;/p&gt;

&lt;p&gt;We built a free generator for it: fill it in your browser, export a PDF. It covers the two formats shippers are actually asked for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;General certificate of origin&lt;/strong&gt; — the standard form accepted for most destinations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;USMCA certification of origin&lt;/strong&gt; — the nine certification fields per 19 CFR 182.12 laid out as plain inputs: originator, exporter, producer, importer, description and HS code, origin criterion, blanket period, signature and date.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The part that saves real time: product lines can come straight from your commercial invoice data, HS codes included — no retyping. The finished certificate exports as a print-ready PDF, and if your broker prefers intake forms, blank templates are free to download in PDF, XLSX and DOCX.&lt;/p&gt;

&lt;p&gt;Find it in the free Invoice x Tariff trade toolkit, next to the tariff rate calculator and HS/HTS code lookup:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://invoicetariff.com/en/certificate-of-origin" rel="noopener noreferrer"&gt;https://invoicetariff.com/en/certificate-of-origin&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ecommerce</category>
      <category>logistics</category>
      <category>smallbusiness</category>
      <category>business</category>
    </item>
    <item>
      <title>I Packaged Our Tariff Engine for npm — Versioned Data, Zero Dependencies, and Trusted Publishing</title>
      <dc:creator>InvoiceTariff</dc:creator>
      <pubDate>Sun, 01 Nov 2026 12:04:32 +0000</pubDate>
      <link>https://dev.to/invoicetariff/i-packaged-our-tariff-engine-for-npm-versioned-data-zero-dependencies-and-trusted-publishing-1gei</link>
      <guid>https://dev.to/invoicetariff/i-packaged-our-tariff-engine-for-npm-versioned-data-zero-dependencies-and-trusted-publishing-1gei</guid>
      <description>&lt;p&gt;Shipping data inside a code package is supposed to be an anti-pattern. Data goes in databases, or S3 buckets, or API responses; packages ship &lt;em&gt;logic&lt;/em&gt;. We spent October deliberately violating that rule: our npm package &lt;code&gt;us-tariff-lookup&lt;/code&gt; bundles a 452KB minified ruleset — every US import tariff layer we track, with legal citations — next to the TypeScript that queries it.&lt;/p&gt;

&lt;p&gt;This is the story of why the violation is the feature, how the data gets into the bundle without leaking our internal docs, and what publishing through npm's staging-and-Trusted-Publishing pipeline actually felt like from the outside. (The engine itself is a hundred-odd KB of TypeScript across nine files — the data outweighs the logic by 4:1, which is the point.)&lt;/p&gt;

&lt;h2&gt;
  
  
  The case for shipping the data
&lt;/h2&gt;

&lt;p&gt;US tariff math has a reproducibility problem. The rules changed roughly five times a month through 2026 — new Section 301 tiers, sector measures, fee schedules — and every change retroactively makes your old quotes look wrong. If your pricing page computes duty by calling a rate API, you can never answer the question that arrives three months later: &lt;em&gt;"what rules were you on when you quoted this?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So we inverted the design. The package ships one versioned seed — &lt;code&gt;rulesetVersion&lt;/code&gt; and &lt;code&gt;dataAsOf&lt;/code&gt; right in the JSON — and the engine is a set of pure functions over it. Same input, same output, forever, until you consciously upgrade. No API key, no network calls, no per-quote billing, and &lt;code&gt;dataAsOf&lt;/code&gt; travels with every result so an auditor can replay the number.&lt;/p&gt;

&lt;p&gt;The cost of that choice is real: updates are a release, not a deploy. We think that's the correct trade for something people use to &lt;em&gt;sign quotes&lt;/em&gt;. Your CI pins the version; your quotes stay explainable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pure functions over one seed
&lt;/h2&gt;

&lt;p&gt;The engine surface is deliberately boring:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rulesetSeed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;searchHts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;calculateLandedCost&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;us-tariff-lookup&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;searchHts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rulesetSeed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;t-shirt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// EN + 中文 keyword search&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculateLandedCost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rulesetSeed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;hts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;61091000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;originCountry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CN&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;entryDate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2026-10-21&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sea&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;units&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;calculateLandedCost&lt;/code&gt; returns layers, not a number:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json-doc"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"totalDuty"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;7394.28&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"effectiveTaxRate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;36.97&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"layers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mfn"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nl"&gt;"rateLabel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"16.5%"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"legalBasis"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HTS Column 1 general rate"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"china301"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"rateLabel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"7.5%"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"chapter99"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"9903.88"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"global301"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"rateLabel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"12.5%"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"litigation"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"fees"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;/* MPF, HMF with statutory citations */&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"warnings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;/* live caveats, e.g. fee table pending verification */&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every layer carries its &lt;code&gt;legalBasis&lt;/code&gt;, a &lt;code&gt;source&lt;/code&gt; URL (USITC / USTR / Federal Register), and a &lt;code&gt;status&lt;/code&gt;. That's not documentation generosity — it's the data model. When one layer is in litigation and the others hold, a flattened percentage can't tell you which part of your number is shaking.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bitemporal by necessity
&lt;/h2&gt;

&lt;p&gt;The awkward lesson of 2026 trade policy: &lt;em&gt;when&lt;/em&gt; a shipment entered decides what it pays. The same HTS code answers differently on either side of a layer's effective date. So &lt;code&gt;entryDate&lt;/code&gt; is a calculation input, not metadata — the engine is bitemporal (rules-date × entry-date), and it refuses dates outside &lt;code&gt;dataAsOf + 90 days&lt;/code&gt; with the exact ceiling in the error message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Entry date cannot be later than 2027-01-05 (today + 90 days)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Monthly package updates slide that window forward. The 90-day horizon isn't a technical limit — it's honesty about how far ahead the rules actually exist.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting 452KB of data into the bundle without leaking
&lt;/h2&gt;

&lt;p&gt;The data pipeline has one hard rule: &lt;strong&gt;the published artifact is built only from public, cleaned data.&lt;/strong&gt; Our working copies of the ruleset carry internal document references in &lt;code&gt;meta.baseline&lt;/code&gt; — research notes, strategy doc paths. Private documentation is fine; a public npm tarball containing internal docs paths is not.&lt;/p&gt;

&lt;p&gt;The build is a thin esbuild script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;entryPoints&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;here&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;..&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;..&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;engine&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
  &lt;span class="na"&gt;bundle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;esm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;platform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;neutral&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node18&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;minify&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;outfile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index.mjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;platform: 'neutral'&lt;/code&gt; keeps Node built-ins out of the bundle graph, minified ruleset JSON inlines into the output, and a hand-written CLI (&lt;code&gt;bin: us-tariff&lt;/code&gt;) gets copied in as a separate file. Tarball: 96KB. Dependencies: zero.&lt;/p&gt;

&lt;p&gt;The incident that wrote the rule: our first build bundled the working-copy JSON, and a pre-publish grep caught internal paths sitting in the seed's metadata. We rebuilt from the public clean source (the &lt;code&gt;us-tariff-rates-2026&lt;/code&gt; repo), re-verified the three reference calculations digit-for-digit, and made "build only from the public snapshot" a script-level invariant instead of a memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Publishing: staging, tokens, and an OIDC cliff
&lt;/h2&gt;

&lt;p&gt;npm's flow for a first-time publisher turned out to be sensibly paranoid: publish to staging, a human approves, then it goes live. Our 0.1.0 sat in staging until a manual approval clicked it out on October 10.&lt;/p&gt;

&lt;p&gt;The token zoo is where we lost an afternoon. Granular publish tokens now start with &lt;code&gt;npm_&lt;/code&gt; — our incident notes from an older automation assumed a different prefix and simply never matched. And npm's new Trusted Publishing (OIDC: tag a release, CI publishes without a long-lived token) needs your GitHub side configured too — our PAT turns out to lack the &lt;code&gt;workflow&lt;/code&gt; scope, so the release workflow file couldn't be pushed by automation and the OIDC loop stays unverified for now. 0.1.1 will be the first tag-driven release; if the OIDC path works, the long-lived token gets revoked the same day. (Manual 2FA steps are exactly the parts we refuse to script around.)&lt;/p&gt;

&lt;h2&gt;
  
  
  What we'd tell ourselves in September
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ship the version, not just the data.&lt;/strong&gt; &lt;code&gt;rulesetVersion&lt;/code&gt; + &lt;code&gt;dataAsOf&lt;/code&gt; in every response has already paid for itself in support threads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grep the artifact like it's untrusted.&lt;/strong&gt; The tarball is a public surface; treat internal strings as a leak class, not a style issue.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bitemporal isn't gold-plating.&lt;/strong&gt; It's the minimum model for rules that change under you — one date field turned every "why did the rate change" question into a five-minute answer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Known limits, stated plainly:&lt;/strong&gt; the bundled search covers 484 curated high-frequency codes (the full 5,689-line HTS ships separately), most rate lines carry explicit &lt;code&gt;sample&lt;/code&gt;/&lt;code&gt;unverified&lt;/code&gt; flags, and multi-word search queries don't tokenize yet — that fix rides the next release.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want the consumer side — &lt;code&gt;npm install&lt;/code&gt; to a working landed-cost endpoint in Express or Next — that's &lt;a href="https://dev.to/invoicetariff/add-us-import-tariff-math-to-your-app-in-5-minutes-with-us-tariff-lookup-43lc"&gt;the integration tutorial&lt;/a&gt;. And the raw data, free without any package, is &lt;a href="https://dev.to/invoicetariff/open-us-tariff-datasets-you-can-actually-build-with-2026-5689-hts-codes-60-country-tiers-and-4831"&gt;the datasets post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Numbers in this post come from &lt;a href="mailto:us-tariff-lookup@0.1.0"&gt;us-tariff-lookup@0.1.0&lt;/a&gt; (ruleset v0.3.4, as of 2026-10-07). Estimates for planning only — not legal advice; your customs broker signs the entry.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install us-tariff-lookup&lt;/code&gt; — zero dependencies, versioned data bundled, MIT licensed. Source on &lt;a href="https://github.com/invoicetariff/us-tariff-lookup" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;; the web calculator lives at &lt;a href="https://invoicetariff.com" rel="noopener noreferrer"&gt;invoicetariff.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>node</category>
      <category>opensource</category>
      <category>engineering</category>
    </item>
    <item>
      <title>Add US Import Tariff Math to Your App in 5 Minutes with us-tariff-lookup</title>
      <dc:creator>InvoiceTariff</dc:creator>
      <pubDate>Wed, 21 Oct 2026 03:33:05 +0000</pubDate>
      <link>https://dev.to/invoicetariff/add-us-import-tariff-math-to-your-app-in-5-minutes-with-us-tariff-lookup-43lc</link>
      <guid>https://dev.to/invoicetariff/add-us-import-tariff-math-to-your-app-in-5-minutes-with-us-tariff-lookup-43lc</guid>
      <description>&lt;p&gt;If you build commerce software — a storefront, a shipping quotes page, a margin calculator — US import tariffs are the cost input most likely to make your numbers wrong. Not because any single rate is complicated, but because the answer is never &lt;em&gt;one&lt;/em&gt; rate. A cotton T-shirt from China in October 2026 stacks four duty layers plus two entry fees: a 16.5% MFN base, 7.5% from a Section 301 list, 12.5% from the new global Section 301 tier, then MPF and HMF on top. Do the math with one lookup table and your quote is off by half.&lt;/p&gt;

&lt;p&gt;Getting the &lt;em&gt;right&lt;/em&gt; number usually means an API key, a per-call bill, and a network dependency. We took a different route with &lt;code&gt;us-tariff-lookup&lt;/code&gt;: the versioned ruleset ships &lt;strong&gt;inside the package&lt;/strong&gt; (zero dependencies, no API key, no network calls), and every duty line carries its legal basis and source. This post walks from &lt;code&gt;npm install&lt;/code&gt; to a working landed-cost endpoint.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install, then look around
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;us-tariff-lookup     &lt;span class="c"&gt;# the library&lt;/span&gt;
npx us-tariff meta               &lt;span class="c"&gt;# or kick the tires without installing anything&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;meta&lt;/code&gt; tells you what's inside:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rulesetVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.3.4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dataAsOf"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-10-07"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"coverage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"mfnCuratedCodes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;484&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"china301Lines"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"global301Tiers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"section232Measures"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"changelogEntries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;57&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"disclaimer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Estimates for planning only — not legal advice. …"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two numbers to notice: &lt;code&gt;rulesetVersion&lt;/code&gt; (the ruleset ships with the package, so results are &lt;strong&gt;deterministic and reproducible&lt;/strong&gt; — the same input gives the same answer until you upgrade) and &lt;code&gt;dataAsOf&lt;/code&gt; (the snapshot date).&lt;/p&gt;

&lt;p&gt;The CLI covers the whole surface. Find a code by English or Chinese keyword:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npx us-tariff search t-shirt
&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"rulesetVersion"&lt;/span&gt;: &lt;span class="s2"&gt;"0.3.4"&lt;/span&gt;,
  &lt;span class="s2"&gt;"dataAsOf"&lt;/span&gt;: &lt;span class="s2"&gt;"2026-10-07"&lt;/span&gt;,
  …
  &lt;span class="s2"&gt;"count"&lt;/span&gt;: 1,
  &lt;span class="s2"&gt;"hits"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;"hts8"&lt;/span&gt;: &lt;span class="s2"&gt;"61091000"&lt;/span&gt;,
      &lt;span class="s2"&gt;"description"&lt;/span&gt;: &lt;span class="s2"&gt;"T-shirts, singlets and other vests, knitted, of cotton"&lt;/span&gt;,
      &lt;span class="s2"&gt;"mfnGeneral"&lt;/span&gt;: &lt;span class="s2"&gt;"16.5%"&lt;/span&gt;,
      &lt;span class="s2"&gt;"matchedBy"&lt;/span&gt;: &lt;span class="s2"&gt;"en"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;npx us-tariff search 保温杯        &lt;span class="c"&gt;# works in Chinese too&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"count"&lt;/span&gt;: 1, &lt;span class="s2"&gt;"hits"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"hts8"&lt;/span&gt;: &lt;span class="s2"&gt;"96170010"&lt;/span&gt;, &lt;span class="s2"&gt;"mfnGeneral"&lt;/span&gt;: &lt;span class="s2"&gt;"10%"&lt;/span&gt;, &lt;span class="s2"&gt;"matchedBy"&lt;/span&gt;: &lt;span class="s2"&gt;"zh"&lt;/span&gt;, … &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;…a stacked calculation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npx us-tariff calc &lt;span class="nt"&gt;--hts&lt;/span&gt; 61091000 &lt;span class="nt"&gt;--value&lt;/span&gt; 20000 &lt;span class="nt"&gt;--origin&lt;/span&gt; CN &lt;span class="nt"&gt;--mode&lt;/span&gt; sea &lt;span class="nt"&gt;--units&lt;/span&gt; 5000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;…recent rule changes (&lt;code&gt;changelog&lt;/code&gt;), and which post-IEEPA refund window applies to a given entry date (&lt;code&gt;refund --entry-date 2026-03-01&lt;/code&gt;). Everything prints JSON with the version and disclaimer attached.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "stacked" actually looks like
&lt;/h2&gt;

&lt;p&gt;Here's the calc result for the T-shirt order — $20,000 declared value, sea freight, 5,000 units — trimmed to the parts that matter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json-doc"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"totalDuty"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;7394.28&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"landedTotal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;27394.28&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"effectiveTaxRate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;36.97&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;// percent of declared value, all-in&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"layers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mfn"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nl"&gt;"rateLabel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"16.5%"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"legalBasis"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HTS Column 1 general rate"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"china301"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"rateLabel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"7.5%"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"chapter99"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"9903.88"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"global301"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"rateLabel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"12.5%"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"litigation"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"fees"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"hmf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;25.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"basis"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"26 U.S.C. §4461 … (sea &amp;amp; water shipments only)"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mpf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;69.28&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"basis"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"19 U.S.C. §58c, FY2027 (from 2026-10-01)"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"warnings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"The fee schedule for this date (FY2027) is pending verification against the Federal Register; CBP bulletins prevail."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"The global 301 layer is in litigation — CBP enforcement prevails."&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;More than half of that total — $4,000 of the $7,394.28 — is the two Section 301 layers, and neither of them touches the "duty rate" column of most product catalogs. &lt;code&gt;layers&lt;/code&gt; is an array, not a number, because that's what the law is. Each layer carries &lt;code&gt;legalBasis&lt;/code&gt;, a &lt;code&gt;source&lt;/code&gt; URL (USITC / USTR / Federal Register), and a &lt;code&gt;status&lt;/code&gt; — note &lt;code&gt;litigation&lt;/code&gt; on the global tier. If your UI flattens this to a single percentage, you're not wrong &lt;em&gt;yet&lt;/em&gt;, but you can't explain &lt;em&gt;why&lt;/em&gt; when a customer asks, and you can't react when one layer changes while the others hold.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wire it into an API (Express)
&lt;/h2&gt;

&lt;p&gt;This is a complete, runnable server — it's the exact code I tested against the published package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// server.mjs  —  node server.mjs&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rulesetSeed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;searchHts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;calculateLandedCost&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;us-tariff-lookup&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;DISCLAIMER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Estimates for planning only — not legal advice. Your customs broker signs the entry, not this tool.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;todayISO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// GET /api/hts/search?q=t-shirt&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/hts/search&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;searchHts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rulesetSeed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;hts8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hts8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;general&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;general&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;matchedBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;matchedBy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}));&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;dataAsOf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rulesetSeed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;asOf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;hits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hits&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// GET /api/landed-cost?hts=61091000&amp;amp;value=20000&amp;amp;origin=CN&amp;amp;mode=sea&amp;amp;units=5000&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/landed-cost&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;hts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hts&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;originCountry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CN&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;entryDate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;todayISO&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sea&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;units&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;units&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculateLandedCost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rulesetSeed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;rulesetVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rulesetSeed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;dataAsOf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rulesetSeed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;asOf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;disclaimer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DISCLAIMER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;totalDuty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;totalDuty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;effectiveTaxRate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;effectiveTaxRate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
      &lt;span class="na"&gt;landedTotal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;landedTotal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;perUnit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;perUnit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
      &lt;span class="na"&gt;warnings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;warnings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rateLabel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;})),&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;invalid request&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;disclaimer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DISCLAIMER&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8787&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;listening on :8787&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Real responses, first the happy path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ curl "http://localhost:8787/api/landed-cost?hts=61091000&amp;amp;value=20000&amp;amp;origin=CN&amp;amp;mode=sea&amp;amp;units=5000"
{
  "rulesetVersion": "0.3.4",
  "dataAsOf": "2026-10-07",
  "totalDuty": 7394.28,
  "effectiveTaxRate": 36.97,
  "landedTotal": 27394.28,
  "perUnit": 5.48,
  "warnings": ["The fee schedule …", "The global 301 layer is in litigation …"],
  "layers": [ … ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;…and the failure path, which is where most tariff integrations go wrong quietly. An unknown HTS code doesn't return zeros — it throws a descriptive error you can surface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ curl "http://localhost:8787/api/landed-cost?hts=99999999&amp;amp;value=100"
{"error":"HTS 99999999 was not found in the local tariff library — try an English
keyword or paste an 8/10-digit code","disclaimer":"…"}          // HTTP 400
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same call works in a Next.js App Router route with no other changes to the engine part:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app/api/landed-cost/route.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rulesetSeed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;calculateLandedCost&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;us-tariff-lookup&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nextUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchParams&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculateLandedCost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rulesetSeed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;hts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;value&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;originCountry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;origin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CN&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;entryDate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mode&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sea&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;as &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sea&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;air&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;postal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;units&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;units&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;rulesetVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rulesetSeed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;dataAsOf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rulesetSeed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;asOf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three API notes that will save you an afternoon:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The package is ESM-only&lt;/strong&gt; (&lt;code&gt;"type": "module"&lt;/code&gt;, Node ≥ 18) — use &lt;code&gt;import&lt;/code&gt;, not &lt;code&gt;require&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;entryDate&lt;/code&gt; is part of the calculation, not metadata.&lt;/strong&gt; The engine is bitemporal: the same HTS code answers differently depending on when it entered the port. It must be within &lt;code&gt;dataAsOf + 90 days&lt;/code&gt;, and the error tells you the exact ceiling (&lt;code&gt;Entry date cannot be later than 2027-01-05 (today + 90 days)&lt;/code&gt;). Monthly package updates slide that window forward.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;mode&lt;/code&gt; is &lt;code&gt;sea | air | express | postal&lt;/code&gt;&lt;/strong&gt; — HMF applies to sea only, and postal shipments ≤ $2,500 use informal-entry flat fees. Passing the transport mode isn't cosmetic; it changes the fees.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Sanity-check it against real SKUs
&lt;/h2&gt;

&lt;p&gt;Three real-ish order lines (all China origin, October 2026), run through the same &lt;code&gt;calculateLandedCost&lt;/code&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;SKU&lt;/th&gt;
&lt;th&gt;HTS&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Duty+fees&lt;/th&gt;
&lt;th&gt;Effective rate&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;TEE-BLK-M (cotton tees)&lt;/td&gt;
&lt;td&gt;61091000&lt;/td&gt;
&lt;td&gt;$20,000&lt;/td&gt;
&lt;td&gt;sea&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$7,394.28&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;36.97%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LAP-14 (laptops)&lt;/td&gt;
&lt;td&gt;84713001&lt;/td&gt;
&lt;td&gt;$50,000&lt;/td&gt;
&lt;td&gt;air&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$6,423.20&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;12.85%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BATT-PACK (Li-ion packs)&lt;/td&gt;
&lt;td&gt;85076000&lt;/td&gt;
&lt;td&gt;$18,000&lt;/td&gt;
&lt;td&gt;air&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$7,424.35&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;41.25%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The middle row is the one people don't believe. Laptops have a &lt;code&gt;Free&lt;/code&gt; MFN rate and sit on no China list — and they still cost 12.85% all-in, purely from the global tier plus MPF. If your pricing engine models "China = 301 list or nothing," laptop SKUs are where it silently leaks. (We go deeper on the pandas side in &lt;a href="https://dev.to/invoicetariff/open-us-tariff-datasets-you-can-actually-build-with-2026-5689-hts-codes-60-country-tiers-and-4831"&gt;the datasets post&lt;/a&gt;.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Show the version — your users will thank you
&lt;/h2&gt;

&lt;p&gt;The most important field in every response is the pair &lt;code&gt;rulesetVersion&lt;/code&gt; + &lt;code&gt;dataAsOf&lt;/code&gt;, and the worst thing you can do is swallow it. Trade rules move about five times a month right now; when a customer compares your quote to their customs broker's entry, the first question is &lt;em&gt;"which rules were you on?"&lt;/em&gt; Three habits that cost nothing:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Render the disclaimer where the number is&lt;/strong&gt;, not in a footer: the package hands you the exact string (&lt;code&gt;Estimates for planning only — not legal advice…&lt;/code&gt;) — pass it through.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Surface &lt;code&gt;warnings&lt;/code&gt; next to the total.&lt;/strong&gt; Two of the current layers carry live caveats (the FY2027 fee table is pending Federal Register verification; the global 301 tier is in litigation). Hiding them turns your app into the weak link when the case resolves.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Log the version with every quote.&lt;/strong&gt; When rates change and someone audits last quarter's numbers, &lt;code&gt;rulesetVersion&lt;/code&gt; is the difference between a five-minute answer and an archaeology project.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Honest limits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The bundled search covers 484 curated high-frequency codes&lt;/strong&gt;, not the full 5,689-line HTS — the full table ships separately in the &lt;a href="https://github.com/invoicetariff/hs-codes-database" rel="noopener noreferrer"&gt;hs-codes-database&lt;/a&gt; repo, and &lt;code&gt;searchHts&lt;/code&gt; returning nothing means "outside the curated set," not "doesn't exist."&lt;/li&gt;
&lt;li&gt;Most v0.3.x rate lines carry &lt;code&gt;sample&lt;/code&gt;/&lt;code&gt;unverified&lt;/code&gt; flags: fine for pricing scenarios, quotes, and demos; your customs broker still signs the actual entry.&lt;/li&gt;
&lt;li&gt;Multi-word search queries ("cotton t-shirt") don't tokenize yet — single tokens ("t-shirt") are the reliable form until the next release.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you'd rather watch the feed than do the math, &lt;a href="https://dev.to/invoicetariff/build-your-own-tariff-change-radar-in-70-lines-of-python-the-data-is-already-open-169o"&gt;the radar post&lt;/a&gt; builds the change-monitoring side in Python. And if you ship something with the package — a Shopify margin app, an ERP plugin — I'd genuinely like to hear what it needed that the schema doesn't have.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;All output above is from &lt;a href="mailto:us-tariff-lookup@0.1.0"&gt;us-tariff-lookup@0.1.0&lt;/a&gt; (ruleset v0.3.4, as of 2026-10-07). Estimates for planning only — not legal advice; your customs broker signs the entry, not this package.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install us-tariff-lookup&lt;/code&gt; — zero dependencies, no API key, data bundled. MIT licensed, source on &lt;a href="https://github.com/invoicetariff/us-tariff-lookup" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;; the web calculator is at &lt;a href="https://invoicetariff.com" rel="noopener noreferrer"&gt;invoicetariff.com&lt;/a&gt;. Prefer a tutorial you can keep open while you code? The same walkthrough lives on our site at &lt;code&gt;invoicetariff.com/tutorials/npm-package&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next in the series: &lt;a href="https://dev.to/invoicetariff/i-packaged-our-tariff-engine-for-npm-versioned-data-zero-dependencies-and-trusted-publishing-1gei"&gt;I Packaged Our Tariff Engine for npm — Versioned Data, Zero Dependencies, and Trusted Publishing&lt;/a&gt; — the inside story of why the data ships inside the package, and what npm's staging-and-Trusted-Publishing pipeline felt like from the outside.&lt;/p&gt;

</description>
      <category>node</category>
      <category>typescript</category>
      <category>ecommerce</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Build Your Own Tariff Change Radar in ~70 Lines of Python (the Data Is Already Open)</title>
      <dc:creator>InvoiceTariff</dc:creator>
      <pubDate>Sun, 18 Oct 2026 14:27:53 +0000</pubDate>
      <link>https://dev.to/invoicetariff/build-your-own-tariff-change-radar-in-70-lines-of-python-the-data-is-already-open-169o</link>
      <guid>https://dev.to/invoicetariff/build-your-own-tariff-change-radar-in-70-lines-of-python-the-data-is-already-open-169o</guid>
      <description>&lt;h1&gt;
  
  
  Build Your Own Tariff Change Radar in ~70 Lines of Python (the Data Is Already Open)
&lt;/h1&gt;

&lt;p&gt;Tariff rates don't sneak up on anyone — tariff &lt;em&gt;changes&lt;/em&gt; do. In 2026 the US trade-policy stack has been moving roughly five times a month: we track every published change in a machine-readable changelog, and the current snapshot holds &lt;strong&gt;57 entries, 54 of them dated in 2026 alone&lt;/strong&gt; — Section 232 measures stacking up (furniture 25%, timber 10%, pharma 20%, semiconductors 25%), the global Section 301 program going live, China exclusions expiring, the FY2027 fee table resetting MPF.&lt;/p&gt;

&lt;p&gt;If you price imports, every one of those is a real-money event you find out about either from a feed like this one — or from the customs invoice. This post builds the first kind: a change radar that runs from cron, watches an open dataset, and pings a webhook when the stack moves. No scraping, no HTML parsing, no API keys. About seventy lines of Python.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why watch a git repo instead of scraping the source?
&lt;/h2&gt;

&lt;p&gt;The raw sources are hostile to automation. Federal Register notices are prose; exclusion lists ship as PDF attachments; CBP publishes CSMS messages on a page that assumes a human is reading it. Parsing all that is a full-time job — it's literally the product we built, and &lt;a href="https://invoicetariff.com/radar" rel="noopener noreferrer"&gt;the public radar&lt;/a&gt; is its front end.&lt;/p&gt;

&lt;p&gt;But once the parsing is done once, the &lt;em&gt;output&lt;/em&gt; is just data. So we publish it: &lt;a href="https://github.com/invoicetariff/invoicetariff" rel="noopener noreferrer"&gt;github.com/invoicetariff/invoicetariff&lt;/a&gt; carries &lt;code&gt;data/changelog.json&lt;/code&gt; — one JSON entry per tracked change:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json-doc"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-10-01-fy2027-fees"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="c1"&gt;// date-prefixed, unique&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-10-01"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"layer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fees"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;                          &lt;/span&gt;&lt;span class="c1"&gt;// mfn | china301 | global301 | section232 | section338 | ieepa | fees&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"published"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="c1"&gt;// or "upcoming" for scheduled changes&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="c1"&gt;// bilingual: 中文 original&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"titleEn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"In effect: FY2027 MPF min/max increase (from 2026-10-01)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"summary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"91 FR 48398"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://www.federalregister.gov/..."&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three properties make this watchable:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Git is the transport.&lt;/strong&gt; &lt;code&gt;git pull&lt;/code&gt; is a more reliable API than most APIs — resumable, cacheable, proxy-friendly, and rate-limit-free.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;status&lt;/code&gt; splits the timeline.&lt;/strong&gt; &lt;code&gt;published&lt;/code&gt; entries are in effect; &lt;code&gt;upcoming&lt;/code&gt; entries are scheduled (the China exclusions expiry on 2026-11-10, the extended truce deadline on 2027-01-10). A radar that only reports the past is half a radar.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The repo ships the ruleset itself&lt;/strong&gt; (&lt;code&gt;ruleset-seed.json&lt;/code&gt;, versioned monthly, currently v0.3.4), so the notification can also tell you which version your last analysis ran against.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The script
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;tariff-radar.py — get notified when the open US tariff ruleset changes.

Data: https://github.com/invoicetariff/invoicetariff (data/changelog.json)
Usage: python3 tariff-radar.py [--webhook https://hooks.slack.com/services/XXX]
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;urllib.request&lt;/span&gt;

&lt;span class="n"&gt;REPO_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://github.com/invoicetariff/invoicetariff&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;HERE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__file__&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;
&lt;span class="n"&gt;REPO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HERE&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;invoicetariff&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;STATE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HERE&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tariff-radar.state.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;LAYERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;span class="n"&gt;WEBHOOK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--webhook&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--webhook&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;capture_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;refresh_repo&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;REPO&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.git&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="nf"&gt;sh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;git&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;clone&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--depth&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;REPO_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;REPO&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;sh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;git&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-C&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;REPO&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pull&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--ff-only&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nf"&gt;refresh_repo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;entries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;REPO&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;changelog.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;entries&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;REPO&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ruleset-seed.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;version&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# State = the set of entry ids already seen. NOT "the last entry":
&lt;/span&gt;    &lt;span class="c1"&gt;# the feed interleaves future-dated `upcoming` items with `published`
&lt;/span&gt;    &lt;span class="c1"&gt;# ones, so the last row is not the newest, and a max-id state would
&lt;/span&gt;    &lt;span class="c1"&gt;# silently miss entries whose id sorts below an upcoming date.
&lt;/span&gt;    &lt;span class="n"&gt;seen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;STATE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_text&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;STATE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;fresh&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;entries&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;seen&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                   &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;date&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;LAYERS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;fresh&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;fresh&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;layer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;LAYERS&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;fresh&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ruleset v&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: no changes since last check&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;

    &lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Tariff ruleset v&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; - &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fresh&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; new change(s):&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;fresh&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;titleEn&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;- [&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;date&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;] &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;layer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;upper&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;): &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;WEBHOOK&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;1900&lt;/span&gt;&lt;span class="p"&gt;]}).&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="c1"&gt;# Discord; Slack: {"text": ...}
&lt;/span&gt;        &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WEBHOOK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                     &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;STATE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seen&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;})))&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First run against today's snapshot, it prints all 57 entries, tail like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Tariff ruleset v0.3.4 - 57 new change(s):
- [2025-10-01] FEES (published): FY2026 MPF/HMF fee schedule effective (CSMS #65741993)
  ...
- [2026-10-08] MFN (published): ITC institution of Section 337 investigation: certain mobile
  electronic devices and components thereof (337-TA-1525, trinamiX v. Apple) (procedural)
- [2026-11-10] CHINA301 (upcoming): Upcoming: China Section 301 product exclusions expire (2026-11-10)
- [2026-11-30] MFN (upcoming): Upcoming: NHTSA SAFE Vehicles Rule III — CAFE fuel-economy
  standards recalibrated (from 2026-11-30; non-tariff notice)
- [2027-01-10] CHINA301 (upcoming): Upcoming: China truce extended to 2027-01-10 (announced 2026-09-23, FR pending)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every run after that prints only what's new, and exits quietly when nothing changed — which is what you want from a cron job.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one bug you'd have written anyway
&lt;/h2&gt;

&lt;p&gt;The tempting version of the state is "remember the id of the last entry, report everything after it." It works — until the first time it doesn't. The feed interleaves &lt;code&gt;upcoming&lt;/code&gt; entries whose ids are &lt;strong&gt;future&lt;/strong&gt; dates (&lt;code&gt;2027-01-10-…&lt;/code&gt;) between &lt;code&gt;published&lt;/code&gt; ones (&lt;code&gt;2026-10-08-…&lt;/code&gt;). So:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;em&gt;last row&lt;/em&gt; of the file is not the newest entry, and&lt;/li&gt;
&lt;li&gt;once your state holds &lt;code&gt;2027-01-10-…&lt;/code&gt; as the high-water mark, a new published entry like &lt;code&gt;2026-11-05-…&lt;/code&gt; sorts &lt;em&gt;below&lt;/em&gt; it and is &lt;strong&gt;silently never reported&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The fix is the boring one: persist the &lt;strong&gt;set of seen ids&lt;/strong&gt; instead of a cursor. It costs a few lines and turns a silent failure mode into a non-event. (This is also why the script sorts by &lt;code&gt;(date, id)&lt;/code&gt; for display — publication order in the file is append order, not chronological.)&lt;/p&gt;

&lt;p&gt;Filter it to the layers you actually price against — say China lists and fees:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 tariff-radar.py &lt;span class="s2"&gt;"china301,fees"&lt;/span&gt; &lt;span class="nt"&gt;--webhook&lt;/span&gt; https://hooks.slack.com/services/XXX
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;…or run it from cron, weekdays at nine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 9 * * 1-5  cd /opt/tariff-radar &amp;amp;&amp;amp; /usr/bin/python3 tariff-radar.py &amp;gt;&amp;gt; radar.log 2&amp;gt;&amp;amp;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Honest limits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Resolution is monthly.&lt;/strong&gt; The dataset is versioned and updated about monthly (CSV rows and the ruleset carry &lt;code&gt;ruleset_version&lt;/code&gt; / &lt;code&gt;ruleset_asof&lt;/code&gt; stamps), so the radar tells you what changed &lt;em&gt;as of&lt;/em&gt; each refresh — great for pricing strategy and renewal dates, not a breaking-news wire. When the EU announces something at 14:00, you'll read it on the news; when the FY2027 MPF floor lands, you'll have it before your next quote goes out.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It's a feed, not an oracle.&lt;/strong&gt; Entries carry &lt;code&gt;source&lt;/code&gt; links (Federal Register, CSMS, USTR) — the radar tells you &lt;em&gt;that&lt;/em&gt; Section 232 pharma went to 20% and links the notice; whether &lt;em&gt;your&lt;/em&gt; product falls in scope is still an HTS-level question. For that, the &lt;a href="https://invoicetariff.com/tariff-calculator" rel="noopener noreferrer"&gt;stacked calculator&lt;/a&gt; runs the same ruleset per code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Discord vs Slack payloads differ&lt;/strong&gt; (the commented line in the script). Everything else — message shape, state, filters — is yours to fork.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The radar page on the site is this exact idea with a UI on top. But the point of publishing the data is that you don't need our UI: a git repo, a JSON array, a cron entry, and your team's chat channel is a working early-warning system for the most volatile cost input of 2026.&lt;/p&gt;

&lt;p&gt;If you extend it — multi-region watching, per-SKU impact digests, a Grafana panel of layer counts — tell me in the comments or open an issue; the schema is versioned precisely so things like that can outlive this post.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Change data comes from InvoiceTariff changelog.json v0.3.4 (as of 2026-10-07); rate levels shown are estimates from the same snapshot, not legal advice.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The dataset behind this post — 5,689 HTS codes, the 60-country tier table, and the stacked ruleset — is MIT-licensed on GitHub; a companion post walks through analyzing and batch-pricing with it in pandas.&lt;/p&gt;

&lt;p&gt;Update: the parser in this post now ships as an npm package — &lt;code&gt;npm install us-tariff-lookup&lt;/code&gt; (zero dependencies, data bundled). &lt;code&gt;npx us-tariff changelog&lt;/code&gt; prints the same feed without writing the parser, &lt;code&gt;npx us-tariff meta&lt;/code&gt; reports which ruleset version you're on, and in code the entries arrive as a &lt;code&gt;changelogEntries&lt;/code&gt; array (published + upcoming, date-desc) — so the seen-ids state from the bug section above is still yours to keep; the feed just gets delivered. A follow-up post wires the library into a real Express/Next API route: &lt;a href="https://dev.to/invoicetariff/add-us-import-tariff-math-to-your-app-in-5-minutes-with-us-tariff-lookup-43lc"&gt;Add US Import Tariff Math to Your App in 5 Minutes&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>automation</category>
      <category>opensource</category>
      <category>devops</category>
    </item>
    <item>
      <title>Open US Tariff Datasets You Can Actually Build With (2026): 5,689 HTS Codes, 60 Country Tiers, and a Machine-Readable Changelog</title>
      <dc:creator>InvoiceTariff</dc:creator>
      <pubDate>Sat, 10 Oct 2026 04:06:19 +0000</pubDate>
      <link>https://dev.to/invoicetariff/open-us-tariff-datasets-you-can-actually-build-with-2026-5689-hts-codes-60-country-tiers-and-4831</link>
      <guid>https://dev.to/invoicetariff/open-us-tariff-datasets-you-can-actually-build-with-2026-5689-hts-codes-60-country-tiers-and-4831</guid>
      <description>&lt;p&gt;If you've ever tried to compute US import duties programmatically, you know the problem isn't the math — it's the data. The rates live in the USITC Harmonized Tariff Schedule (a website that fights scrapers), the Section 301 lists are PDFs and Federal Register notices, and the fee tables change every fiscal year. Every "tariff calculator" tutorial online ends with &lt;code&gt;MFN_RATE = 0.165  # update manually&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We run &lt;a href="https://invoicetariff.com/tariff-calculator" rel="noopener noreferrer"&gt;a free tariff calculator&lt;/a&gt; and got tired of that, so we publish everything the engine knows as &lt;strong&gt;versioned, MIT-licensed open data&lt;/strong&gt; on GitHub — updated monthly, every rate line carrying its legal basis and source link. In this post I'll walk through what's in the three repos, then build five real things with pandas: analyze the 60-country tariff tiers, slice the China Section 301 lists, batch-price a SKU catalog, detect Section 232 hits, and preview the machine-readable changelog.&lt;/p&gt;

&lt;p&gt;All numbers below come from the current snapshot &lt;strong&gt;v0.3.4 (as of 2026-10-07)&lt;/strong&gt;, and every code snippet was run against it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The repos
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Repo&lt;/th&gt;
&lt;th&gt;What's inside&lt;/th&gt;
&lt;th&gt;Format&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/invoicetariff/invoicetariff" rel="noopener noreferrer"&gt;invoicetariff/invoicetariff&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;The full stacked ruleset &lt;code&gt;ruleset-seed.json&lt;/code&gt; (MFN + 301 + 232 + 338 + IEEPA + fees), &lt;code&gt;changelog.json&lt;/code&gt;, &lt;code&gt;destinations.json&lt;/code&gt;, &lt;code&gt;refund-channels.json&lt;/code&gt;, and three CSV extracts&lt;/td&gt;
&lt;td&gt;JSON + CSV&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/invoicetariff/us-tariff-rates-2026" rel="noopener noreferrer"&gt;invoicetariff/us-tariff-rates-2026&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;The same &lt;code&gt;ruleset-seed.json&lt;/code&gt; as a standalone single-file dataset&lt;/td&gt;
&lt;td&gt;JSON&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/invoicetariff/hs-codes-database" rel="noopener noreferrer"&gt;invoicetariff/hs-codes-database&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;mfn-full.json&lt;/code&gt;: all &lt;strong&gt;5,689&lt;/strong&gt; US HTS 8-digit codes with the official MFN &lt;code&gt;general&lt;/code&gt; rate&lt;/td&gt;
&lt;td&gt;JSON&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/invoicetariff/invoicetariff
git clone https://github.com/invoicetariff/hs-codes-database
git clone https://github.com/invoicetariff/us-tariff-rates-2026   &lt;span class="c"&gt;# optional, same JSON as the main repo&lt;/span&gt;
pip &lt;span class="nb"&gt;install &lt;/span&gt;pandas
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What makes this more than a data dump: every Section 301/232/338/IEEPA/fee line carries a &lt;code&gt;legalBasis&lt;/code&gt; string and a &lt;code&gt;source&lt;/code&gt; object (title + URL — usually the Federal Register notice). When your spreadsheet says "12.5%", you can answer &lt;em&gt;"which document, which paragraph"&lt;/em&gt;. And the whole thing is bilingual — every name field has a &lt;code&gt;nameEn&lt;/code&gt;/Chinese pair, because a lot of cross-border sourcing happens in Chinese.&lt;/p&gt;

&lt;h2&gt;
  
  
  Loading it without the footguns
&lt;/h2&gt;

&lt;p&gt;Two things will bite you in the first five minutes, so let's get them out of the way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;

&lt;span class="n"&gt;ruleset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;invoicetariff/data/ruleset-seed.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;hts&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;invoicetariff/data/us-tariff-ruleset-hts-codes.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8-sig&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="c1"&gt;# the CSVs carry a BOM
&lt;/span&gt;                   &lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hts8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;           &lt;span class="c1"&gt;# see below
&lt;/span&gt;&lt;span class="n"&gt;econ&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;invoicetariff/data/us-tariff-ruleset-economies.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8-sig&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;s232&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;invoicetariff/data/us-tariff-ruleset-section232.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8-sig&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;full&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hs-codes-database/mfn-full.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;hts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hts8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hts8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zfill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;            &lt;span class="c1"&gt;# defensive; cheap insurance
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;encoding="utf-8-sig"&lt;/code&gt;&lt;/strong&gt; — the CSV extracts are UTF-8 with BOM. With plain &lt;code&gt;utf-8&lt;/code&gt;, your first column is silently named &lt;code&gt;\ufeffhts8&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;dtype={"hts8": str}&lt;/code&gt;&lt;/strong&gt; — without it, pandas reads the 8-digit codes as &lt;code&gt;int64&lt;/code&gt;. That's fine until you join against the JSON datasets, where codes are strings, and the merge blows up with a type error. The &lt;code&gt;zfill(8)&lt;/code&gt; matters if you bring your own dataset that includes chapter-01 codes (&lt;code&gt;01012100&lt;/code&gt;, live horses) — those have real leading zeros.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MFN rates are text, not numbers.&lt;/strong&gt; The &lt;code&gt;general&lt;/code&gt; column is the official USITC text: &lt;code&gt;Free&lt;/code&gt;, &lt;code&gt;16.5%&lt;/code&gt;, but also genuinely non-ad-valorem rates like &lt;code&gt;2.1¢/kg + 12%&lt;/code&gt;. Parse defensively:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ad_valorem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;free&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nan&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nan&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;          &lt;span class="c1"&gt;# specific duties (¢/kg, ¢/unit) need quantity data
&lt;/span&gt;
&lt;span class="n"&gt;hts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mfn_pct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mfn_general&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ad_valorem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# in the curated 484-code table: 189 Free, 245 ad-valorem, 50 with a specific-duty component
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That last number is worth internalizing: &lt;strong&gt;one in ten codes can't be priced from value alone&lt;/strong&gt;. If a tool promises you "the duty" from an HTS code and a value without asking for unit weight, it's skipping those.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The 60-country Global 301 program is only two rates
&lt;/h2&gt;

&lt;p&gt;The newest layer — a &lt;em&gt;global&lt;/em&gt; Section 301 program effective 2026-07-24 — assigns every economy a tier rate. Load &lt;code&gt;economies.csv&lt;/code&gt; and the drama collapses into two numbers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;econ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;global301_rate_pct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;value_counts&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;sort_index&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c1"&gt;# 10.0    19     ← 19 countries at 10%
# 12.5    41     ← 41 countries at 12.5% (China sits here, as do the EU, Japan, Korea…)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two tiers, 19 vs 41 countries. The practical takeaway for anyone with a multi-country supply chain: the &lt;em&gt;rate&lt;/em&gt; barely discriminates, but the &lt;strong&gt;combined cap&lt;/strong&gt; (&lt;code&gt;mfn301_combined_cap_pct&lt;/code&gt;) and per-country add-on columns are where countries diverge. Check your origin countries against this table before assuming "country of origin doesn't matter anymore" — for the 301 layer it mostly doesn't, which is exactly why the next dataset matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Slicing the China Section 301 lists
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;ruleset-seed.json → .china301[]&lt;/code&gt; has 25 lines in v0.3.4 — Lists 2/3/4A plus the 2026 four-year-review additions. A three-line pivot tells you where the pain is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;c301&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DataFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ruleset&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;china301&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c301&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;groupby&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hts8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="c1"&gt;# 7.5    12    ← List 4A lines
# 25.0   12    ← List 3 + the 2026 review additions (e.g. lithium batteries 85076000)
# 50.0    1    ← solar cells 85414200, doubled in the review
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Half the lines doubled to 25% during the statutory four-year review, and solar cells went to 50%. If your landed-cost model still says "China 301 = 7.5%", it's describing 2019.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Batch-pricing a SKU catalog (the one most people actually want)
&lt;/h2&gt;

&lt;p&gt;Here's the workflow that earns its keep: you have a product catalog with HTS codes, and you want an all-in duty+fee estimate per SKU. Join the curated CSV with the fee table and the country tier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;fy27&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ruleset&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fees&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fiscalYear&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2027&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# MPF: 0.3464% of value, min $34.58, max $670.86 (FY2027, in effect 2026-10-01)
# HMF: 0.125%, ocean only
&lt;/span&gt;
&lt;span class="n"&gt;skus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DataFrame&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sku&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TEE-BLK-M&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hts8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;61091000&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;units&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unit_value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;4.00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ocean&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sku&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;LAP-14&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hts8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;84713001&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;units&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unit_value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;250.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;air&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sku&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BATT-PACK&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hts8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;85076000&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;units&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unit_value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;18.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;air&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;skus&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;skus&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;units&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;skus&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unit_value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;skus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hts&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hts8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mfn_pct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;china301_rate_pct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hts8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;how&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;left&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;cn_tier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;econ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;econ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;country_code&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;global301_rate_pct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;iloc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;   &lt;span class="c1"&gt;# 12.5
&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mfn_pct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;china301_rate_pct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;_usd&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;fillna&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;global301_usd&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;cn_tier&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mpf_usd&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;fy27&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mpfRate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fy27&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mpfMin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="n"&gt;fy27&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mpfMax&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hmf_usd&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;fy27&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hmfRate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ocean&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;total_usd&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mfn_pct_usd&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;china301_rate_pct_usd&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;global301_usd&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mpf_usd&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hmf_usd&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]].&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eff_pct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;total_usd&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output (China origin, FY2027 fees):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      sku     hts8   value  mfn  301-list  301-global   mpf   hmf  total  eff%
TEE-BLK-M 61091000  20000  3300      1500        2500  69.28  25.0  7394  36.97%
   LAP-14 84713001  50000     0         0        6250 173.20   0.0  6423  12.85%
BATT-PACK 85076000  18000   612      4500        2250  62.35   0.0  7424  41.25%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read the middle row twice. Laptops have a &lt;code&gt;Free&lt;/code&gt; MFN rate and sit on &lt;em&gt;no&lt;/em&gt; China list — yet they cost 12.85% all-in, purely because of the global tier and fees. And lithium-ion battery packs — 2026's four-year-review poster child — stack 3.4% MFN + 25% review list + 12.5% global tier into &lt;strong&gt;41%&lt;/strong&gt;. If you source either, your pricing model needs the stack, not a single rate.&lt;/p&gt;

&lt;p&gt;(Note what this toy model skips: Section 232, exclusions, informal-entry flat fees under $2,500, and the specific-duty codes from earlier. Which brings us to…)&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Detecting Section 232 hits with prefix matching
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;s232.csv&lt;/code&gt; has the 8 active measures — steel/aluminium/copper articles at 50%, autos at 25%, furniture at 25%, pharmaceuticals at 20% (general tier, since 2026-09-29), softwood timber at 10%, semiconductors at 25%. The &lt;code&gt;hts_scope&lt;/code&gt; column mixes 2-digit chapters (&lt;code&gt;73&lt;/code&gt;) with code-prefix lists (&lt;code&gt;847150; 847180; 847330&lt;/code&gt;), so normalize to prefixes and match:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;prefixes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;s232&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hts_scope&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;

&lt;span class="n"&gt;hit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;hts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hts8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;prefixes&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;          &lt;span class="c1"&gt;# 89 of the 484 curated codes are 232-exposed
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the curated set that's 89 codes — 18% — and chapter 30 alone (pharmaceuticals) is a wall of them. If your catalog touches steel, aluminium, copper, autos, timber, furniture, pharma, or semiconductors, a "China-only" tariff model is the wrong model: 232 doesn't care where the goods ship from.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. The changelog is the dataset's killer feature
&lt;/h2&gt;

&lt;p&gt;Rates you can look up. &lt;strong&gt;Changes&lt;/strong&gt; are what blindside you. &lt;code&gt;changelog.json&lt;/code&gt; is a machine-readable feed of every rule change we track, and it's what powers the live &lt;a href="https://invoicetariff.com/radar" rel="noopener noreferrer"&gt;tariff change radar&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt;
&lt;span class="n"&gt;cl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;invoicetariff/data/changelog.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;entries&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cl&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;                                            &lt;span class="c1"&gt;# 57 entries total
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;collections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;layer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;cl&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;# {'mfn': 35, 'section232': 8, 'china301': 5, 'section338': 4, 'ieepa': 2, 'fees': 2, 'global301': 1}
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;cl&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;date&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2026-01-01&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;    &lt;span class="c1"&gt;# 54 entries dated in 2026 alone
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fifty-four entries in ten months. Entries carry &lt;code&gt;date&lt;/code&gt;, &lt;code&gt;layer&lt;/code&gt;, &lt;code&gt;status&lt;/code&gt; (&lt;code&gt;published&lt;/code&gt; / &lt;code&gt;upcoming&lt;/code&gt;), and bilingual titles — upcoming items include the China exclusions expiry (2026-11-10) and the extended truce deadline (2027-01-10). Each entry has an id prefixed with its date, so a diff-able state file is all you need to turn this into a monitoring bot — which is exactly what we'll build in the follow-up post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data quality: read the flags before you ship
&lt;/h2&gt;

&lt;p&gt;The dataset is honest about its edges, and you should be too when you build on it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;v0.3.x is a Phase-1 snapshot.&lt;/strong&gt; Except the FY2027 fee table, rate lines carry &lt;code&gt;sample&lt;/code&gt;/&lt;code&gt;unverified&lt;/code&gt; annotations — good for estimates, pricing scenarios, and demos; &lt;strong&gt;not yet certified for production customs declarations&lt;/strong&gt;. The &lt;code&gt;meta.nextHardDates&lt;/code&gt; field tracks what's being verified next.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coverage is two-tiered by design&lt;/strong&gt;: 484 curated codes with the full stack in &lt;code&gt;ruleset-seed.json&lt;/code&gt;, all 5,689 codes MFN-only in &lt;code&gt;mfn-full.json&lt;/code&gt;. Join them for broad-but-shallow or shallow-but-deep.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It moves.&lt;/strong&gt; The ruleset is versioned and updated monthly; every CSV row carries &lt;code&gt;ruleset_version&lt;/code&gt; / &lt;code&gt;ruleset_asof&lt;/code&gt;, so a stale analysis announces itself. Pin the version you ran against, and re-run when it bumps.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you'd rather eyeball the stack than code it, the &lt;a href="https://invoicetariff.com/tariff-calculator" rel="noopener noreferrer"&gt;calculator&lt;/a&gt; runs the same ruleset in the browser and links every result line back to the JSON entry; the &lt;a href="https://invoicetariff.com/hts" rel="noopener noreferrer"&gt;HTS search&lt;/a&gt; covers all 5,689 codes. The CSV extracts are also downloadable with a citation guide at &lt;a href="https://invoicetariff.com/en/tariff-data" rel="noopener noreferrer"&gt;tariff-data&lt;/a&gt; (CC BY 4.0; the JSON is MIT).&lt;/p&gt;

&lt;h2&gt;
  
  
  What would you build?
&lt;/h2&gt;

&lt;p&gt;A landed-cost Shopify app, a procurement dashboard, an LLM tool-calling endpoint for "what does this part cost to import" — the data's the boring part now, which is the point. If you build something on it, open an issue on the repo or drop it in the comments; I'm curious what directions this goes.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;All figures in this post come from InvoiceTariff ruleset v0.3.4 (as of 2026-10-07) and the FY2027 fee table — estimates for planning, not legal advice; your customs broker signs the entry, not your notebook.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you want the monitoring side — getting told when the stack changes instead of re-checking — &lt;a href="https://dev.to/invoicetariff/build-your-own-tariff-change-radar-in-70-lines-of-python-the-data-is-already-open-169o"&gt;the follow-up&lt;/a&gt; walks through a ~70-line change radar on top of &lt;code&gt;changelog.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And if you'd rather import the math than parse the spreadsheets, &lt;a href="https://dev.to/invoicetariff/add-us-import-tariff-math-to-your-app-in-5-minutes-with-us-tariff-lookup-43lc"&gt;the third post&lt;/a&gt; takes &lt;code&gt;us-tariff-lookup&lt;/code&gt; from &lt;code&gt;npm install&lt;/code&gt; to a working landed-cost endpoint in Express or Next.&lt;/p&gt;

</description>
      <category>python</category>
      <category>pandas</category>
      <category>opensource</category>
      <category>ecommerce</category>
    </item>
    <item>
      <title>How Much Tariff Do You Actually Pay Importing From China in 2026? A Code-Level Breakdown</title>
      <dc:creator>InvoiceTariff</dc:creator>
      <pubDate>Fri, 02 Oct 2026 01:36:36 +0000</pubDate>
      <link>https://dev.to/invoicetariff/how-much-tariff-do-you-actually-pay-importing-from-china-in-2026-a-code-level-breakdown-5ba3</link>
      <guid>https://dev.to/invoicetariff/how-much-tariff-do-you-actually-pay-importing-from-china-in-2026-a-code-level-breakdown-5ba3</guid>
      <description>&lt;p&gt;If you buy goods from China and import them into the United States, the number on your customs entry is never "the tariff rate." It's a &lt;strong&gt;stack&lt;/strong&gt;: a base MFN duty, plus Section 301 layers, plus Section 232 if your product touches steel or aluminum, plus user fees that often cost more than the duties. Most sellers discover this when the invoice arrives.&lt;/p&gt;

&lt;p&gt;I maintain a small open tariff engine, so instead of explaining this with vibes, I'll walk through the actual math our engine performs — with real numbers pulled straight from the versioned ruleset JSON (v0.3.2, as of 2026-09-24, FY2027 fee table in effect since 2026-10-01) — and give you a runnable TypeScript (plus Python) implementation you can adapt.&lt;/p&gt;

&lt;p&gt;By the end you'll be able to answer, to the dollar: &lt;em&gt;what will this shipment actually cost me in duties and fees?&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The 2026 stack, layer by layer
&lt;/h2&gt;

&lt;p&gt;For a typical China-origin shipment the stack currently looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Duty = MFN(base rate)                    ← USITC Harmonized Tariff Schedule
     + Section 301 (China lists 1–4A)    ← USTR actions, per HTS code
     + Section 301 (2026 global program) ← country tiers, effective 2026-07-24
     + Section 232 (steel/aluminum/...)  ← only for covered products
     ─ IEEPA "fentanyl tariff" (10%)     ← TERMINATED 2026-02-24 (SCOTUS); historical layer
Fees = MPF  0.3464% of value, min $34.58, max $670.86   (FY2027, since 2026-10-01)
     + HMF  0.125% of value              ← ocean shipments only
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few things worth calling out, because they trip people up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MFN is per-code, and "Free" is a real answer.&lt;/strong&gt; Laptops (HTS 8471.30) have a &lt;code&gt;Free&lt;/code&gt; MFN general rate in the USITC schedule. That does &lt;em&gt;not&lt;/em&gt; mean the laptop enters free in 2026 — see below.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The China Section 301 lists are per-code too.&lt;/strong&gt; A cotton T-shirt (61091000) sits on List 4A at 7.5%; a laptop isn't on any of the 17 list lines in the current ruleset.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;There is now a &lt;em&gt;global&lt;/em&gt; Section 301 program&lt;/strong&gt; (effective 2026-07-24) with country tiers — China sits in the 12.5% tier. This is new in 2026 and a lot of landed-cost spreadsheets don't know it exists yet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IEEPA is a refund question now, not a cost question.&lt;/strong&gt; The 10% "fentanyl tariff" layer was struck down on 2026-02-24. If you paid it, that money may be recoverable — that's a lookup problem, not a stacking problem.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The fees are not rounding errors.&lt;/strong&gt; MPF is capped at $670.86, so above ~$194k of declared value it stops growing, but in the $10k–$190k range it's real money. And note the floor just moved: the FY2026 minimum was $33.58, FY2027 (in effect since 2026-10-01) is $34.58.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The data model (this is the part developers care about)
&lt;/h2&gt;

&lt;p&gt;You can't compute this stack without a versioned dataset, because every layer changes on its own schedule. Our engine reads one JSON ruleset; here are the exact rows we need for two worked examples, copied verbatim from &lt;code&gt;ruleset-seed.json&lt;/code&gt; &lt;strong&gt;v0.3.2 (asOf 2026-09-24)&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json-doc"&gt;&lt;code&gt;&lt;span class="c1"&gt;// MFN rows (engine/data/ruleset-seed.json → .mfn[])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;// ⚠️ v0.3.x rows carry sample/unverified flags upstream — estimates, not customs-certified&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"hts8"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"84713001"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Portable automatic data processing machines…"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"general"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Free"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"sample"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"hts8"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"61091000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"T-shirts, singlets… of cotton"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nl"&gt;"general"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"16.5%"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"sample"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;// China Section 301 (→ .china301[]) — 17 lines total&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"hts8"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"61091000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"list"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4A"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"rate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;7.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"legalBasis"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Trade Act 1974 §301 (USTR action, 9903.88.01 series)"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;// Global Section 301 (→ .global301, effectiveFrom 2026-07-24) — 60 country tiers&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"country"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"rate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;12.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"legalBasis"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Trade Act 1974 §301 (global forced-labor program; FR 2026-15181 §1(a)(i))"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;// Fee table (→ .fees[]) — fiscal-year keyed; the FY2027 row is in effect since 2026-10-01&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"fiscalYear"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2027&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"validFrom"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-10-01"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"validTo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2027-09-30"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mpfRate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.3464&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"mpfMin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;34.58&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"mpfMax"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;670.86&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"hmfRate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.125&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"informalTiers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"maxValue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"fee"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2.69&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                     &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"maxValue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"fee"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;8.06&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                     &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"maxValue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"fee"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;12.09&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note what the data gives you for free: &lt;code&gt;legalBasis&lt;/code&gt; and &lt;code&gt;source&lt;/code&gt; on every line. When a client asks "where did 12.5% come from?", the answer is a Federal Register citation, not a shrug.&lt;/p&gt;

&lt;h2&gt;
  
  
  The TypeScript
&lt;/h2&gt;

&lt;p&gt;This is a simplified but &lt;em&gt;runnable&lt;/em&gt; version of the stacking logic — no exclusions, no 232 matching, no informal-entry tiers, just the main path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Data: InvoiceTariff ruleset v0.3.2 (engine/data/ruleset-seed.json, asOf 2026-09-24)&lt;/span&gt;
&lt;span class="c1"&gt;// Fee table: FY2027, in effect 2026-10-01&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MFN_GENERAL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;84713001&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;// "Free"   (laptops)&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;61091000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;16.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// cotton T-shirts&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CHINA_301_LISTS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;61091000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;7.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;// List 4A&lt;/span&gt;
  &lt;span class="c1"&gt;// 84713001: not on any China 301 list in v0.3.2&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;GLOBAL_301_TIER_CN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;12.5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      &lt;span class="c1"&gt;// effective 2026-07-24 (FR 2026-15181)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;FEES_FY2027&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;mpfRate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.3464&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;mpfMin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;34.58&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;mpfMax&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;670.86&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;hmfRate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.125&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                     &lt;span class="c1"&gt;// ocean only&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;pct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rate&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;stackedTariff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;hts8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;declaredValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// USD, transaction value&lt;/span&gt;
  &lt;span class="nl"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;          &lt;span class="c1"&gt;// "CN" in this example&lt;/span&gt;
  &lt;span class="nl"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ocean&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;air&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;hts8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;declaredValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mode&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mfn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MFN_GENERAL&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;hts8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;declaredValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;list301&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CHINA_301_LISTS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;hts8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;declaredValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;global301&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CN&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;pct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;GLOBAL_301_TIER_CN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;declaredValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mpf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;pct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;FEES_FY2027&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mpfRate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;declaredValue&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;FEES_FY2027&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mpfMin&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;FEES_FY2027&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mpfMax&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hmf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ocean&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;pct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;FEES_FY2027&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hmfRate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;declaredValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;duty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mfn&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;list301&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;global301&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;mfn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;list301&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;global301&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mpf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hmf&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;duty&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;mpf&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;hmf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;effectiveRatePct&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="p"&gt;(((&lt;/span&gt;&lt;span class="nx"&gt;duty&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;mpf&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;hmf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;declaredValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Worked example 1: $50,000 of laptops from China, ocean freight&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;stackedTariff&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;hts8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;84713001&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;declaredValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CN&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ocean&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="c1"&gt;// → mfn 0, list301 0, global301 6250, mpf 173.20, hmf 62.50&lt;/span&gt;
&lt;span class="c1"&gt;// → total $6,485.70  (effective 12.97%)&lt;/span&gt;

&lt;span class="c1"&gt;// Worked example 2: $20,000 of cotton T-shirts from China, ocean&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;stackedTariff&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;hts8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;61091000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;declaredValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CN&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ocean&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="c1"&gt;// → mfn 3300, list301 1500, global301 2500, mpf 69.28, hmf 25&lt;/span&gt;
&lt;span class="c1"&gt;// → total $7,394.28  (effective 36.97%)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the same thing in Python, if that's your stack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Data: InvoiceTariff ruleset v0.3.2 (ruleset-seed.json, asOf 2026-09-24)
# Fee table: FY2027, in effect 2026-10-01
&lt;/span&gt;&lt;span class="n"&gt;MFN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;84713001&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;61091000&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;16.5&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;CHINA_301&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;61091000&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;7.5&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;GLOBAL_301_CN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;12.5&lt;/span&gt;          &lt;span class="c1"&gt;# effective 2026-07-24
&lt;/span&gt;&lt;span class="n"&gt;MPF&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.3464&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;34.58&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hi&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;670.86&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;HMF_OCEAN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.125&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;stacked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hts8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ocean&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;mfn&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MFN&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hts8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
    &lt;span class="n"&gt;list_301&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CHINA_301&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hts8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
    &lt;span class="n"&gt;global_301&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GLOBAL_301_CN&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;origin&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="n"&gt;mpf&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MPF&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MPF&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="n"&gt;MPF&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hi&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;hmf&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HMF_OCEAN&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ocean&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="n"&gt;total&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mfn&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;list_301&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;global_301&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;mpf&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;hmf&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mfn&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mfn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;list301&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;list_301&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;global301&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;global_301&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mpf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mpf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hmf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hmf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;total&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;effective_pct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;stacked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;84713001&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50_000&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# total ≈ 6485.70 → 12.97%
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;stacked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;61091000&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20_000&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# total ≈ 7394.28 → 36.97%
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read those two outputs again, because they contain the whole story of 2026 sourcing math:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;laptop&lt;/strong&gt; went from effectively duty-free to &lt;strong&gt;~13%&lt;/strong&gt; the moment the global program went live on 2026-07-24 — with zero change to the HTS schedule.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;T-shirt&lt;/strong&gt; is now pushing &lt;strong&gt;37% all-in&lt;/strong&gt; between MFN, List 4A, and the global tier. If your pricing model still assumes "MFN + 7.5%", you're underquoting by 18 points.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The parts I left out (on purpose)
&lt;/h2&gt;

&lt;p&gt;The snippet above is the happy path. The production engine adds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Section 232 measures&lt;/strong&gt; — 8 lines in the ruleset (steel/aluminium articles at 50% since 2025-06-04, plus derivatives). Product-level matching, not code-level.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exclusion windows&lt;/strong&gt; — both China-list exclusions (with expiry dates) and 39 HTS-prefix exclusions under the global program.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Informal entry tiers&lt;/strong&gt; — shipments under $2,500 pay flat fees ($2.69/$8.06/$12.09) instead of MPF/HMF, which completely changes the small-parcel math, together with the de minimis threshold rules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The caveat section of the ruleset itself&lt;/strong&gt;: v0.3.x flags most non-fee rows as &lt;code&gt;sample&lt;/code&gt;/&lt;code&gt;unverified&lt;/code&gt; upstream, and &lt;code&gt;unverifiedNotes&lt;/code&gt; records that several exemption lists published as PDF attachments aren't machine-encoded yet — meaning for those goods the engine can &lt;em&gt;over&lt;/em&gt;-count the global 301 layer. Estimates first; your customs broker still signs the entry.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to sanity-check a code against the full 5,689-row HTS table, the &lt;a href="https://invoicetariff.com/en/tariff-calculator" rel="noopener noreferrer"&gt;free tariff calculator&lt;/a&gt; runs exactly this stack in the browser and shows the per-line provenance — for example the &lt;a href="https://invoicetariff.com/en/hts/84713001" rel="noopener noreferrer"&gt;HTS 8471.30 tariff rate&lt;/a&gt; page shows the &lt;code&gt;Free&lt;/code&gt; MFN row and every layer stacked on top of it. For the 301 layer specifically, the &lt;a href="https://invoicetariff.com/en/china-tariff" rel="noopener noreferrer"&gt;China tariff guide&lt;/a&gt; walks the lists line by line.&lt;/p&gt;

&lt;h2&gt;
  
  
  The layer you should be watching: change velocity
&lt;/h2&gt;

&lt;p&gt;The nasty part of 2026 isn't any single rate — it's that the stack changes on independent calendars. The ruleset's &lt;code&gt;nextHardDates&lt;/code&gt; had three entries when this snapshot was taken; two have already fired:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;2026-09-29&lt;/strong&gt; — Section 232 pharmaceuticals expansion ✅ (took effect)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;2026-10-01&lt;/strong&gt; — FY2027 MPF reset ✅ (took effect; the fee constants in this post are already FY2027: min $34.58 / max $670.86)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;2027-01-10&lt;/strong&gt; — China exclusions + tariff truce + port fee measures now share this extended deadline (extension announced 2026-09-23, FR notice pending)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can't diff this by hand. Our ruleset ships a machine-readable &lt;code&gt;changelog.json&lt;/code&gt; (51 entries and counting), which also feeds the public &lt;a href="https://invoicetariff.com/en/radar" rel="noopener noreferrer"&gt;tariff change radar&lt;/a&gt; — it's the cheap way to find out your cost basis moved &lt;em&gt;before&lt;/em&gt; the invoice tells you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Model the stack, not "the tariff rate": MFN + 301 layers + fees, each with its own effective dates.&lt;/li&gt;
&lt;li&gt;Keep rates in &lt;strong&gt;versioned data&lt;/strong&gt;, not in your code — the logic barely changes, the data changes monthly.&lt;/li&gt;
&lt;li&gt;Track &lt;code&gt;legalBasis&lt;/code&gt;/&lt;code&gt;source&lt;/code&gt; per line; "because the spreadsheet said so" doesn't survive a customs audit.&lt;/li&gt;
&lt;li&gt;Fee tables have fiscal years. FY2027 MPF (min $34.58 / max $670.86) went live 2026-10-01 — diary the next rollover and the 2027-01-10 China measures cluster.&lt;/li&gt;
&lt;li&gt;If you paid the IEEPA tariff before February 2026, start reading up on refund channels instead of writing it off.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;All rates in this post come from a single versioned snapshot (InvoiceTariff ruleset v0.3.2, as of 2026-09-24) and the FY2027 fee table — they are estimates for planning, not legal advice. Your customs entry is signed by your broker, not by your code.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Questions, corrections, or your own worked examples are welcome in the comments.&lt;/p&gt;

</description>
      <category>python</category>
      <category>typescript</category>
      <category>tutorial</category>
      <category>ecommerce</category>
    </item>
    <item>
      <title>InvoiceTariff Public API: Free HTS Code Search &amp; US Tariff Radar (No API Key)</title>
      <dc:creator>InvoiceTariff</dc:creator>
      <pubDate>Wed, 16 Sep 2026 03:31:05 +0000</pubDate>
      <link>https://dev.to/invoicetariff/invoicetariff-public-api-free-hts-code-search-us-tariff-radar-no-api-key-6bj</link>
      <guid>https://dev.to/invoicetariff/invoicetariff-public-api-free-hts-code-search-us-tariff-radar-no-api-key-6bj</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Spec: &lt;code&gt;https://invoicetariff.com/openapi.json&lt;/code&gt; (OpenAPI 3.1) · RSS: &lt;code&gt;https://invoicetariff.com/radar/feed.xml&lt;/code&gt; · LLM index: &lt;code&gt;https://invoicetariff.com/llms.txt&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you sell internationally, two questions decide your margin: &lt;strong&gt;what is the duty rate for my product&lt;/strong&gt;, and &lt;strong&gt;did it just change&lt;/strong&gt;. The US tariff landscape in 2025–2026 is a moving target — Section 301 lists, Section 232 sector tariffs, IEEPA layers, Federal Register notices every week. InvoiceTariff (&lt;code&gt;https://invoicetariff.com&lt;/code&gt;) is a free web tool that answers both questions, and its public API lets you wire the same data into your own systems. &lt;strong&gt;No sign-up, no API key, no charge.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This document describes the public read-only endpoints, with real request/response examples. An interactive calculator is at &lt;code&gt;/en/tariff-calculator&lt;/code&gt;, and all 5,689 HTS 8-digit codes are browsable at &lt;code&gt;/en/hts&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick facts
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Base URL&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://invoicetariff.com&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auth&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Methods&lt;/td&gt;
&lt;td&gt;GET only (read-only)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rate limit&lt;/td&gt;
&lt;td&gt;30 requests/min/IP on &lt;code&gt;/api/hts/search&lt;/code&gt; (HTTP 429 + &lt;code&gt;retry-after&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Caching&lt;/td&gt;
&lt;td&gt;Search &amp;amp; radar responses are CDN-cached for 5 minutes (&lt;code&gt;cache-control: public, max-age=300&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Formats&lt;/td&gt;
&lt;td&gt;JSON, RSS 2.0, plain text&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Machine-readable spec&lt;/td&gt;
&lt;td&gt;`&lt;code&gt;/openapi.json&lt;/code&gt; — OpenAPI 3.1`&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data sources&lt;/td&gt;
&lt;td&gt;USITC HTS (US government, public domain); Federal Register notices&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Endpoints
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Search HTS codes — &lt;code&gt;GET /api/hts/search&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Full-text search over the complete US HTS 8-digit table (5,689 lines, synced from USITC). Match by code prefix (dots optional) or description keyword. Returns up to 12 results, code-prefix hits ranked first.&lt;/p&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;bash&lt;/p&gt;

&lt;h1&gt;
  
  
  by code prefix
&lt;/h1&gt;

&lt;p&gt;curl "&lt;a href="https://invoicetariff.com/api/hts/search?q=8471" rel="noopener noreferrer"&gt;https://invoicetariff.com/api/hts/search?q=8471&lt;/a&gt;"&lt;/p&gt;

&lt;h1&gt;
  
  
  by keyword
&lt;/h1&gt;

&lt;p&gt;curl "&lt;a href="https://invoicetariff.com/api/hts/search?q=lithium" rel="noopener noreferrer"&gt;https://invoicetariff.com/api/hts/search?q=lithium&lt;/a&gt;"&lt;br&gt;
&lt;code&gt;&lt;/code&gt;`&lt;/p&gt;

&lt;p&gt;Response (real example, keyword &lt;code&gt;lithium&lt;/code&gt;):&lt;/p&gt;

&lt;p&gt;&lt;code&gt;`json&lt;br&gt;
{&lt;br&gt;
  "ok": true,&lt;br&gt;
  "results": [&lt;br&gt;
    {&lt;br&gt;
      "hts8": "28369100",&lt;br&gt;
      "description": "Carbonates; peroxocarbonates (percarbonates); commercial ammonium carbonate containing ammonium carbamate: — Other: — Lithium carbonates",&lt;br&gt;
      "general": "3.7%"&lt;br&gt;
    },&lt;br&gt;
    {&lt;br&gt;
      "hts8": "85065000",&lt;br&gt;
      "description": "Primary cells and primary batteries; parts thereof: — Lithium",&lt;br&gt;
      "general": "2.7%"&lt;br&gt;
    }&lt;br&gt;
  ]&lt;br&gt;
}&lt;br&gt;
`&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;hts8&lt;/code&gt; — 8-digit code, digits only (insert a dot after the first six for display: &lt;code&gt;2836.91.00&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;general&lt;/code&gt; — Column 1 general duty rate exactly as printed in the HTS (&lt;code&gt;Free&lt;/code&gt;, &lt;code&gt;2.7%&lt;/code&gt;, compound expressions like &lt;code&gt;6.5% + 37.5¢/kg&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Exceed 30 requests/min and you get &lt;code&gt;429&lt;/code&gt; with &lt;code&gt;{"ok": false, "error": "rate_limited"}&lt;/code&gt; and a &lt;code&gt;retry-after&lt;/code&gt; header.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Tariff radar updates — &lt;code&gt;GET /api/radar/updates&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;A pipeline scans the US Federal Register every 12 hours and digests tariff-relevant notices into structured entries: effective dates, affected HTS scope, old → new values where applicable, and links to the official document. Add an RSS reader and you never miss a change; consume the JSON and you can route them into Slack, ERP, or an AI agent.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;`bash&lt;br&gt;
curl "https://invoicetariff.com/api/radar/updates"        # all entries, newest first&lt;br&gt;
curl "https://invoicetariff.com/api/radar/updates?id=2026-09-15-2026-18834"  # single entry&lt;br&gt;
`&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Response shape (real example, truncated):&lt;/p&gt;

&lt;p&gt;&lt;code&gt;`json&lt;br&gt;
{&lt;br&gt;
  "ok": true,&lt;br&gt;
  "entries": [&lt;br&gt;
    {&lt;br&gt;
      "id": "2026-09-15-2026-18834",&lt;br&gt;
      "date": "2026-09-15",&lt;br&gt;
      "layer": "mfn",&lt;br&gt;
      "status": "published",&lt;br&gt;
      "title": "Accreditation and Approval of Bennett Testing Service, Inc. (Rahway, NJ), as a Commercial Gauger and Laboratory",&lt;br&gt;
      "titleEn": "…same…",&lt;br&gt;
      "summaryEn": "Notice is hereby given, pursuant to CBP regulations, that Bennett Testing Service, Inc. …",&lt;br&gt;
      "affectedHtsEn": "See document",&lt;br&gt;
      "affectedCount": null,&lt;br&gt;
      "changes": [],&lt;br&gt;
      "sources": [&lt;br&gt;
        { "title": "Federal Register 2026-18834 — …", "url": "https://www.federalregister.gov/documents/2026/09/15/2026-18834/…" }&lt;br&gt;
      ]&lt;br&gt;
    }&lt;br&gt;
  ]&lt;br&gt;
}&lt;br&gt;
`&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Field notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;layer&lt;/code&gt; — which tariff layer is affected: &lt;code&gt;mfn&lt;/code&gt;, &lt;code&gt;china301&lt;/code&gt;, &lt;code&gt;global301&lt;/code&gt;, &lt;code&gt;section232&lt;/code&gt;, &lt;code&gt;section338&lt;/code&gt;, &lt;code&gt;fees&lt;/code&gt;, &lt;code&gt;ieepa&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;status&lt;/code&gt; — &lt;code&gt;published&lt;/code&gt; (effective), &lt;code&gt;upcoming&lt;/code&gt; (announced, future date), &lt;code&gt;historical&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;changes&lt;/code&gt; — array of &lt;code&gt;{label, oldValue, newValue}&lt;/code&gt; (+ &lt;code&gt;*En&lt;/code&gt; variants) when the notice changes numeric values.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sources&lt;/code&gt; — official Federal Register / agency links. Always cite the source, not just the digest.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Prefer RSS? Same data at &lt;code&gt;https://invoicetariff.com/radar/feed.xml&lt;/code&gt; (RSS 2.0).&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Visitor country — &lt;code&gt;GET /api/geo&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Returns the caller's ISO-3166 alpha-2 country as detected at the CDN edge (&lt;code&gt;null&lt;/code&gt; when unavailable). Handy as a lightweight geo fallback.&lt;/p&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;bash&lt;br&gt;
curl "&lt;a href="https://invoicetariff.com/api/geo" rel="noopener noreferrer"&gt;https://invoicetariff.com/api/geo&lt;/a&gt;"&lt;/p&gt;

&lt;h1&gt;
  
  
  {"country":"US"}
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`&lt;/p&gt;

&lt;h3&gt;
  
  
  4. LLM-friendly indexes — &lt;code&gt;GET /llms.txt&lt;/code&gt;, &lt;code&gt;GET /llms-full.txt&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Following the &lt;a href="https://llmstxt.org" rel="noopener noreferrer"&gt;llms.txt convention&lt;/a&gt;, the site publishes a markdown index of its pages and data endpoints for AI agents. Point your agent at &lt;code&gt;https://invoicetariff.com/llms.txt&lt;/code&gt; and it can discover the calculator, the HTS browser, and the API without a human.&lt;/p&gt;

&lt;h2&gt;
  
  
  Minimal client examples
&lt;/h2&gt;

&lt;p&gt;Python (3.8+):&lt;/p&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;python&lt;br&gt;
import requests&lt;/p&gt;

&lt;p&gt;BASE = "&lt;a href="https://invoicetariff.com" rel="noopener noreferrer"&gt;https://invoicetariff.com&lt;/a&gt;"&lt;/p&gt;

&lt;p&gt;def find_hts(keyword: str):&lt;br&gt;
    r = requests.get(f"{BASE}/api/hts/search", params={"q": keyword}, timeout=10)&lt;br&gt;
    r.raise_for_status()&lt;br&gt;
    return r.json()["results"]&lt;/p&gt;

&lt;p&gt;def tariff_watch():&lt;br&gt;
    r = requests.get(f"{BASE}/api/radar/updates", timeout=10)&lt;br&gt;
    r.raise_for_status()&lt;br&gt;
    for e in r.json()["entries"]:&lt;br&gt;
        if e["layer"] in ("china301", "global301") and e["status"] == "upcoming":&lt;br&gt;
            print(e["date"], e["titleEn"], e["sources"][0]["url"])&lt;/p&gt;

&lt;p&gt;if &lt;strong&gt;name&lt;/strong&gt; == "&lt;strong&gt;main&lt;/strong&gt;":&lt;br&gt;
    for hit in find_hts("lithium"):&lt;br&gt;
        print(hit["hts8"], hit["general"], hit["description"][:60])&lt;br&gt;
&lt;code&gt;&lt;/code&gt;`&lt;/p&gt;

&lt;p&gt;JavaScript / TypeScript:&lt;/p&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;ts&lt;br&gt;
const BASE = "&lt;a href="https://invoicetariff.com" rel="noopener noreferrer"&gt;https://invoicetariff.com&lt;/a&gt;";&lt;/p&gt;

&lt;p&gt;export async function findHts(q: string) {&lt;br&gt;
  const res = await fetch(&lt;code&gt;${BASE}/api/hts/search?q=${encodeURIComponent(q)}&lt;/code&gt;);&lt;br&gt;
  if (res.status === 429) throw new Error(&lt;code&gt;rate limited, retry after ${res.headers.get("retry-after")}s&lt;/code&gt;);&lt;br&gt;
  const { results } = await res.json();&lt;br&gt;
  return results;&lt;br&gt;
}&lt;br&gt;
&lt;code&gt;&lt;/code&gt;`&lt;/p&gt;

&lt;h2&gt;
  
  
  What this API is (and isn't)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Read-only reference data.&lt;/strong&gt; It exposes HTS lookup and tariff-change monitoring. It does not compute your full landed cost — that logic (MFN + 301 + 232 + IEEPA stacking, MPF/HMF fees, multi-destination VAT) runs client-side in the &lt;code&gt;free calculator&lt;/code&gt; or batch mode.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A full programmatic calculation API is planned.&lt;/strong&gt; If you need &lt;code&gt;goods value + HTS + destination → landed cost&lt;/code&gt; as an endpoint, join the waitlist at &lt;code&gt;invoicetariff.com/api-waitlist&lt;/code&gt; — it shapes the roadmap.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rates are official but not legal advice.&lt;/strong&gt; Data comes from USITC and the Federal Register; always confirm against the official sources linked in each radar entry before clearing customs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;OpenAPI 3.1 spec: &lt;code&gt;https://invoicetariff.com/openapi.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Site (free, bilingual EN/中文): &lt;code&gt;https://invoicetariff.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;HTS browser: &lt;code&gt;https://invoicetariff.com/en/hts&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Tariff radar page + RSS: &lt;code&gt;https://invoicetariff.com/en/radar&lt;/code&gt; · &lt;code&gt;https://invoicetariff.com/radar/feed.xml&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;LLM index: &lt;code&gt;https://invoicetariff.com/llms.txt&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>api</category>
      <category>ecommerce</category>
      <category>python</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Is your product hit by the 2026 "global" Section 301 tariff? A 9-step check before you place the PO</title>
      <dc:creator>InvoiceTariff</dc:creator>
      <pubDate>Thu, 10 Sep 2026 00:40:30 +0000</pubDate>
      <link>https://dev.to/invoicetariff/is-your-product-hit-by-the-2026-global-section-301-tariff-a-9-step-check-before-you-place-the-po-11ic</link>
      <guid>https://dev.to/invoicetariff/is-your-product-hit-by-the-2026-global-section-301-tariff-a-9-step-check-before-you-place-the-po-11ic</guid>
      <description>&lt;p&gt;Since July 24, 2026, a new tariff layer applies to goods from &lt;strong&gt;60 economies&lt;/strong&gt; — and in my experience talking to small importers, most of them found out the hard way: the quote looked fine, then the entry summary came back with a charge nobody budgeted for. This is the "global" Section 301 program (the forced-labor one, Federal Register 2026-15181), and it is &lt;strong&gt;separate&lt;/strong&gt; from the older China Section 301 lists.&lt;/p&gt;

&lt;p&gt;Last week I wrote about the five duty layers in a landed-cost calculation. Today, a concrete pre-order check: how to tell in about 15 minutes whether this new layer hits your product, and how much it actually adds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Nail down the 10-digit HTS code
&lt;/h2&gt;

&lt;p&gt;Everything starts with classification. Get the exact 10-digit HTS code from your supplier — in writing. A 6-digit guess is not enough, because the exemptions and the Chapter 99 surcharge lines live at the 8–10 digit level. If two suppliers quote you "the same" product under different codes, resolve that disagreement before you compute anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Confirm true country of origin
&lt;/h2&gt;

&lt;p&gt;Origin is where the goods were &lt;strong&gt;grown, manufactured, or substantially transformed&lt;/strong&gt; — not where they were shipped from. A Vietnamese-assembled product using Chinese components may or may not be Vietnamese origin; a Malaysian-traded Chinese-made good is still Chinese origin. When in doubt, your customs broker can make a formal determination. Getting this wrong poisons every later step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Check whether Section 232 covers your product (if yes, you may be exempt)
&lt;/h2&gt;

&lt;p&gt;This surprises people: goods covered by the Section 232 sectoral tariffs — steel, aluminum, copper and derivatives, passenger cars/light trucks and parts, wood products, medium/heavy trucks and parts, semiconductors — are &lt;strong&gt;exempt from the global 301 layer&lt;/strong&gt;, regardless of origin country. The two programs don't stack. So before you panic about the 12.5% tier, check whether your HTS line already falls under a 232 action.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Find your country's tier
&lt;/h2&gt;

&lt;p&gt;The program has four tiers:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tier&lt;/th&gt;
&lt;th&gt;Economies (examples)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;10% flat (17)&lt;/td&gt;
&lt;td&gt;India, Indonesia, Malaysia, Mexico, Canada, UK, Pakistan, Sri Lanka…&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10% &lt;em&gt;cap&lt;/em&gt;
&lt;/td&gt;
&lt;td&gt;European Union (all 27), Taiwan&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12.5% &lt;em&gt;cap&lt;/em&gt;
&lt;/td&gt;
&lt;td&gt;Japan, South Korea, Switzerland&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12.5% flat (38)&lt;/td&gt;
&lt;td&gt;China, Vietnam, Thailand, Brazil, Hong Kong, Singapore, Türkiye, Australia…&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The "cap" tiers are &lt;strong&gt;net of MFN&lt;/strong&gt;: the MFN duty plus the 301 surcharge combined cannot exceed 10% (or 12.5%). So a German machine part with a 2.5% MFN rate gets 7.5% added; a line with a 10%+ MFN rate gets &lt;strong&gt;zero&lt;/strong&gt; added. Flat tiers just stack on top, period.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: If you import from Canada or Mexico — check USMCA eligibility
&lt;/h2&gt;

&lt;p&gt;Goods from Canada or Mexico that qualify for USMCA duty-free treatment are exempt from the global 301 layer. The importer claims this eligibility, so make sure your supplier documentation actually supports a USMCA claim (certification of origin, tariff shift rules). Don't assume — verify, or skip the exemption.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Scan the exclusion lists
&lt;/h2&gt;

&lt;p&gt;Two kinds of carve-outs exist in U.S. note 52 of the Federal Register notice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;General product exclusions&lt;/strong&gt; — 16 specific commodity lines (etrogs, frozen tropical fruit, sowing seeds, açaí, single-strength citrus juice, coconut water, eucalyptus plywood, and similar). Narrow, but worth a scan.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Per-economy product lists&lt;/strong&gt; — Annex II of the notice lists product exemptions for specific countries (UK, EU, Switzerland, Taiwan, and others).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The authoritative source is the HTS Chapter 99, Subchapter III text on &lt;a href="https://hts.usitc.gov" rel="noopener noreferrer"&gt;hts.usitc.gov&lt;/a&gt; — search your 10-digit code and read the Chapter 99 references that come back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7: Stack the layers — and watch China
&lt;/h2&gt;

&lt;p&gt;For &lt;strong&gt;China origin&lt;/strong&gt;, the new 12.5% global 301 layer stacks &lt;strong&gt;on top of&lt;/strong&gt; the existing China Section 301 lists (the 7.5%–25% List 1–4A rates) and on top of MFN. A product that was "25% tariffed" last year can now carry meaningfully more. Also note: the existing China 301 exclusion lists are scheduled to expire November 10, 2026 — if your product currently relies on an exclusion, diarize that date.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 8: Mind the special cases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;In-transit relief&lt;/strong&gt;: goods loaded before July 24 and entered before July 28, 12:01 a.m. ET escaped the layer. Only relevant for shipments in the pipeline at announcement time, but worth knowing if you're auditing old entries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Textile TRQs pending&lt;/strong&gt;: Bangladesh, Cambodia, Indonesia, and Malaysia are supposed to get tariff-rate quotas for apparel; until USTR establishes them, the flat 10% applies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Canada has an extra layer&lt;/strong&gt;: separate proclamations under Section 338 add a &lt;strong&gt;50% surcharge&lt;/strong&gt; on Canadian autos, dairy, and alcohol (effective August 22, 2026) — with &lt;strong&gt;no USMCA exemption&lt;/strong&gt;, unlike the global 301 layer. If you import Canadian wine, maple-adjacent dairy, or vehicle parts, read the Annex II scope carefully; 232-covered goods are again excluded.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Caps on compound duties&lt;/strong&gt;: for the capped tiers, compound MFN duties are reduced to their ad-valorem equivalent first. This is fiddly math — most calculators (and some brokers) get it wrong.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 9: Recompute your margin at the landed number
&lt;/h2&gt;

&lt;p&gt;Add the layers to MFN, add MPF (0.3464%, min/max apply) and freight, and re-run your unit economics at that number — not at invoice value, and not at last quarter's rate sheet. Then screenshot or print your calculation with the date on it: when a rate changes, you'll want to know which quotes were priced on which rule snapshot.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest caveats
&lt;/h2&gt;

&lt;p&gt;This program is already being litigated at the Court of International Trade, and rates have been adjusted by proclamation more than once since July. Whatever you compute today, treat it as a snapshot: &lt;strong&gt;verify the rates the week you place the order&lt;/strong&gt;, not the week you read a blog post (including this one).&lt;/p&gt;

&lt;p&gt;I maintain a versioned tariff rule database for a living — we built &lt;strong&gt;InvoiceTariff&lt;/strong&gt; precisely because static spreadsheets kept rotting — and even we re-verify against the Federal Register text every time the radar flags a change. The method above is the same one we walk through; do it manually once and you'll never look at a supplier quote the same way again.&lt;/p&gt;




</description>
      <category>ecommerce</category>
      <category>tariffs</category>
      <category>supplychain</category>
      <category>smallbusiness</category>
    </item>
    <item>
      <title>How I calculate landed cost for small US imports — a 2026 founder's guide</title>
      <dc:creator>InvoiceTariff</dc:creator>
      <pubDate>Wed, 09 Sep 2026 02:24:25 +0000</pubDate>
      <link>https://dev.to/invoicetariff/how-i-calculate-landed-cost-for-small-us-imports-a-2026-founders-guide-2h4c</link>
      <guid>https://dev.to/invoicetariff/how-i-calculate-landed-cost-for-small-us-imports-a-2026-founders-guide-2h4c</guid>
      <description>&lt;p&gt;Last year I helped a friend import a small batch of phone accessories from Shenzhen to the US. The quote from her supplier looked great — until the shipment got stuck in customs with a bill she never saw coming. That experience sent me down a rabbit hole, and I want to share what I learned about calculating &lt;strong&gt;true landed cost&lt;/strong&gt; in 2026, because the rules changed dramatically in the past two years.&lt;/p&gt;

&lt;h2&gt;
  
  
  The five layers you actually pay
&lt;/h2&gt;

&lt;p&gt;When people say "tariff", they usually mean just one layer. In reality, for most goods entering the US, you pay up to five:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;MFN duty&lt;/strong&gt; — the baseline rate from the HTS code. Check it free on the &lt;a href="https://hts.usitc.gov" rel="noopener noreferrer"&gt;USITC HTS search&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Section 301 China tariff&lt;/strong&gt; — if the product is China-origin, an additional 7.5%–25% applies to thousands of HTS lines. This is where most surprises happen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reciprocal/global tariffs (2025–2026 layer)&lt;/strong&gt; — the 2025 executive orders added country-level ad valorem tariffs that stack on top of #1 and #2. Rates have shifted several times, so check the current snapshot before ordering.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MPF/HMF&lt;/strong&gt; — the merchandise processing fee (0.3464%, min/max apply) for ocean/air entries. Small but real.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State sales/use tax &amp;amp; last-mile&lt;/strong&gt; — not customs, but part of true landed cost.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  A worked example
&lt;/h2&gt;

&lt;p&gt;Say you import $4,000 of LED desk lamps (HTS 9405.XX, China origin):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Rate&lt;/th&gt;
&lt;th&gt;Amount&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Invoice value&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;$4,000.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MFN duty&lt;/td&gt;
&lt;td&gt;~3.9%&lt;/td&gt;
&lt;td&gt;$156.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Section 301&lt;/td&gt;
&lt;td&gt;25% (List 3)&lt;/td&gt;
&lt;td&gt;$1,000.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reciprocal layer&lt;/td&gt;
&lt;td&gt;current snapshot rate&lt;/td&gt;
&lt;td&gt;varies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MPF&lt;/td&gt;
&lt;td&gt;0.3464%&lt;/td&gt;
&lt;td&gt;$13.86&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That "cheap" order carries &lt;strong&gt;30%+ in duty layers&lt;/strong&gt; before it leaves the port. If your margin math assumed invoice value + 10% shipping, you're underwater.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three lessons I learned the hard way
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Your supplier's HS code suggestion is a starting point, not gospel.&lt;/strong&gt; Classification drives everything. A "lamp" classified under 9405 vs 8513 can differ by tens of percent in total duty. When in doubt, get a binding ruling or ask your broker in writing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. De minimis is not a strategy.&lt;/strong&gt; The $800 de minimis exemption that fueled years of direct-from-China parcels has been tightened for covered-origin goods; building your unit economics on it is building on sand. Check the current de minimis policy per origin country every time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Automate the boring math.&lt;/strong&gt; I built a spreadsheet first, then realized the rates change so often that a static sheet rots within weeks. Rule tables need versioning and a changelog — which is why we ended up building &lt;strong&gt;InvoiceTariff&lt;/strong&gt;, a free calculator with a versioned rule base (more on that in a future post; this one is deliberately method-first).&lt;/p&gt;

&lt;h2&gt;
  
  
  Your 10-minute pre-order checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Get the exact HTS code from your supplier — in writing&lt;/li&gt;
&lt;li&gt;[ ] Look up MFN rate on USITC (free, 2 min)&lt;/li&gt;
&lt;li&gt;[ ] Check whether Section 301 applies to that HTS line for your origin country&lt;/li&gt;
&lt;li&gt;[ ] Check the current reciprocal-tariff snapshot for the origin country&lt;/li&gt;
&lt;li&gt;[ ] Add MPF (0.3464%) + freight + insurance&lt;/li&gt;
&lt;li&gt;[ ] Recompute your margin at the &lt;em&gt;landed&lt;/em&gt; number, not invoice value&lt;/li&gt;
&lt;/ul&gt;




</description>
      <category>ecommerce</category>
      <category>tariffs</category>
      <category>supplychain</category>
      <category>smallbusiness</category>
    </item>
  </channel>
</rss>
