Landed Cost Simulator
Prices a pre-purchase what-if: duty stack, risk-adjusted landed cost, and supplier screen.
Deterministic service. Given a product the importer hasn't yet ordered (or a supplier quote, or a draft PO), runs it through the full agent pipeline and returns a methodology-cited landed cost estimate before the importer signs anything.
This is the agent that turns Commers from "broker software" into "importer software that the broker also uses." It's why the C-suite at an importer comes back, not just the customs ops team.
What it does
Reads a single product line (description + origin + supplier + value + quantity, OR a PDF quote/PO via the Document Extractor) and composes the classifier, denied-party screener, duty calculator, and risk modeler into one trip. Returns a structured landed cost: classification, full duty stack with Federal Register citations, screening result with sanctions-list source, a transparent detention-risk range, and a per- unit landed cost the importer can put in a margin model.
Persisted to the simulations table so the importer can compare runs side-by-side (e.g. "what if we sourced from Vietnam instead of China?").
This isn't a single Claude call — it's a single-purpose orchestrator that calls 4 agents and 1 retrieval layer in sequence. Same shape as the Audit Responder (Agent #7), just at a different point in the lifecycle: Audit Responder fires after clearance, Simulator fires before the PO.
Inputs
Manual entry:
{
description: string; // "100% cotton men's t-shirts, knit, crew neck"
originCountry: string; // "CN"
supplierName: string; // "Xinjiang Western Cotton Trading"
valueCents: number; // 12_000_000 ($120K declared FOB)
quantity: number; // 12_000
mode?: 'ocean_fcl' | 'ocean_lcl' | 'air'; // affects HMF applicability
}
From a document (PDF / image of a quote or PO):
{
file: File; // multipart upload
}
// → extracted by the Document Extractor agent → SimulateInput
Outputs
{
input: SimulateInput;
classification: {
htsCode: string; // "6109.10.0027"
confidence: number; // 82
rationale: string; // cited CROSS rulings
};
screening: {
band: 'block' | 'review' | 'watch' | 'clear';
blocking: boolean;
topHit: { matched, list, score } | null;
hits: ScreeningHit[];
};
duty: {
baseDutyCents: number;
additionalDutyCents: number;
mpfCents: number; // 19 CFR 24.23
hmfCents: number; // 19 CFR 24.24, ocean only
totalDutyCents: number;
effectiveRatePct: number; // 159 for Xinjiang cotton @ China origin
components: Array<{ // every layer with its Federal Register citation
label: string;
source: 'base' | 'trade_program' | 'fee';
program?: string; // "Section 301", "IEEPA China", "Fentanyl Tariff"
rate: number;
valueCents: number;
citation: string; // "USTR Notice 84 FR 43304" etc.
}>;
};
risk: {
detentionProbabilityLow: number;
detentionProbabilityHigh: number;
delayDays: number;
carryingCostCents: number;
responseCostLowCents: number;
responseCostHighCents: number;
expectedAdditionLowCents: number;
expectedAdditionHighCents: number;
};
landed: {
productCostCents: number; // input.valueCents
baseLandedCostCents: number; // product + duty + fees
riskAdjustedLowCents: number; // + risk expected addition low
riskAdjustedHighCents: number; // + risk expected addition high
costPerUnitBaseCents: number;
costPerUnitRiskHighCents: number;
};
flags: Array<{ // high-severity surfaces
level: 'high' | 'medium' | 'low';
category: string;
title: string; // human-readable
detail: string;
}>;
simulationId: string; // persisted; used for history + compare
}
The "marquee" demo number — the 159% effective rate on Xinjiang cotton tees — comes out of this output's duty.effectiveRatePct field. The components array under it lists base (16.5%) + Section 301 List 4A (7.5%) + IEEPA China (125%) + Fentanyl Tariff (10%), each with its Federal Register citation.
When it runs
- Simulation screen — drag a quote, drop a PO, type a product. The primary user-facing surface.
- /api/customs-clearance/simulate — direct JSON POST (importer systems can integrate it as a webhook).
- /api/customs-clearance/simulate/from-document — multipart file upload that auto-extracts first.
- /api/customs-clearance/simulations — list / read history.
- /api/customs-clearance/simulations/:id — single full result.
Every fire persists a row in customs_clearance.simulations so the broker / importer can compare against past runs (different origins, different declared values, different suppliers).
Dependencies
Calls these agents in order:
- HTS Classifier (Agent #1) — gets the 10-digit HTS code + rationale + cited CROSS rulings.
- Denied-Party Screener (Agent #3) — runs the supplier name against
us_trade_csl. Always runs even if classifier confidence is low. - Duty Calculator (Agent #4) — stacks every active trade program (Section 301 / 232 / IEEPA / Fentanyl / etc.) against the assigned HTS + origin.
- Risk Modeler (Agent #5) — produces the detention probability band and the dollar exposure range.
Plus the Document Extractor (Agent #2) when the fire comes from a PDF/image upload.
The Simulator doesn't add any LLM call of its own — it's pure composition + persistence + flag aggregation. It adds no model cost beyond the one Classifier call when a description is provided fresh; the from-document path adds the Document Extractor on top.
What success looks like
| Metric | Target | Today |
|---|---|---|
| Methodology coverage — every number traces to a citation | 100% | ✓ — surfaced via in-app "How this is calculated" modal + How landed cost is calculated |
| Speed (description → full result) | Fast | ✓ — returns a full result in seconds (most of that is the Classifier's model call) |
| Speed (PDF upload → full result) | Fast | ✓ — returns a full result in seconds (Extractor + Classifier run in sequence) |
| Persisted for compare | 100% | ✓ — simulations table, history endpoint |
| Honest about model bands | "modelled, range" labeled in UI | ✓ — risk model is labeled, never asserted as prediction |
What it does NOT do
- Does NOT submit anything to CBP. There is no entry created. No Form 7501. Nothing transmitted. The Simulator is read-only by design.
- Does NOT include freight, insurance, broker fees, or bond cost in the landed cost. The methodology doc explicitly enumerates these exclusions and surfaces "Freight roadmap: Q3" so the importer knows it's intentional, not an omission.
- Does NOT apply specific (per-unit) duty rates. Flagged for broker manual computation.
- Does NOT account for U.S. Note 20(b) Section 301 exclusion granularity yet. Coverage is at the HTS-prefix level. Q3 roadmap.
- Does NOT predict CBP behavior. The Risk Modeler section is explicitly a planning-grade range, not a prediction.
- Does NOT override broker judgment. If a CFO uses the Simulator to commit to a $5M PO, the broker is still required to re-verify at file time. The Simulator's output is decision-support, not the decision.
Roadmap
See Landed cost — what we are still closing for the full plan — every missing cost category with concrete data sources, prioritized build order, partnership patterns, and eval discipline. Highlights:
- Q3 2026 — Freight rate integration (Freightos / Xeneta API) so landed cost includes shipping. Today it's intentionally excluded and flagged; removing the flag will be the visible signal.
- Q3 2026 — U.S. Note 20(b) Section 301 exclusion granularity, so importers running scenarios on goods covered by active exclusions see the lower rate rather than the headline 25/30/etc%.
- Q4 2026 — Multi-line PO support (today the simulator runs on one line at a time; importers want to drop a 20-line PO and see the whole landed cost in one trip).
- Q4 2026 — "What-if" compare mode — pin one simulation as the baseline, then run variants (different origin, different supplier, different HTS) and see the delta side-by-side. Partial: the history page already does paired compare on past runs.
- Q1 2027 — Carbon-intensity field on the simulated line so the result includes the CBAM certificate cost (EU-only, but importers shipping into EU need this).
- Q1 2027 — Webhook subscriptions — when a tariff rate changes, re-run all persisted simulations affected by the change and notify the importer that their landed cost has moved.
How this differs from a real entry filing
A Simulation is a dry run. It uses the same agents and the same methodology as a real entry, but:
| Aspect | Simulation | Real entry filing |
|---|---|---|
| Persistence | simulations table | shipments + line_items + … |
| State machine | none — terminal at result | draft → ai_review → ready → filed → cleared |
| CBP transmission | never | yes (via Autopilot's transmit action) |
| Authoritative | no — decision-support | yes — broker signs |
| Broker required | no — importer can run themselves | yes |
The same agents power both. The Simulator just chains them at a different point in the importer's purchase lifecycle.
Put your own book of entries through Commers.