Skip to Content
APILanded Cost Route Contract

Landed Cost Route Contract

Status: Active
Version: v1
Last updated: 2026-03-20

This document is the normative contract for POST /api/trade/landed-cost.

It is intentionally documented separately outside the versioned public API contract pack described in docs/api/public-api-contract-v1.md. The public pack remains scoped to signup, billing, jobs, SIMA, and upload routes. POST /api/trade/landed-cost is an authenticated tenant trade route documented separately here.

Route and auth

  • Route: POST /api/trade/landed-cost
  • Auth: Clerk bearer token or integration auth (Authorization: Bearer ... or compatibility x-api-key + x-org-id)
  • Customer-facing authority source is destination-aware: OPENCLAW for US/default, OPENCLAW_CBSA for Canada, OPENCLAW_HMRC for UK, OPENCLAW_TARIC for EU member states.
  • Catalog refresh uses the same destination-aware source selector as the public landed-cost route.

Request contract

Required fields:

  • productValue
  • hsCode
  • originCountry
  • destinationCountry

Optional fields:

  • shippingCost
  • insurance
  • currency
  • quantity
  • quantityUnit
  • provider
  • description

Quantity-aware rules:

  • quantity is a positive decimal representing the total customs quantity for the shipment line matched to the HS code.
  • quantityUnit must be one of: KGM, LTR, DZN, TNE.
  • quantity and quantityUnit must be provided together
  • Quantity is preserved as provided in the first slice; no rounding or unit conversion occurs.

Currency rules:

  • currency is an optional 3-letter ISO 4217 code (e.g. EUR, USD, GBP).
  • When provided, the engine evaluates de minimis thresholds for the destination country. Without currency, de minimis evaluation is skipped.
  • If currency does not match the threshold currency for the destination, the response includes deMinimis.skipped: 'currency_mismatch' (no exemption applied, threshold still reported).
  • For EU destinations, currency also drives the low-value trust gate: EUR values at or below the €150 IOSS boundary return trust.level: 'indicative'; non-EUR currencies return trust.level: 'undetermined'.

Provider comparison rules:

  • provider enables tenant-scoped external comparison for legacy value-only requests.
  • provider comparison does not support quantity-aware landed-cost requests yet
  • Quantity-aware requests with provider return 400 INVALID_REQUEST.
  • Provider comparison only runs when currency is explicitly supplied and equals 'USD'. Omitting currency or supplying any non-USD value skips provider comparison (the response includes the internal result with providerSkipReason: 'non_usd_corridor').

Example requests

Value-only request:

{ "productValue": 100.0, "hsCode": "6109.10.00", "originCountry": "CN", "destinationCountry": "US", "shippingCost": 50.0, "insurance": 10.0 }

Quantity-aware request:

{ "productValue": 100.0, "hsCode": "2207.20.00", "originCountry": "CN", "destinationCountry": "CA", "shippingCost": 50.0, "insurance": 10.0, "quantity": 2.0, "quantityUnit": "KGM" }

Provider comparison request:

{ "productValue": 100.0, "hsCode": "6109.10.00", "originCountry": "CN", "destinationCountry": "US", "provider": "zonos", "description": "Cotton knit t-shirt" }

Response notes

  • Authoritative and rate_not_available responses report the customer-facing source selected for the request destination.
  • Canada requests (destinationCountry=CA) report metadata.sourceCode = "OPENCLAW_CBSA" when the authoritative engine resolves through the CBSA source.
  • Quantity-aware duty-expression evaluation is supported for the first landed-cost CBSA formula slice only; unsupported expressions remain status: "rate_not_available" with metadata.unsupportedExpression = true.

Contract boundaries

  • CLAUDE.md is a route index, not the full normative contract.
  • docs/postman/RGL8R-API.postman_collection.json is a first-party request example surface and must stay aligned with this document.
  • packages/mcp-server/src/tools/landed-cost.ts is a first-party tool surface and must stay aligned with this document.
  • apps/docs/content/public/... is generated from docs/ and must not be edited directly.