Skip to content

Extracting Tariff Codes From a Customs Declaration Form

10 min read · updated August 11, 2026

A tariff code looks like one identifier and behaves like two. The first six digits are a treaty-level classification that means the same thing in every participating country; everything after them is national law, and it is the part that decides what is owed.

The six digits everyone shares

The Harmonized Commodity Description and Coding System is maintained by the World Customs Organization and is hierarchical in a way that is worth reading literally, because the hierarchy is what lets you validate a partial code.

  • Chapter — the first two digits. Chapters run 01 to 97, and chapter 77 is reserved for future international use, so a code beginning 77 is not a truncation you can repair.
  • Heading — the first four digits, written 61.09 or 6109 depending on the form. This is the level at which the goods get their legal description.
  • Subheading — six digits, 6109.10. This is the deepest level that is internationally harmonised.

The dash structure in the published nomenclature is not decoration either: a one-dash subheading is subordinate to its heading and a two-dash subheading is subordinate to the one-dash line above it. A six-digit code whose parent four-digit heading does not exist is invalid, and that is a lookup you can run offline against the nomenclature file rather than a judgement call.

Where national codes take over

Past six digits, countries extend the code themselves, and the length alone tells you which regime you are looking at. The European Union’s Combined Nomenclature adds two digits to make eight, and the TARIC database adds two more to make ten, plus separate additional codes for things like anti-dumping measures. The United States Harmonized Tariff Schedule uses ten digits, of which the first eight are the legal rate line and the last two are a statistical suffix that carries no duty consequence at all. Other administrations use eight, ten or eleven.

The practical consequence for extraction is that a six-digit code copied from an export document is not usable for import duty in the destination country without national extension, and nothing on the face of the document says so. If your downstream system expects a country-specific rate line, storing the six-digit code and marking it as unextended is honest; padding it with zeros to reach ten is a fabricated classification.

Store the code as a string, not an integer. Leading zeros are significant — chapter 09 is coffee and tea, and 0902.30 becoming 90230 in a JSON number field is a silent, unrecoverable corruption. The same argument applies to any identifier field in the table schema you land these rows in.

The second code on the line

This is the failure that a schema with one hs_code field guarantees. On a United States entry, chapters 98 and 99 of the Harmonized Tariff Schedule are national-only: chapter 98 holds special classification provisions and chapter 99 holds temporary modifications enacted by trade legislation and proclamation. A line of merchandise can therefore carry its ordinary classification and, additionally, a chapter 99 code that imposes or suspends a rate.

An extractor that returns the first code it finds, or that returns the longest, or that returns the one nearest the description, will sometimes return the wrong one of the pair — and the one it drops may be the one carrying the additional duty. Model the field as an ordered list of codes per line item, with the ordinary classification and any special-provision codes distinguished by their chapter, and let the duty logic downstream decide which applies.

The code is dated, and the date matters

The Harmonized System is amended on a roughly five-year cycle, and amendments create, delete and merge headings. The World Customs Organization published the 2022 edition, which is the one in force at the time of writing, and has since accepted the amendments for a 2028 edition entering into force on 1 January 2028 — comprising, on the WCO’s own account, six new headings, 428 new subheadings, five deleted headings and 172 deleted subheadings, for a nomenclature of 1,229 headings and 5,852 subheadings. The WCO publishes the 2028 nomenclature and its correlation tables, and correlation tables are the important part: they are the mapping from an old code to its successors, and a code deleted in an edition change may correspond to more than one new code.

So a historical archive of declarations does not contain codes in one nomenclature. It contains codes in whichever edition was in force on the date of the entry, and validating a 2019 declaration against the current table will reject codes that were entirely correct. Extract the entry date alongside the code and validate against the edition in force then.

The edition dates and counts above are the WCO’s published figures at the time of writing. The five-year cycle is a convention rather than a guarantee, and national implementations of a new edition can lag the international entry-into-force date. Check the WCO and the relevant national administration before relying on either.

Extraction failures specific to tariff codes

  • Formatting is not information. 6109.10.0012, 6109 10 00 12 and 6109100012 are the same code. Normalise to digits only for storage and keep the printed form if you need to reproduce the document.
  • Length is ambiguous evidence. An eight-digit code might be an EU Combined Nomenclature code or a US rate line with the statistical suffix omitted. The declaring country, not the length, resolves it.
  • The description does not have to match. Goods descriptions on declarations are commercial text, not tariff text. Do not use similarity between the description and the nomenclature entry as a validation signal; it produces confident rejections of correct classifications and is a good way to invite a model to invent a code that fits the words.
  • One entry, many lines. A declaration is a header plus a repeating line-item block, and the block often continues onto a second sheet whose column positions have shifted. Extract line items as an array with an explicit line number, and check that the numbers are contiguous — the multi-entity schema shape rather than one object per document.
  • A wrong code that validates. Every digit of a tariff code is meaningful and none of them is a checksum. Unlike a container number, there is no arithmetic here — the only validation available is existence in the nomenclature for the relevant date, and a transposition that lands on another real code will pass it.