How Universal Commerce Protocol (UCP) Handles Capability Negotiation Between Platforms and Businesses
UCP handles capability negotiation through a deterministic five-step process where platforms fetch business discovery profiles, intersect capability sets by ISO-date version, prune orphaned extensions, validate constraint requirements, and compose final schemas for payload validation.
The Universal Commerce Protocol (UCP) separates protocol-version compatibility from capability negotiation to enable flexible integrations between commerce platforms and business systems. According to the Universal-Commerce-Protocol/ucp source code, businesses act as servers publishing discovery profiles while platforms serve as clients that compute active capabilities through a deterministic intersection algorithm. This process ensures that only mutually supported features activate for each session, with strict validation against schemas defined in source/schemas/ucp.json and related specification files.
Discovery Profile Retrieval at /.well-known/ucp
The negotiation begins when a platform retrieves the business's discovery profile from the /.well-known/ucp endpoint. This JSON document must conform to the UCP Discovery Profile schema defined in source/discovery/profile_schema.json, which specifies the structure for both $defs/platform_profile and $defs/business_profile objects. The profile contains the business's advertised capabilities, supported protocol versions, and service definitions, serving as the authoritative source for the intersection algorithm.
Businesses may also advertise version-specific URLs through supported_versions fields, allowing platforms to select appropriate endpoints. The core metadata schema in source/schemas/ucp.json defines the capabilities, services, and payment_handlers objects that appear within these discovery documents.
The Capability Intersection Algorithm
The platform executes the Intersection Algorithm described in docs/specification/overview.md to determine which capabilities are active for the session. For each capability name present in both the business profile and the platform's own capability list, the algorithm selects the highest mutually-supported version using ISO-date version strings that sort chronologically.
def intersect(biz_caps, plat_caps):
result = {}
# 1. Compute intersection of names
for name, biz_versions in biz_caps.items():
if name not in plat_caps:
continue
# 2. Select highest common version
common = set(v["version"] for v in biz_versions) & \
set(v["version"] for v in plat_caps[name])
if not common:
continue
result[name] = max(common) # ISO-date strings sort correctly
# 3. Prune orphaned extensions
changed = True
while changed:
changed = False
for name, ext in list(result.items()):
if "extends" in ext:
parents = ext["extends"] if isinstance(ext["extends"], list) else [ext["extends"]]
if not any(p in result for p in parents):
del result[name]
changed = True
return result
If a capability name exists only in one party's list, or if no common version exists between the two sets, that capability is immediately dropped from consideration.
Extension Pruning and Dependency Resolution
Capabilities that extend others through the extends property require special handling during negotiation. As defined in source/schemas/capability.json, an extension survives only if at least one of its parent capabilities remains in the intersection set. The platform iteratively removes orphaned extensions—those whose parents were dropped during version conflict resolution—until no more capabilities are removed.
This pruning handles transitive dependency chains. For example, if capability B extends capability A, and capability C extends capability B, the removal of A triggers the removal of B, which subsequently triggers the removal of C. The algorithm repeats until the capability set stabilizes.
Version Constraint Validation
After intersection and pruning, the platform validates any remaining capabilities against their version constraints. The requires object inside capability definitions—specified in the $defs/requires section of source/schemas/ucp.json—can mandate specific protocol versions or dependent capability versions.
The platform checks that the negotiated protocol version satisfies requires.protocol constraints and that any required capability versions are present in the active set. Capabilities failing these checks are excluded from the final composition, ensuring that the platform never attempts to use features with unmet dependencies.
Schema Composition and Payload Validation
With the final capability set determined, the platform fetches the base schemas and any extension schemas, composing them using JSON Schema's allOf directive according to the Schema Resolution Convention in the specification. This merged schema validates all subsequent request and response payloads exchanged during the session.
The composition process treats capabilities as modular units, allowing extensions to augment base functionality while maintaining strict validation guarantees. Each capability's spec and schema references from the discovery profile drive this final assembly stage.
Error Handling and Fallback Mechanisms
When any negotiation step fails—whether due to empty capability intersections, unsatisfied version constraints, or schema composition errors—UCP returns a negotiation-failure response with status: "error" and a specific error code such as capabilities_incompatible. As documented in docs/specification/overview.md#error-handling, the response may include an optional continue_url field that redirects the shopper to a fallback web checkout flow, allowing transactions to proceed even when protocol-level negotiation cannot succeed.
Summary
- Discovery: Platforms fetch business profiles from
/.well-known/ucpconforming tosource/discovery/profile_schema.json. - Intersection: The algorithm selects the highest common ISO-date version for each capability present in both parties' lists.
- Pruning: Extensions with
extendsreferences are removed iteratively if their parent capabilities are absent, as defined insource/schemas/capability.json. - Validation: The platform enforces
requiresconstraints fromsource/schemas/ucp.jsonagainst the negotiated protocol version. - Composition: Final schemas merge via
allOfto validate session payloads. - Fallback: Negotiation failures return structured errors with optional
continue_urlfor web-based fallbacks.
Frequently Asked Questions
What happens when capability versions don't match between platform and business?
When version sets have no intersection, the platform drops that capability from the active set. The algorithm compares ISO-date version strings and selects the maximum value present in both lists; if the intersection is empty, the capability is excluded from further negotiation steps.
How does UCP handle transitive extension dependencies?
The platform applies iterative pruning to handle transitive chains. If capability B extends A, and C extends B, removing A triggers removal of B, which then triggers removal of C. This process repeats until no orphaned extensions remain, ensuring only capabilities with satisfied dependency graphs activate.
What is the role of the /.well-known/ucp endpoint in capability negotiation?
The /.well-known/ucp endpoint serves as the uniform location where businesses publish their discovery profiles. Platforms initiate negotiation by sending an HTTP GET to this endpoint—or to version-specific URLs from supported_versions—to retrieve the JSON document containing advertised capabilities, versions, and service configurations required for the intersection algorithm.
How does UCP handle negotiation failures?
UCP returns a standardized error response with status: "error" and codes like capabilities_incompatible when negotiation cannot produce a valid capability set. The response may include a continue_url parameter that redirects to a web-based checkout flow, providing a graceful degradation path when protocol-level agreement is impossible.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →