Skip to content

[RFC] Store-Based Local Inventory & Fulfillment Options #375

@maximenajim

Description

@maximenajim

RFC: Store-Based Local Inventory & Fulfillment Options

New capability: dev.ucp.shopping.locations
Extended capabilities: dev.ucp.shopping.fulfillment, dev.ucp.shopping.catalog.search, dev.ucp.shopping.catalog.lookup, dev.ucp.shopping.order
Staged rollout: 3 PRs — Foundation → Methods → Locations & Availability (see Appendix A)


Summary

This RFC proposes extensions to the Unified Commerce Protocol (UCP) to support
store-based local inventory visibility and expanded fulfillment options
beyond the current shipping and pickup method types. Today, UCP treats
product availability as a single global boolean and limits fulfillment to two
method types. This is insufficient for retailers that operate thousands of
physical locations, each with independent inventory, and offer fulfillment
modes such as same-day delivery, curbside pickup, and buy-online-pickup-in-store
(BOPIS).

This proposal introduces:

  1. A per-location, per-method inventory availability model, with a business
    opt-in for disclosure (retailers with competitively sensitive per-SKU
    per-store inventory can participate in pickup without disclosing it)
  2. An enriched retail location entity with first-class holiday/exception hours
  3. Distinct types for customer-visible fulfillment origins vs. internal
    fulfillment nodes (with structural, not prose, enforcement of the
    visibility boundary)
  4. Two new fulfillment method types (curbside, local_delivery) with
    qualifiers for origin and transfer scenarios, plus a documented criterion
    for what promotes a method to top-level status
  5. Quantity-aware line_item_ids[] so a single line item can split across
    fulfillment methods (e.g., 2 pickup + 3 shipped)
  6. Location-aware catalog search and lookup (the canonical place for
    per-variant per-location availability)
  7. A standalone Locations capability (locations-only, no per-variant
    inventory — that lives in catalog)
  8. Post-purchase lifecycle events for pickup and local delivery flows, with
    corrected tracking_number semantics
  9. A first-class Fulfillment Option Eligibility model so membership-gated
    options (e.g., "Circle 360 members get free same-day delivery") have a
    concrete resolution story
  10. MUST-level privacy rules for buyer geo, with platform-derived coarse geo
    routed through the signals mechanism

Scope boundary: This RFC explicitly defers digital (already handled by
UCP via omitting fulfillment), in_store_only (modeled as an availability
restriction, not a checkout method), and treats ship_from_store /
ship_to_store as qualifiers on existing methods rather than new top-level
types. See Design Rationale.


Motivation

The Problem

Modern omnichannel retailers maintain inventory across thousands of stores and
distribution centers. Customers increasingly expect to:

  • See what's available nearby — "Is this in stock at my local store?"
  • Choose how they get it — Ship to home, pick up in store, curbside,
    same-day delivery from a nearby store
  • Get it fast — Same-day or next-day fulfillment from local inventory

UCP's current model cannot express these scenarios:

  1. Variant availability is globalvariant.availability is a single
    { available: boolean, status: string } with no per-location granularity.
    A platform cannot tell a buyer "in stock at Store A, out of stock at
    Store B," nor can it express that an item is available for pickup but not
    for local delivery at the same location.

  2. Fulfillment method types are limited — The fulfillment_method.type
    enum only includes "shipping" and "pickup". There is no way to represent
    local_delivery or curbside as first-class method types with distinct
    buyer experiences.

  3. Retail location is underspecifiedretail_location.json only has id,
    name, and optional address. There are no fields for geo-coordinates,
    operating hours, store type/format, distance from buyer, phone number,
    capabilities, or services offered.

  4. No location context from buyercontext.json has postal_code and
    address_region but no latitude/longitude for proximity-based experiences.
    The existing eligibility array can signal membership claims via
    reverse-domain names, but there is no structured mechanism for fulfillment
    eligibility decisions beyond opaque string claims.

  5. Catalog search and lookup are location-unaware — There is no mechanism
    to filter or rank catalog results by store-level availability.
    catalog_search.json has no location filter, and catalog_lookup.json
    (where PDP-style "is this in stock near me?" queries occur) has no way to
    request per-location availability.

  6. No location-finding capability — There is no API to discover nearby
    stores, check which stores carry a product, or find the closest store
    with inventory.

  7. No fulfillment origin — Post-purchase, there is no way to communicate
    which store or warehouse is fulfilling an order. fulfillment_group.json,
    expectation.json, and fulfillment_event.json all lack an origin field.

  8. Post-purchase events are shipment-centricfulfillment_event.type
    covers processing, shipped, in_transit, delivered, etc. There are no
    event types for pickup readiness (ready_for_pickup), curbside arrival
    (arrived), local delivery dispatch (out_for_local_delivery), or store
    transfer arrival (arrived_at_store). The existing schema also says
    tracking_number is "required if type != processing" — which is incorrect
    for in-store events.

  9. No structured unavailability reasons — When a fulfillment method is
    unavailable, there is no machine-readable reason — only a human-readable
    description. Platforms cannot programmatically suggest alternatives.

  10. No pickup windows, hold durations, or order cutoffs — There is no way
    to express when an order will be ready for pickup, how long a store will
    hold it, or the deadline to place an order for a given fulfillment option.

  11. No quantity-aware split fulfillmentfulfillment_method.line_item_ids
    is string[], meaning each line item belongs to exactly one method.
    Retailers routinely satisfy one quantity locally and others from a DC
    (e.g., "2 ready for pickup, 3 ship tomorrow"). UCP cannot express this.

  12. No first-class membership-gated fulfillment eligibility — Many
    retailers offer member-only fulfillment (e.g., Circle 360 → free Shipt
    same-day delivery, Walmart+ → free grocery delivery). context.eligibility
    provides claims but there is no protocol-level binding between a claim
    and a fulfillment option.

Who Benefits

  • Platforms (agents): Can present location-aware availability, show nearby
    store options, and offer richer fulfillment choices without custom
    integrations per retailer.
  • Businesses (retailers): Can expose their omnichannel capabilities through
    UCP rather than requiring buyers to fall back to continue_url for
    store-specific flows. Retailers with sensitive per-store inventory can
    opt out of disclosure while still supporting pickup.
  • Buyers: Get faster, more transparent fulfillment with visibility into
    local availability and options.

Goals

  • Enable per-location, per-method inventory availability queries through UCP
    (with business opt-in to per-store inventory disclosure)
  • Extend the fulfillment method type enum with two new buyer-facing primitives:
    curbside and local_delivery
  • Model ship_from_store and ship_to_store as qualifiers (origin on groups
    and transfer flag on groups) rather than top-level method types
  • Enrich the retail_location entity with geo-coordinates, weekly hours,
    first-class exception_hours (for holidays/remodels/temporary hours),
    capabilities, distance, contact information, store format, and status
  • Introduce separate customer_visible_origin and internal_origin types
    (unified by a fulfillment_origin oneOf) so internal fulfillment nodes
    structurally cannot carry rendered fields
  • Add buyer location context (lat/lng) to context.json with MUST-level
    privacy rules; route platform-derived coarse geo through the existing
    signals mechanism
  • Add structured unavailability reasons (closed enum) distinct from
    availability status
  • Add pickup windows, hold durations, order cutoff times, and minimum order
    quantities to fulfillment options
  • Add post-purchase event types for pickup and local delivery lifecycle,
    with corrected tracking_number semantics
  • Enable location-aware catalog search and lookup (the canonical home for
    per-variant per-location availability)
  • Define a standalone dev.ucp.shopping.locations capability (locations-only;
    inventory queries are catalog operations)
  • Introduce quantity-aware line_item_ids[] so split-quantity fulfillment
    across methods is expressible
  • Define a first-class eligibility-option binding for membership-gated
    fulfillment
  • Maintain backward compatibility — existing shipping and pickup flows
    remain unchanged

Non-Goals

  • Internal order routing/allocation logic — UCP does not dictate how a
    business decides which store fulfills an order; it only provides the
    interface to expose options and status to platforms.
  • Real-time inventory count exposure — UCP will express availability
    status per location per method, not exact stock quantities (which are
    operationally sensitive).
  • Store operations workflows — Pick lists, hold bins, employee handhelds,
    and internal store processes are out of scope.
  • Delivery zone management UI — Businesses define their service areas
    internally; UCP provides the interface to express availability per method
    per location.
  • Third-party delivery provider integration — UCP models the fulfillment
    option; the business manages its relationship with delivery providers.
  • Digital fulfillment — UCP already handles digital goods by allowing
    checkout fulfillment to be omitted and by including digital in
    expectation.method_type. This RFC does not add digital as a new
    fulfillment method type.
  • In-store-only as a checkout method — Items only purchasable in-store are
    modeled as availability restrictions (method_availability with
    unavailability_reason: "in_store_only" on all non-store methods), not as
    a selectable fulfillment method in the checkout flow.
  • Age-verification / prescription workflows — Regulated items (alcohol,
    pharmacy) are flagged via unavailability_reason: "restricted" or
    "in_store_only", but the identity-verification workflow is out of scope
    and expected to land in a separate RFC coordinated with the identity-linking
    mechanism registry.

Protocol Integration Model

This RFC follows UCP's existing extension pattern as documented in the
fulfillment specification's "Adding New Methods" section, with a small
governance clarification:

  1. New method types (curbside, local_delivery) are
    protocol-blessed additions to the base fulfillment_method.type enum,
    not retailer-specific extensions. §12
    updates fulfillment.md's "Adding New Methods" section to distinguish
    two paths:

    • Protocol-blessed methods (like these): added to the base enum via
      an RFC and a dev.ucp.shopping.fulfillment capability version bump.
    • Vendor-defined methods: still require an extension schema and
      reverse-domain naming.
  2. Enriched retail_location, new types (customer_visible_origin,
    internal_origin, fulfillment_origin, location_availability,
    method_availability, availability_summary), and new fields on existing
    types are additive schema changes.

  3. dev.ucp.shopping.locations is a new standalone capability, declared
    via capability negotiation in the business profile. Platforms that don't
    support it simply don't call it.

  4. Location-aware catalog extends catalog_search.json and
    catalog_lookup.json with optional location_filter. Per-variant,
    per-location availability is returned via catalog, not via the locations
    capability (see §10 for the rationale).

Proposed staged rollout

This RFC lands as three sequenced PRs to make review tractable:

  1. Foundation PRretail_location (enriched with geo, hours, exception
    hours, capabilities, etc.), customer_visible_origin, internal_origin,
    fulfillment_origin (oneOf), origin on fulfillment_group,
    expectation, and fulfillment_event, context.geo privacy rules, and
    the new signals["dev.ucp.shopping.geo"] signal.
  2. Methods PR — New method types (curbside, local_delivery),
    fulfillment_option enhancements (windows, hold, cutoff, eligibility
    depend-on), transfer_origin on fulfillment_group, fulfillment_event
    new event types + corrected tracking_number semantics, quantity-aware
    line_item_ids[], business_fulfillment_config four-way matrices and
    disclosure toggles, and cleanup of the merchant_fulfillment_config.json
    duplicate.
  3. Locations & Availability PRdev.ucp.shopping.locations capability,
    location_availability and method_availability types,
    availability_summary, location_filter on catalog,
    business_fulfillment_config.discloses_location_availability.

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