Skip to content

Clarify itemized fee support in totals[] #219

@maximenajim

Description

@maximenajim

Context

The UCP total.json schema already defines "fee" as a valid type enum value in the totals[] array, but the specification does not document:

  • Whether multiple type: "fee" entries are permitted in the same totals[] array
  • How platforms should render multiple fees (collapsed vs. itemized)
  • How fees interact with the total calculation formula
  • Whether fees can appear at different levels (checkout, line item, fulfillment option)
    Businesses implementing UCP have no guidance on how to express itemized fees (e.g., service fees, handling fees, recycling fees, convenience fees).

Proposal

We propose documenting the following semantics for type: "fee" entries.

  1. Multiple fee entries are allowed
    A business MAY include multiple type: "fee" entries in the same totals[] array. Each entry represents a distinct, itemized charge:
{
  totals: [
    {type: subtotal, display_text: Subtotal, amount: 5000},
    {type: fee, display_text: Service Fee, amount: 200},
    {type: fee, display_text: Handling Fee, amount: 150},
    {type: fee, display_text: Gift Wrap Fee, amount: 350},
    {type: fulfillment, display_text: Standard Shipping, amount: 500},
    {type: tax, display_text: Tax, amount: 520},
    {type: total, display_text: Total, amount: 6720}
  ]
}
  1. Total calculation formula includes all fees
    total = subtotal - discount + fulfillment + tax + fee₁ + fee₂ + ... + feeₙ

  2. Fees at multiple levels
    Fees MAY appear at any level where totals[] exists:

  • Checkout-level: $.totals[]
  • Line-item-level: $.line_items[].totals[]
  • Fulfillment-option-level: $.fulfillment_options[].totals[]

Key Design Question: Should fees be a formal Extension like Discounts?

Option A: Document within existing totals[]

Fees remain a type value in the existing Total schema. No new schema files, no capability registration. This is the minimal approach — it clarifies what's already structurally possible.

Pros:

  • No new schemas
  • Fees are conceptually simpler than discounts (no codes, no stacking, no allocations)
  • Already works today — just needs documentation

Cons:

  • No structured metadata (no way to express fee reason, legal / regulatory disclosures, tax applicability, whether fee is waivable, etc.)
  • No capability discovery — platforms can't know in advance if a business will include fees
  • No allocation breakdown — can't express "this fee is because of line item X"
  • Limited to display_text + amount — not machine-readable

Option B: Create a Fee Extension

Create fee.json with structured fee types, a fees object on checkout, and capability registration via dev.ucp.shopping.fee.
This could enable:

  • Fee discovery: Business advertises dev.ucp.shopping.fee so platforms know to expect and render fees
  • Structured fee objects: applied_fee with title, type (service, handling, recycling, convenience, etc.), taxable boolean, waivable boolean
  • Fee allocations: Link fees to specific line items or fulfillment options
  • Fee negotiation: Platform could potentially request fee waivers or adjustments

Pros:

  • Machine-readable fee metadata
  • Platform can adapt UI based on fee capability discovery
  • Future-proof for fee negotiation, fee itemization in receipts, etc.

Cons:

  • May be over-engineering for a feature that's simpler than discounts
  • Requires new schema file, spec page, capability registration

Open Questions

Q1: Uniqueness constraints

Are there any uniqueness constraints on type within a totals[] array? Should we formally state that subtotal, discount, fulfillment, tax, and total MUST appear at most once, while fee MAY appear multiple times?

Q2: Is display_text required for fees?

The schema marks display_text as optional. For fees, should it be effectively REQUIRED (SHOULD vs. MUST) since a fee without a label is not useful to the buyer?

Q3: Fee ordering

Should the spec prescribe a canonical ordering of type values in totals[]? (e.g., subtotal → discount → fee → fulfillment → tax → total)

Q4: Fee aggregation for line-item fees

When a fee appears in both line_items[].totals[] AND checkout-level totals[], should the checkout-level fee be the sum of line-item fees of the same kind? Or are they independent?

Q5: Impact on other schemas

total.json is shared across checkout.json, cart.json, order.json, line_item.json, order_line_item.json, and fulfillment_option.json. Do the same fee rules apply uniformly across all contexts?

Metadata

Metadata

Assignees

No one assigned

    Labels

    TC reviewReady for TC review

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions