Skip to content

Shipping financial fields: shippingCost, shippingInsurance, additionalFees #47

@codeal-ltd

Description

@codeal-ltd

Originally opened in: https://github.com/commerce-operations-foundation/mcp-reference-server/pull/24

These three fields feed into the customs-assessed value calculation. Their treatment varies by destination country: in some markets shipping cost and insurance are included in assessed value, in others excluded. The reviewer queried the scope of shippingInsurance specifically (insured amount, provider, coverage type). The author's view is that these are standard customs declaration entries, rarely populated but structurally required. Decision needed on whether to group these under a ShippingCharges or similar node, and what metadata shippingInsurance needs beyond the numeric value.

What the existing schema tells us:

  • shippingPrice (number) already exists as a flat header field in the current schema
  • The PR proposes adding shippingInsurance (number) and additionalFees (number) at the same flat level
  • The reviewer flagged shippingInsurance as too vague and questioned whether these belong grouped

The core problem - These three amounts feed the customs assessed value calculation, but their treatment varies by destination country. Some markets include shipping and insurance in the dutiable value (CIF basis), others exclude them (FOB basis). A flat number with no metadata gives the TMS no way to determine which calculation to apply. The adapter ends up hardcoding country rules rather than reading them from the order.

"shippingCharges": {
  "type": "object",
  "description": "Shipping-related charges collected by the seller. Used in customs assessed value calculations. Treatment varies by destination country: CIF markets include shippingCost and insuranceAmount in dutiable value; FOB markets exclude them. Currency follows the order-level currency field.",
  "properties": {
    "shippingCost": {
      "description": "Freight charge collected from the end customer at checkout. Distinct from the actual carrier cost paid by the seller. Included in customs assessed value in CIF-basis markets.",
      "type": "number"
    },
    "insuranceAmount": {
      "description": "Declared insurance value for the shipment. Standard field in customs declarations. Included in customs assessed value in CIF-basis markets, excluded in FOB-basis markets. Rarely populated in ecommerce but structurally required for full customs compliance.",
      "type": "number"
    },
    "additionalFees": {
      "description": "Any other charges collected at checkout that are not freight or insurance (e.g. handling fees, remote area surcharges passed to the customer). Impacts customs assessed value where declared.",
      "type": "number"
    },
    "customsValuationBasis": {
      "description": "The valuation method that applies to this shipment, determining which charges are included in the dutiable value. CIF includes shippingCost and insuranceAmount; FOB excludes them. Defaults to CIF where not specified, as this is the more common international standard.",
      "type": "string",
      "enum": ["CIF", "FOB", "CFR"]
    },
    "sellerPaidShipping": {
      "description": "True if the seller absorbs the freight cost and shippingCost is zero or not passed to the customer (e.g. free shipping promotion). Informs customs that the declared shipping charge is not a buyer cost.",
      "type": "boolean"
    }
  },
  "additionalProperties": false
}

shippingCost replaces shippingPrice from the existing flat field. The rename is worth raising with the group: shippingPrice is ambiguous between what the seller charged the customer and what the carrier charged the seller. shippingCost in this node is explicitly the customer-facing charge from checkout.

insuranceAmount rather than shippingInsurance. The reviewer's objection was that the original field name was too vague: who provides the insurance, what is it for. The description resolves this: it is the declared insurable value of the shipment for customs declaration purposes, not a product sold by the seller. Renaming makes the purpose unambiguous.

customsValuationBasis is the critical addition. Without it, every TMS adapter has to maintain a country-level lookup table to determine whether to include shipping and insurance in the dutiable value. Declaring it on the order means the WMS or seller platform, which has the trade lane context at order creation time, sets it explicitly. The TMS reads it and builds the customs entry accordingly.

sellerPaidShipping handles the free-shipping case cleanly. A shippingCost of zero is ambiguous: it could mean the seller charged nothing, or that the field was not populated. The boolean removes that ambiguity and prevents the TMS from incorrectly declaring a zero freight charge to customs, which can trigger queries from some authorities.

Relationship to the full cross-border schema structure:

order (header)
├── crossBorderParties          party identity and regulatory IDs
├── crossBorderCharges          taxes and duties collected at checkout
   ├── taxCollected
   ├── dutyCollected
   ├── duties[]                typed duty breakdown
   ├── taxScheme
   ├── iossNumber
   └── ddpElected
├── shippingCharges             shipping financials for customs valuation
   ├── shippingCost
   ├── insuranceAmount
   ├── additionalFees
   ├── customsValuationBasis
   └── sellerPaidShipping
├── incoterms                   existing flat field
└── reasonForExport             proposed enum

Interaction between nodes
ddpElected in crossBorderCharges and customsValuationBasis in shippingCharges are related but distinct. DDP tells the customs authority that the seller has pre-collected all duties and taxes. The valuation basis tells customs how to calculate what those duties should be. Both are needed. A DDP shipment still needs a declared CIF or FOB value to validate that the pre-collected amounts are correct.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions