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:
- 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)
- An enriched retail location entity with first-class holiday/exception hours
- Distinct types for customer-visible fulfillment origins vs. internal
fulfillment nodes (with structural, not prose, enforcement of the
visibility boundary)
- 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
- Quantity-aware
line_item_ids[] so a single line item can split across
fulfillment methods (e.g., 2 pickup + 3 shipped)
- Location-aware catalog search and lookup (the canonical place for
per-variant per-location availability)
- A standalone Locations capability (locations-only, no per-variant
inventory — that lives in catalog)
- Post-purchase lifecycle events for pickup and local delivery flows, with
corrected tracking_number semantics
- 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
- 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:
-
Variant availability is global — variant.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.
-
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.
-
Retail location is underspecified — retail_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.
-
No location context from buyer — context.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.
-
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.
-
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.
-
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.
-
Post-purchase events are shipment-centric — fulfillment_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.
-
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.
-
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.
-
No quantity-aware split fulfillment — fulfillment_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.
-
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:
-
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.
-
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.
-
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.
-
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:
- Foundation PR —
retail_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.
- 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.
- Locations & Availability PR —
dev.ucp.shopping.locations capability,
location_availability and method_availability types,
availability_summary, location_filter on catalog,
business_fulfillment_config.discloses_location_availability.
RFC: Store-Based Local Inventory & Fulfillment Options
New capability:
dev.ucp.shopping.locationsExtended capabilities:
dev.ucp.shopping.fulfillment,dev.ucp.shopping.catalog.search,dev.ucp.shopping.catalog.lookup,dev.ucp.shopping.orderStaged 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
shippingandpickupmethod types. Today, UCP treatsproduct 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:
opt-in for disclosure (retailers with competitively sensitive per-SKU
per-store inventory can participate in pickup without disclosing it)
fulfillment nodes (with structural, not prose, enforcement of the
visibility boundary)
curbside,local_delivery) withqualifiers for origin and transfer scenarios, plus a documented criterion
for what promotes a method to top-level status
line_item_ids[]so a single line item can split acrossfulfillment methods (e.g., 2 pickup + 3 shipped)
per-variant per-location availability)
inventory — that lives in catalog)
corrected
tracking_numbersemanticsoptions (e.g., "Circle 360 members get free same-day delivery") have a
concrete resolution story
routed through the signals mechanism
Scope boundary: This RFC explicitly defers
digital(already handled byUCP via omitting fulfillment),
in_store_only(modeled as an availabilityrestriction, not a checkout method), and treats
ship_from_store/ship_to_storeas qualifiers on existing methods rather than new top-leveltypes. See Design Rationale.
Motivation
The Problem
Modern omnichannel retailers maintain inventory across thousands of stores and
distribution centers. Customers increasingly expect to:
same-day delivery from a nearby store
UCP's current model cannot express these scenarios:
Variant availability is global —
variant.availabilityis 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.
Fulfillment method types are limited — The
fulfillment_method.typeenum only includes
"shipping"and"pickup". There is no way to representlocal_deliveryorcurbsideas first-class method types with distinctbuyer experiences.
Retail location is underspecified —
retail_location.jsononly hasid,name, and optionaladdress. There are no fields for geo-coordinates,operating hours, store type/format, distance from buyer, phone number,
capabilities, or services offered.
No location context from buyer —
context.jsonhaspostal_codeandaddress_regionbut no latitude/longitude for proximity-based experiences.The existing
eligibilityarray can signal membership claims viareverse-domain names, but there is no structured mechanism for fulfillment
eligibility decisions beyond opaque string claims.
Catalog search and lookup are location-unaware — There is no mechanism
to filter or rank catalog results by store-level availability.
catalog_search.jsonhas no location filter, andcatalog_lookup.json(where PDP-style "is this in stock near me?" queries occur) has no way to
request per-location availability.
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.
No fulfillment origin — Post-purchase, there is no way to communicate
which store or warehouse is fulfilling an order.
fulfillment_group.json,expectation.json, andfulfillment_event.jsonall lack an origin field.Post-purchase events are shipment-centric —
fulfillment_event.typecovers
processing,shipped,in_transit,delivered, etc. There are noevent types for pickup readiness (
ready_for_pickup), curbside arrival(
arrived), local delivery dispatch (out_for_local_delivery), or storetransfer arrival (
arrived_at_store). The existing schema also saystracking_numberis "required if type != processing" — which is incorrectfor in-store events.
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.
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.
No quantity-aware split fulfillment —
fulfillment_method.line_item_idsis
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.
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.eligibilityprovides claims but there is no protocol-level binding between a claim
and a fulfillment option.
Who Benefits
store options, and offer richer fulfillment choices without custom
integrations per retailer.
UCP rather than requiring buyers to fall back to
continue_urlforstore-specific flows. Retailers with sensitive per-store inventory can
opt out of disclosure while still supporting pickup.
local availability and options.
Goals
(with business opt-in to per-store inventory disclosure)
curbsideandlocal_deliveryship_from_storeandship_to_storeas qualifiers (origin on groupsand transfer flag on groups) rather than top-level method types
retail_locationentity with geo-coordinates, weekly hours,first-class
exception_hours(for holidays/remodels/temporary hours),capabilities, distance, contact information, store format, and status
customer_visible_originandinternal_origintypes(unified by a
fulfillment_originoneOf) so internal fulfillment nodesstructurally cannot carry rendered fields
context.jsonwith MUST-levelprivacy rules; route platform-derived coarse geo through the existing
signals mechanism
availability status
quantities to fulfillment options
with corrected
tracking_numbersemanticsper-variant per-location availability)
dev.ucp.shopping.locationscapability (locations-only;inventory queries are catalog operations)
line_item_ids[]so split-quantity fulfillmentacross methods is expressible
fulfillment
shippingandpickupflowsremain unchanged
Non-Goals
business decides which store fulfills an order; it only provides the
interface to expose options and status to platforms.
status per location per method, not exact stock quantities (which are
operationally sensitive).
and internal store processes are out of scope.
internally; UCP provides the interface to express availability per method
per location.
option; the business manages its relationship with delivery providers.
checkout fulfillment to be omitted and by including
digitalinexpectation.method_type. This RFC does not adddigitalas a newfulfillment method type.
modeled as availability restrictions (method_availability with
unavailability_reason: "in_store_only"on all non-store methods), not asa selectable fulfillment method in the checkout flow.
pharmacy) are flagged via
unavailability_reason: "restricted"or"in_store_only", but the identity-verification workflow is out of scopeand 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:
New method types (
curbside,local_delivery) areprotocol-blessed additions to the base
fulfillment_method.typeenum,not retailer-specific extensions. §12
updates
fulfillment.md's "Adding New Methods" section to distinguishtwo paths:
an RFC and a
dev.ucp.shopping.fulfillmentcapability version bump.reverse-domain naming.
Enriched
retail_location, new types (customer_visible_origin,internal_origin,fulfillment_origin,location_availability,method_availability,availability_summary), and new fields on existingtypes are additive schema changes.
dev.ucp.shopping.locationsis a new standalone capability, declaredvia capability negotiation in the business profile. Platforms that don't
support it simply don't call it.
Location-aware catalog extends
catalog_search.jsonandcatalog_lookup.jsonwith optionallocation_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:
retail_location(enriched with geo, hours, exceptionhours, capabilities, etc.),
customer_visible_origin,internal_origin,fulfillment_origin(oneOf),originonfulfillment_group,expectation, andfulfillment_event,context.geoprivacy rules, andthe new
signals["dev.ucp.shopping.geo"]signal.curbside,local_delivery),fulfillment_optionenhancements (windows, hold, cutoff, eligibilitydepend-on),
transfer_originonfulfillment_group,fulfillment_eventnew event types + corrected
tracking_numbersemantics, quantity-awareline_item_ids[],business_fulfillment_configfour-way matrices anddisclosure toggles, and cleanup of the
merchant_fulfillment_config.jsonduplicate.
dev.ucp.shopping.locationscapability,location_availabilityandmethod_availabilitytypes,availability_summary,location_filteron catalog,business_fulfillment_config.discloses_location_availability.