Trade
Who imports it? Four workbooks that keep the answer, from US customs records
Marin Mountain Bikes filed 5,711 shipments of bicycles into the US in the twelve months to 12 November 2026. Giant filed 3,943 and Trek 2,121. Nobody announces numbers like these; they are on the bills of lading, the documents that travel with each sea cargo and that US customs keeps, naming who took delivery, from whom, and from which country. We read them through Bill of Lading Data’s partner API, and every figure on this page is theirs.
The question a seller actually asks is narrower than a ranking: who buys what I make, and from whom do they buy it today. Below are five products and their largest importers, a game made of the same rankings, and four workbooks you can make in your account that keep the answer current, each with a schema that refuses an edit which would make it wrong.
572
US companies imported black tea between January and November 2026
6,688
banana shipments filed by Dole Fresh Fruit, the most of any importer
385
olive oil shipments filed by Drupley, almost four times the next importer
Five products and who imports them
Each ranking counts the shipments a consignee filed under one HS code, the customs number for a kind of goods (0803 is bananas, 8712 bicycles). It is a ranking of names as filed, so one firm can appear twice: Dole files as “Dole Fresh Fruit Company, Inc” and as “Dole Fresh Fruit Company”. A consignee is sometimes a forwarder or a warehouse rather than the buyer; Americold Logistics, fourth in olive oil, stores food for others.
| Product | US importers | Largest three, by shipments |
|---|---|---|
| Black tea (HS 0902.30 / 0902.40) | 572 | Vahdam Teas Global Inc 397 · FBA Luxmi Estates Inc 119 · Southern Tea LLC 96 |
| Green coffee beans (HS 0901.11) | 1,533 | Neumann Gruppe USA, Inc 1,066 · Starbucks Manuf EMEA B V 659 · A La Orden 619 |
| Bananas (HS 0803) | 622 | Dole Fresh Fruit Company, Inc 6,688 · Chiquita Fresh North Americallc 6,268 · Del Monte Fresh Produce N A Inc 4,541 |
| Bicycles (HS 8712) | 286 | Marin Mountain Bikes Inc 5,711 · Giant Bicycle Inc 3,943 · Specialized Bicycle Components 2,452 |
| Olive oil (HS 1509) | 477 | Drupley, Inc 385 · Maeva USA Inc 103 · Borges USA, Inc 96 |
Guess before you read the table
Two importers of the same product: which filed more? The five rankings are a free game. Sign in to add a product of your own.
Play who imports moreFour workbooks, each with a schema it compiles under
A hedwigai workbook is a document a research run writes and keeps current. Give one a schema and every edit to it, by a run, by you in the app, or by ChatGPT or Claude over MCP, is checked before it is kept. A schema has two parts. A tables layer says what each column holds: a date, a choice, a code of four digits. A TLA+ module says what must hold across rows, and TLC, the TLA+ model checker, checks it on every edit. An edit that breaks either is refused with the row and column it broke.
The rows below are real, read on 12 November 2026. We ran each module through TLC on those rows, where it holds, and on one broken edit, which it refuses.
1. Importer prospects
The largest importers of one HS code, ranked by shipments, with where each buys from. The schema keeps the ranking a ranking — ranks in order with no gap, more shipments never below fewer — and keeps a forwarder, which carries someone else's goods, out of the lead list.
| rank | importer | hs code | shipments | ships from | kind | status |
|---|---|---|---|---|---|---|
| 1 | Vahdam Teas Global Inc | 0902.40 | 397 | IN | buyer | new |
| 2 | FBA Luxmi Estates Inc | 0902.40 | 119 | IN | buyer | new |
| 3 | Southern Tea LLC | 0902.40 | 96 | VN, ID, JM, IN | buyer | new |
| 4 | National Management Logistics, Inc | 0902.40 | 93 | AR, JM, ES, MX | forwarder | not a fit |
| 5 | Henry P. Thomson, Inc | 0902.40 | 93 | VN, ID, MY, SG | buyer | new |
The schema
```tables
{
"tables": [
{
"name": "importers",
"tab": "Importers",
"key": [
"importer"
],
"columns": [
{
"name": "rank",
"type": "integer",
"required": true,
"unique": true,
"min": 1
},
{
"name": "importer",
"required": true,
"unique": true
},
{
"name": "hs code",
"required": true,
"pattern": "^[0-9]{4}(\\.[0-9]{2}){0,3}$"
},
{
"name": "shipments",
"type": "integer",
"required": true,
"min": 0
},
{
"name": "ships from",
"type": "list",
"separator": ", "
},
{
"name": "kind",
"type": "choice",
"values": [
"buyer",
"forwarder",
"unsure"
],
"required": true
},
{
"name": "status",
"type": "choice",
"values": [
"new",
"contacted",
"replied",
"meeting",
"won",
"not a fit"
],
"required": true
}
]
}
]
}
```
```tla
---- MODULE Business ----
EXTENDS Workbook, Naturals, Sequences
VARIABLE ok
Init == ok = TRUE
Next == UNCHANGED ok
Spec == Init /\ [][Next]_ok
\* The ranking reads top down: rank 1, 2, 3 ... with no gap.
RanksInOrder == \A i \in DOMAIN importers : importers[i].rank = i
\* More shipments never sit below fewer.
ByShipments == \A i \in 1..(Len(importers) - 1) :
importers[i].shipments >= importers[i + 1].shipments
\* A forwarder carries someone else's goods: it is never worked as a lead.
ForwardersAreNotLeads == \A i \in DOMAIN importers :
importers[i].kind = "forwarder" => importers[i].status = "not a fit"
====
```
```cfg
SPECIFICATION Spec
INVARIANT RanksInOrder
INVARIANT ByShipments
INVARIANT ForwardersAreNotLeads
```
Refused by TLC: setting row 4’s status to “contacted” breaks RanksInOrder, ByShipments, ForwardersAreNotLeads.
2. Supplier switch watch
One importer's bills of lading, oldest first, with the country each was shipped from. `switched` is not an opinion: TLC checks that it is true exactly where a bill's origin differs from the bill before it. Harney & Sons bought black tea from India in February and from Taiwan in July.
| importer | bill of lading | arrived | hs code | supplier | origin | switched |
|---|---|---|---|---|---|---|
| Harney & Sons Tea | (Kolkata, unnumbered) | 2026-02-25 | 09024010 | Aeon Commodities Private Limited | IN | no |
| Harney & Sons Tea | GPBBTPNYC265248 | 2026-07-01 | 090240 | Jen Ming Ritz Co., Ltd. | TW | yes |
| Harney & Sons Tea | GPBBTPNYC267274 | 2026-09-10 | 090240 | Jen Ming Ritz Co., Ltd. | TW | no |
The schema
```tables
{
"tables": [
{
"name": "watch",
"tab": "Watch",
"key": [
"importer",
"bill of lading"
],
"columns": [
{
"name": "importer",
"required": true
},
{
"name": "bill of lading",
"required": true,
"unique": true
},
{
"name": "arrived",
"type": "date",
"required": true
},
{
"name": "hs code",
"required": true,
"pattern": "^[0-9]{4,10}$"
},
{
"name": "supplier",
"required": true
},
{
"name": "origin",
"required": true,
"pattern": "^[A-Z]{2}$"
},
{
"name": "switched",
"type": "boolean",
"required": true
}
]
}
]
}
```
```tla
---- MODULE Business ----
EXTENDS Workbook, Naturals, Sequences
VARIABLE ok
Init == ok = TRUE
Next == UNCHANGED ok
Spec == Init /\ [][Next]_ok
\* Bills are kept oldest first, one importer at a time.
InOrder == \A i \in 1..(Len(watch) - 1) :
watch[i].importer = watch[i + 1].importer => watch[i].arrived <= watch[i + 1].arrived
\* "switched" is not an opinion: it says whether this bill's origin differs
\* from the same importer's bill before it.
SwitchedMeansNewOrigin == \A i \in DOMAIN watch :
watch[i].switched =
(\E j \in DOMAIN watch : j = i - 1 /\ watch[j].importer = watch[i].importer
/\ watch[j].origin /= watch[i].origin)
====
```
```cfg
SPECIFICATION Spec
INVARIANT InOrder
INVARIANT SwitchedMeansNewOrigin
```
Refused by TLC: setting row 2’s switched to “no” breaks InOrder, SwitchedMeansNewOrigin.
3. A rival exporter's customers
Who a competing exporter ships to, read from the exporter's side of the same records, with when each customer was first and last seen. A customer seen once was seen on one day.
| exporter | customer | customer city | first seen | last seen | shipments |
|---|---|---|---|---|---|
| Jen Ming Ritz Co., Ltd. | Harney & Sons Tea | Millerton, NY | 2026-07-01 | 2026-09-10 | 2 |
| Casa Fuentes SACIFI | Eastern Tea Corp. | Jamesburg, NJ | 2026-10-19 | 2026-10-19 | 1 |
| Madhu Jayanti International | Harris Tea Company | Moorestown, NJ | 2026-09-19 | 2026-09-19 | 1 |
The schema
```tables
{
"tables": [
{
"name": "customers",
"tab": "Customers",
"key": [
"exporter",
"customer"
],
"columns": [
{
"name": "exporter",
"required": true
},
{
"name": "customer",
"required": true
},
{
"name": "customer city"
},
{
"name": "first seen",
"type": "date",
"required": true
},
{
"name": "last seen",
"type": "date",
"required": true
},
{
"name": "shipments",
"type": "integer",
"required": true,
"min": 1
}
]
}
]
}
```
```tla
---- MODULE Business ----
EXTENDS Workbook, Naturals, Sequences
VARIABLE ok
Init == ok = TRUE
Next == UNCHANGED ok
Spec == Init /\ [][Next]_ok
\* A customer is first seen no later than it is last seen.
SeenInOrder == \A i \in DOMAIN customers : customers[i].first_seen <= customers[i].last_seen
\* One shipment can only have been seen on one day.
OneShipmentOneDay == \A i \in DOMAIN customers :
customers[i].shipments = 1 => customers[i].first_seen = customers[i].last_seen
====
```
```cfg
SPECIFICATION Spec
INVARIANT SeenInOrder
INVARIANT OneShipmentOneDay
```
Refused by TLC: setting row 2’s first seen to “2026-10-01” breaks SeenInOrder, OneShipmentOneDay.
4. Outreach to importers
The importers worth a message, why each, and how far the conversation got. A stage past `new` must say when the importer was contacted, and a reply must come after the contact.
| importer | why them | stage | contacted on | replied on | source |
|---|---|---|---|---|---|
| Marin Mountain Bikes Inc | 5,711 bicycle shipments in 12 months, from ID and VN | new | https://billofladingdata.com/ | ||
| Giant Bicycle Inc | 3,943 bicycle shipments, from VN and TW | new | https://billofladingdata.com/ | ||
| Trek Bicycle Corporation | 2,121 bicycle shipments, from VN and CN | new | https://billofladingdata.com/ |
The schema
```tables
{
"tables": [
{
"name": "outreach",
"tab": "Outreach",
"key": [
"importer"
],
"columns": [
{
"name": "importer",
"required": true,
"unique": true
},
{
"name": "why them",
"required": true
},
{
"name": "stage",
"type": "choice",
"values": [
"new",
"contacted",
"replied",
"meeting",
"won",
"lost"
],
"required": true
},
{
"name": "contacted on",
"type": "date"
},
{
"name": "replied on",
"type": "date"
},
{
"name": "source",
"type": "url",
"required": true
}
]
}
]
}
```
```tla
---- MODULE Business ----
EXTENDS Workbook, Naturals, Sequences
VARIABLE ok
Init == ok = TRUE
Next == UNCHANGED ok
Spec == Init /\ [][Next]_ok
Past(s) == s \in {"contacted", "replied", "meeting", "won", "lost"}
Answered(s) == s \in {"replied", "meeting", "won"}
\* A stage past "new" says when the importer was contacted.
ContactedHasADate == \A i \in DOMAIN outreach :
Past(outreach[i].stage) <=> outreach[i].contacted_on /= ""
\* A reply has a date, and it comes after the contact.
RepliesFollowContact == \A i \in DOMAIN outreach :
Answered(outreach[i].stage) =>
/\ outreach[i].replied_on /= ""
/\ outreach[i].replied_on >= outreach[i].contacted_on
====
```
```cfg
SPECIFICATION Spec
INVARIANT ContactedHasADate
INVARIANT RepliesFollowContact
```
Refused by TLC: setting row 1’s stage to “contacted” breaks ContactedHasADate, RepliesFollowContact.
Keeping them current
In a workbook’s run, or in your own agent over MCP, the trade program reads the same records. A company’s page is read once and kept for thirty days for every account, so a second question about it is free; Bill of Lading Data is asked only for what that page cannot answer, such as an HS code on each line or the importers of a code, and is billed per record it returns.
$ trade search importers 0902.40 # who imports black tea, ranked $ trade company shipments harney-sons-tea --hs 0902 --from 2026-01-01 $ trade supplier customers jen-ming-ritz # a rival exporter's customers
What these records cannot say
They cover sea imports into the US; goods that come by air, truck or rail are mostly absent. A consignee can be a forwarder, a warehouse or a marketplace (Amazon.com Services is eighth in black tea), so a ranking is a list of names to check, not of buyers. A filer can mark its records confidential, and some of the largest importers do. We leave out shipment value: the records carry an estimate on too few lines for a ranking by it to mean anything, so the rankings are by shipments.
More head-to-head evals
| Measure | GLM-5.3 | DeepSeek V4.1 Flash |
|---|---|---|
| Right, of 75 | 75 | 71 |
| Seconds a question, median | 3.9 | 1.8 |
| Measure | First run | Best since |
|---|---|---|
| Landscape, seconds | 937 | 233 |
| Memo, seconds | 759 | 602 |
| Measure | Qwen3 235B | GLM-5.2 | Gemini 3.8 Flash | Claude Opus 5 |
|---|---|---|---|---|
| Seconds to the plan, median | 27 | 48 | 57 | 94 |
| Plans written, of three runs | 2 | 3 | 3 | 3 |
| Measure | SubQ | jev | Decider | Nimble |
|---|---|---|---|---|
| Found, mean of five columns at section length | 64% | 65% | 66% | 68% |
| Mechanism of action, found at section length | 57% | 51% | 61% | 54% |
| Measure | ask | Apollo | treg |
|---|---|---|---|
| Usable leads | 13 of 40 | 7 of 40 | 6 of 28 |
| Cost per usable lead | $0.037 | $0.27 | $0.23 |
| Measure | ask with jev | ask with Decider |
|---|---|---|
| Questions right, of 92 | 89 | 89 |
| Wrong answers | 1 | 2 |
| Measure | jev | ask |
|---|---|---|
| Our 370 clinical decisions, right | 94.6% | 93.0% |
| PubMedQA, right (best EdgeEvals scored: 62.2%) | 77.0% | 74.4% |
| Measure | ask | Claude Opus 5.5 |
|---|---|---|
| Questions right, of 95 | 59 | 63 |
| Small companies right, of 20 | 13 | 9 |
| Measure | realestate-us | Best of four assistants |
|---|---|---|
| Floor-plan rents right, of 26 | 26 | 23 |
| Amenities claimed the listing doesn't state | 12 | 129 |
| Measure | ask | jev |
|---|---|---|
| Right, of the questions answered | 98% | 79% |
| Wrong answers, of 92 | 2 | 19 |
| Measure | Trained localiser | Best of four frontier models |
|---|---|---|
| Mean overlap with the defect (IoU, 0 to 1) | 0.421 | 0.109 |
Bill of Lading Data