diff --git a/docs/documentation/core-concepts.md b/docs/documentation/core-concepts.md index a8fbec62b..47d9257bf 100644 --- a/docs/documentation/core-concepts.md +++ b/docs/documentation/core-concepts.md @@ -141,7 +141,7 @@ each declares the date `D` of the UCP release it ships in. Third-party extensions publish versions on their own cadence. The following are examples of capabilities defined in UCP — see the -[Specification](../specification/overview.md) for the authoritative and +[Specification](../specification/overview/index.md) for the authoritative and up-to-date list. | Capability | Description | @@ -165,10 +165,10 @@ core capabilities. { "dev.ucp.shopping.fulfillment": [ { - "version": "2026-04-08", + "version": "{{ ucp_version }}", "extends": "dev.ucp.shopping.checkout", - "spec": "https://ucp.dev/2026-04-08/specification/fulfillment", - "schema": "https://ucp.dev/2026-04-08/schemas/shopping/fulfillment.json" + "spec": "https://ucp.dev/{{ ucp_version }}/specification/fulfillment", + "schema": "https://ucp.dev/{{ ucp_version }}/schemas/shopping/fulfillment.json" } ] } @@ -179,7 +179,7 @@ intersection is automatically pruned. This ensures extension coherence — you never activate a discount extension without the checkout it extends. The following are examples of extensions defined in UCP — see the -[Specification](../specification/overview.md) for the authoritative and +[Specification](../specification/overview/index.md) for the authoritative and up-to-date list. | Extension | Extends | Description | @@ -270,35 +270,35 @@ authentication are resolved together. ```json { "ucp": { - "version": "2026-04-08", + "version": "{{ ucp_version }}", "services": { "dev.ucp.shopping": [ { - "version": "2026-04-08", - "spec": "https://ucp.dev/2026-04-08/specification/overview", + "version": "{{ ucp_version }}", + "spec": "https://ucp.dev/{{ ucp_version }}/specification/overview/", "transport": "rest", - "schema": "https://ucp.dev/2026-04-08/services/shopping/rest.openapi.json", + "schema": "https://ucp.dev/{{ ucp_version }}/services/shopping/rest.openapi.json", "endpoint": "https://business.example.com/ucp/v1" } ] }, "capabilities": { "dev.ucp.shopping.checkout": [{ - "version": "2026-04-08", - "spec": "https://ucp.dev/2026-04-08/specification/checkout", - "schema": "https://ucp.dev/2026-04-08/schemas/shopping/checkout.json" + "version": "{{ ucp_version }}", + "spec": "https://ucp.dev/{{ ucp_version }}/specification/shopping/checkout", + "schema": "https://ucp.dev/{{ ucp_version }}/schemas/shopping/checkout.json" }], "dev.ucp.shopping.fulfillment": [{ - "version": "2026-04-08", - "spec": "https://ucp.dev/2026-04-08/specification/fulfillment", - "schema": "https://ucp.dev/2026-04-08/schemas/shopping/fulfillment.json", + "version": "{{ ucp_version }}", + "spec": "https://ucp.dev/{{ ucp_version }}/specification/fulfillment", + "schema": "https://ucp.dev/{{ ucp_version }}/schemas/shopping/fulfillment.json", "extends": "dev.ucp.shopping.checkout" }] }, "payment_handlers": { "com.example.processor_tokenizer": [{ "id": "processor_tokenizer", - "version": "2026-04-08", + "version": "{{ ucp_version }}", "spec": "https://example.com/specs/payments/processor_tokenizer", "schema": "https://example.com/specs/payments/merchant_tokenizer.json" }] @@ -335,7 +335,7 @@ remains the client's decision. Platforms **MUST** validate this binding for declared `schema` URLs and **MUST** reject entities that fail it. Identifiers carry no fetched URL, and the `spec` (documentation) URL is not authority-bound (any `https` origin). See -[Authority Binding](../specification/overview.md#authority-binding) for the +[Authority Binding](../specification/overview/index.md#authority-binding) for the normative algorithm. The `dev.ucp.*` namespace is reserved exclusively for capabilities governed by @@ -453,7 +453,7 @@ Every UCP-defined service, capability, and extension in release `D` declares version `D`. Third-party extensions and payment handlers are versioned by their authors, independently of UCP releases. -See [Protocol Version](../specification/overview.md#protocol-version) for version -discovery, [Component Versioning and Release Snapshots](../specification/overview.md#component-versioning-and-release-snapshots) +See [Protocol Version](../specification/overview/index.md#protocol-version) for version +discovery, [Component Versioning and Release Snapshots](../specification/overview/index.md#component-versioning-and-release-snapshots) for the normative release contract, and [Versioning](../versioning.md) for the release-branch and backport process. diff --git a/docs/documentation/schema-authoring.md b/docs/documentation/schema-authoring.md index 8d9beb42e..f2c0dda4b 100644 --- a/docs/documentation/schema-authoring.md +++ b/docs/documentation/schema-authoring.md @@ -113,7 +113,7 @@ Define transport bindings that appear in `ucp.services{}` registries. Each trans that service `version` repeats on each entry, and transport bindings have no separate version. The referenced OpenAPI/OpenRPC artifact carries its own `info.version` as artifact metadata, not a negotiated version. See - [Component Versioning and Release Snapshots](../specification/overview.md#component-versioning-and-release-snapshots) + [Component Versioning and Release Snapshots](../specification/overview/index.md#component-versioning-and-release-snapshots) - **Variants**: `platform_schema`, `business_schema` - **Transport requirements** (additional beyond the common base): - Platform profile (`platform_schema`): REST/MCP/Embedded require `schema` (OpenAPI/OpenRPC URL). A2A has no additional requirements. @@ -130,7 +130,7 @@ Define payment handler configurations in `ucp.payment_handlers{}` registries. Examples: `com.google.pay`, `dev.shopify.shop_pay`, `dev.ucp.processor_tokenizer` -**→ See [Payment Handler Guide](../specification/payment-handler-guide.md)** for detailed +**→ See [Payment Handler Guide](../specification/payment/guide.md)** for detailed guidance on handler structure, config/instrument/credential schemas, and the full specification template. @@ -209,7 +209,7 @@ The member name `ucp` is reserved at every structured UCP object scope — an object whose members are schema-defined fields — for the protocol namespace. The top-level envelope is its root manifestation. Dictionary containers are excluded because their keys are data rather than fields. See -[The `ucp` Protocol Namespace](../specification/overview.md#the-ucp-protocol-namespace) +[The `ucp` Protocol Namespace](../specification/overview/index.md#the-ucp-protocol-namespace) for the normative rules. For schema authors this means: - **Never mint a structured domain field named `ucp`.** Schema authors @@ -374,7 +374,7 @@ does not replace negotiation: capabilities and extensions are still selected by exact-version intersection. Profile selection, including profiles for older supported releases, is defined -in [Protocol Version](../specification/overview.md#protocol-version). +in [Protocol Version](../specification/overview/index.md#protocol-version). ### Third-Party Extensions and Payment Handlers @@ -523,7 +523,7 @@ object fields: ## The `request_constraints` Protocol Member Normative processing, scope, lifecycle, and invalid-member behavior are defined -in [Request Constraints](../specification/overview.md#request-constraints). +in [Request Constraints](../specification/overview/index.md#request-constraints). This section covers only the schema-authoring boundary. ### Local structure @@ -583,7 +583,7 @@ admits that container through its optional reference to Every Action type is declared by an extension and becomes available only when that extension is negotiated, as defined in -[Actions](../specification/overview.md#actions). Before advertising support, +[Actions](../specification/overview/index.md#actions). Before advertising support, both the Business and the Platform should assess the extension's complete Action contract. Negotiation is pre-runtime agreement on that contract's semantics and support; it does not pre-approve every future `config` value or @@ -963,7 +963,7 @@ Manual invocation: ```bash python3 scripts/validate_examples.py --schema-base source/schemas/ -python3 scripts/validate_examples.py --schema-base source/schemas/ --file docs/specification/checkout-rest.md docs/specification/cart.md +python3 scripts/validate_examples.py --schema-base source/schemas/ --file docs/specification/shopping/checkout/rest.md docs/specification/shopping/cart/index.md python3 scripts/validate_examples.py --schema-base source/schemas/ --audit ``` diff --git a/docs/index.md b/docs/index.md index 9c2f1de5d..c0f86478d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -312,7 +312,7 @@ image: assets/banner.png

Checkout

Support complex cart logic, dynamic pricing, tax calculations, and more across millions of businesses through unified checkout sessions.

- Get Started + Get Started
@@ -393,7 +393,7 @@ image: assets/banner.png

Identity Linking

OAuth 2.0 standard enables agents to maintain secure, authorized relationships without sharing credentials.

- Get Started + Get Started
@@ -433,7 +433,7 @@ image: assets/banner.png

Order

From purchase confirmation to delivery. Real-time webhooks power status updates, shipment tracking, and return processing across every channel.

- Get Started + Get Started
@@ -609,7 +609,7 @@ image: assets/banner.png

Integrate and negotiate directly with a seller's checkout API to power native UI and workflows for your platform.

- Get Started + Get Started
@@ -620,7 +620,7 @@ image: assets/banner.png

Embed and render business checkout UI to support complex checkout flows, with advanced capabilities like bidirectional communication, and payment and shipping address delegation.

- See how it works + See how it works
@@ -1109,7 +1109,7 @@ image: assets/banner.png
Experiment
-

Experiment

+

Experiment

Experiment with the protocol and its different agent roles

diff --git a/docs/specification/ap2-mandates.md b/docs/specification/ap2-mandates.md index e0fe34936..a6204d376 100644 --- a/docs/specification/ap2-mandates.md +++ b/docs/specification/ap2-mandates.md @@ -75,7 +75,7 @@ Businesses declare support by adding `dev.ucp.shopping.ap2_mandate` to their "dev.ucp.shopping.checkout": [ { "version": "{{ ucp_version }}", - "spec": "https://ucp.dev/{{ ucp_version }}/specification/checkout", + "spec": "https://ucp.dev/{{ ucp_version }}/specification/shopping/checkout", "schema": "https://ucp.dev/{{ ucp_version }}/schemas/shopping/checkout.json" } ], @@ -137,7 +137,7 @@ This extension uses the cryptographic primitives defined in the * **Canonicalization:** JCS ([RFC 8785](https://datatracker.ietf.org/doc/html/rfc8785)) * **Key Format:** JWK ([RFC 7517](https://datatracker.ietf.org/doc/html/rfc7517)) * **Key Discovery:** `keys[]` in `/.well-known/ucp` (see - [Key Discovery](overview.md#key-discovery)) + [Key Discovery](overview/index.md#key-discovery)) See [Message Signatures](signatures.md) for key format and rotation. diff --git a/docs/specification/buyer-consent.md b/docs/specification/buyer-consent.md index 1c5e03862..9f6a5317c 100644 --- a/docs/specification/buyer-consent.md +++ b/docs/specification/buyer-consent.md @@ -330,8 +330,8 @@ Some consent states depend on additional buyer or checkout data. For example, SMS marketing consent requires a buyer phone number. When the platform confirms a consent value whose required dependency is missing, businesses surface the gap through the standard [Checkout Status -Lifecycle](checkout.md#checkout-status-lifecycle) and [Error -Handling](checkout.md#error-handling) mechanisms. +Lifecycle](shopping/checkout/index.md#checkout-status-lifecycle) and [Error +Handling](shopping/checkout/index.md#error-handling) mechanisms. On `create_cart`, `update_cart`, `create_checkout`, and `update_checkout`, businesses SHOULD surface missing dependencies as `warning` messages so the @@ -354,7 +354,7 @@ consent decisions remain valid; the warning is informational. On `complete_checkout`, businesses MUST NOT transition the checkout to `completed` while a confirmed consent decision has unmet data dependencies. Missing dependencies MUST be surfaced via the standard [Error -Handling](checkout.md#error-handling) flow. +Handling](shopping/checkout/index.md#error-handling) flow. ## Normative requirements diff --git a/docs/specification/identity-linking.md b/docs/specification/common/identity-linking/index.md similarity index 98% rename from docs/specification/identity-linking.md rename to docs/specification/common/identity-linking/index.md index 5cd3d3a66..13c428fec 100644 --- a/docs/specification/identity-linking.md +++ b/docs/specification/common/identity-linking/index.md @@ -17,7 +17,7 @@ # Identity Linking Capability * **Capability Name:** `dev.ucp.common.identity_linking` -* **Schema:** `https://ucp.dev/schemas/common/identity_linking.json` +* **Schema:** `https://ucp.dev/{{ ucp_version }}/schemas/common/identity_linking.json` ## Overview @@ -90,8 +90,8 @@ business **MAY** populate it from stored state on the response (for example, Identity linking provides the authenticated user context for these values. Subject to the scopes that gate the operation, a business **MAY** return the -user's loyalty membership in `loyalty` (see [Loyalty](loyalty.md)), saved -payment instruments in `payment.instruments[]` (see [Checkout](checkout.md)), or +user's loyalty membership in `loyalty` (see [Loyalty](../../loyalty.md)), saved +payment instruments in `payment.instruments[]` (see [Checkout](../../shopping/checkout/index.md)), or buyer profile data in `buyer`. Businesses **MUST NOT** return stored user-specific state unless the request is @@ -412,7 +412,7 @@ namespace; its value is an array of mechanism entries. A provider key is a reverse-domain **identifier**, not a schema-bearing entity: it declares no `schema` URL, so the -[Authority Binding](overview.md#authority-binding) (which binds an entity's +[Authority Binding](../../overview/index.md#authority-binding) (which binds an entity's `schema` URL to its namespace authority) does not apply here. A provider's trust anchor is its `auth_url`, governed by the discovery rules below; binding `auth_url` to the provider's namespace authority is a possible future hardening, @@ -481,8 +481,8 @@ direct OAuth flows (always available via discovery): "capabilities": { "dev.ucp.common.identity_linking": [{ "version": "{{ ucp_version }}", - "spec": "https://ucp.dev/specification/identity-linking", - "schema": "https://ucp.dev/schemas/common/identity_linking.json", + "spec": "https://ucp.dev/{{ ucp_version }}/specification/common/identity-linking/", + "schema": "https://ucp.dev/{{ ucp_version }}/schemas/common/identity_linking.json", "config": { "providers": { "app.example.login": [ @@ -1123,8 +1123,8 @@ operations gated: "capabilities": { "dev.ucp.common.identity_linking": [{ "version": "{{ ucp_version }}", - "spec": "https://ucp.dev/specification/identity-linking", - "schema": "https://ucp.dev/schemas/common/identity_linking.json", + "spec": "https://ucp.dev/{{ ucp_version }}/specification/common/identity-linking/", + "schema": "https://ucp.dev/{{ ucp_version }}/schemas/common/identity_linking.json", "config": { "scopes": { "dev.ucp.shopping.order:read": {}, @@ -1161,8 +1161,8 @@ No guest checkout — every transaction requires an authenticated user: "capabilities": { "dev.ucp.common.identity_linking": [{ "version": "{{ ucp_version }}", - "spec": "https://ucp.dev/specification/identity-linking", - "schema": "https://ucp.dev/schemas/common/identity_linking.json", + "spec": "https://ucp.dev/{{ ucp_version }}/specification/common/identity-linking/", + "schema": "https://ucp.dev/{{ ucp_version }}/schemas/common/identity_linking.json", "config": { "scopes": { "dev.ucp.shopping.checkout:manage": {}, diff --git a/docs/specification/discount.md b/docs/specification/discount.md index 033fc8e4c..314b8de8d 100644 --- a/docs/specification/discount.md +++ b/docs/specification/discount.md @@ -194,7 +194,7 @@ segment, or promotional rules: ## Eligibility Claims Eligibility claims are buyer claims about eligible benefits (see -[Context](checkout.md#context)) such as loyalty membership, payment instrument +[Context](shopping/checkout/index.md#context)) such as loyalty membership, payment instrument perks, and similar. When the discount extension is active, Businesses that choose to accept eligibility claims **MUST** surface their effect on pricing as provisional discounts in the `applied` array. Platforms **MUST** display @@ -203,7 +203,7 @@ provisional discounts to the buyer. ### Discount Behavior Platforms send buyer claims via `context.eligibility` on cart or checkout -requests (see [Context](checkout.md#context)). When a Business recognizes a +requests (see [Context](shopping/checkout/index.md#context)). When a Business recognizes a claim and it affects pricing, it **MUST** surface a corresponding provisional discount in the `discounts.applied` array. This gives the Platform structured attribution to display to the buyer. @@ -226,12 +226,12 @@ Discounts from accepted but unverified claims carry `provisional: true`. Provisional discounts remain until the claim is verified, rescinded, or replaced during the session. At checkout completion, all remaining provisional claims **MUST** be resolved (see -[Eligibility Verification at Completion](checkout.md#eligibility-verification-at-completion)). +[Eligibility Verification at Completion](shopping/checkout/index.md#eligibility-verification-at-completion)). ### Example: Provisional Discount with Attribution Using the same claim-resolution pattern described in -[Eligibility Verification at Completion](checkout.md#eligibility-verification-at-completion), +[Eligibility Verification at Completion](shopping/checkout/index.md#eligibility-verification-at-completion), the discount extension provides structured attribution. The Platform claims a store card benefit; the Business surfaces the provisional discount with full stacking and allocation details: diff --git a/docs/specification/embedded-protocol.md b/docs/specification/embedded-protocol.md index d0674d5e5..c96405802 100644 --- a/docs/specification/embedded-protocol.md +++ b/docs/specification/embedded-protocol.md @@ -33,8 +33,8 @@ Capability-specific details — discovery, URL parameters, delegation contracts, message payloads, and schema definitions — are defined in each capability's EP binding specification: -- [Checkout Capability — EP Binding](embedded-checkout.md) -- [Cart Capability — EP Binding](embedded-cart.md) +- [Checkout Capability — EP Binding](shopping/checkout/embedded.md) +- [Cart Capability — EP Binding](shopping/cart/embedded.md) ## Terminology & Actors @@ -128,7 +128,7 @@ Transport errors are protocol-level failures that prevent request processing. These are returned as JSON-RPC `error` using standard JSON-RPC error codes and indicate the message itself is invalid or could not be processed — not that executed business logic produced an error outcome. See the -[Core Specification](overview.md#error-codes) for the complete error code +[Core Specification](overview/index.md#error-codes) for the complete error code registry. For example, if a request cannot be processed (unknown method, malformed diff --git a/docs/specification/fulfillment.md b/docs/specification/fulfillment.md index 9dfbc330c..c78a12d12 100644 --- a/docs/specification/fulfillment.md +++ b/docs/specification/fulfillment.md @@ -54,10 +54,10 @@ On Checkout, the `fulfillment` field contains: ## Location Context -Base [Context](catalog/index.md#context) defines an optional `location`: a +Base [Context](shopping/catalog/index.md#context) defines an optional `location`: a stable, opaque [Location](glossary.md#commerce) identifier in the Business's namespace. The field appears on Catalog requests and on Cart and Checkout -create and update requests (see [Checkout Context](checkout.md#context)). +create and update requests (see [Checkout Context](shopping/checkout/index.md#context)). Fulfillment does not add or redefine the field; when the Fulfillment extension is active, it defines the field's effects. @@ -89,7 +89,7 @@ Precedence is scoped to what each field governs: these fields without collapsing their roles. A Catalog response can report a place-based method at `loc_123`. Because base Cart Context already includes `location`, `loc_123` can travel forward as `context.location` on a Cart -request. [Cart-to-Checkout conversion](cart.md#cart-to-checkout-conversion) +request. [Cart-to-Checkout conversion](shopping/cart/index.md#cart-to-checkout-conversion) initializes the Checkout from the Cart's `context`, so the Business **MAY** use `loc_123` to generate an initial Checkout fulfillment destination. Once the Platform sets `selected_destination_id`, that explicit selection governs. @@ -372,15 +372,15 @@ describes another location. A Business that cannot honor the submitted selection rejects it rather than replacing it. When the Business cannot accept a `selected_destination_id` submitted on -[Update Checkout](checkout.md#update-checkout) — the ID is not recognized for +[Update Checkout](shopping/checkout/index.md#update-checkout) — the ID is not recognized for that method, or revalidation fails — it follows the general behavior for a rejected Update: it **MUST** leave the current Checkout unchanged and **MUST** return that Checkout with an error Message with `severity: "recoverable"` whose `path` selects the attempted method's `selected_destination_id` (for example `$.fulfillment.methods[0].selected_destination_id`). See -[Error Handling](checkout.md#error-handling) and -[The `path` Field](checkout.md#the-path-field). +[Error Handling](shopping/checkout/index.md#error-handling) and +[The `path` Field](shopping/checkout/index.md#the-path-field). ## Rendering diff --git a/docs/specification/glossary.md b/docs/specification/glossary.md index fa07e47df..f47164c00 100644 --- a/docs/specification/glossary.md +++ b/docs/specification/glossary.md @@ -41,16 +41,16 @@ acronym in each specification Markdown file spells out the full term (e.g., ## Commerce -| Term | Acronym | Definition | -| :--------------------------- | :------ | :---------------------------------------------------------------------------------------------------------------------------------------------------- | -| **Business** | - | The entity selling goods or services. In UCP, they act as the **Merchant of Record (MoR)**, retaining financial liability and ownership of the order. | -| **Location** | - | A physical place (e.g., store, restaurant, property, pickup point) identified by a stable, opaque string in a Business's namespace. | -| **Increment** | - | Optional [ordering granularity](overview.md#ordering-increment) of a sale basis, a count of steps; advisory for Platform-authored quantities. | -| **Merchant of Record** | MoR | The legal entity responsible for the sale, including financial liability and order ownership. | -| **Payment Service Provider** | PSP | The financial infrastructure provider that processes payments, authorizations, and settlements on behalf of the business. | -| **Platform** | - | The consumer-facing surface (AI agent, app, website) acting on behalf of the user to discover businesses and facilitate commerce. | -| **Quantity Unit** | - | A [sale-basis descriptor](overview.md#quantities-and-units) with machine identity (`unit`, effective `scale`); excludes `display_text`/`increment`. | -| **Step** | - | One [integer increment](overview.md#quantities-and-units) in the authoritative sale basis: `10^-scale` of `unit`. | +| Term | Acronym | Definition | +| :--------------------------- | :------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Business** | - | The entity selling goods or services. In UCP, they act as the **Merchant of Record (MoR)**, retaining financial liability and ownership of the order. | +| **Location** | - | A physical place (e.g., store, restaurant, property, pickup point) identified by a stable, opaque string in a Business's namespace. | +| **Increment** | - | Optional [ordering granularity](overview/index.md#ordering-increment) of a sale basis, a count of steps; advisory for Platform-authored quantities. | +| **Merchant of Record** | MoR | The legal entity responsible for the sale, including financial liability and order ownership. | +| **Payment Service Provider** | PSP | The financial infrastructure provider that processes payments, authorizations, and settlements on behalf of the business. | +| **Platform** | - | The consumer-facing surface (AI agent, app, website) acting on behalf of the user to discover businesses and facilitate commerce. | +| **Quantity Unit** | - | A [sale-basis descriptor](overview/index.md#quantities-and-units) with machine identity (`unit`, effective `scale`); excludes `display_text`/`increment`. | +| **Step** | - | One [integer increment](overview/index.md#quantities-and-units) in the authoritative sale basis: `10^-scale` of `unit`. | ## Payments diff --git a/docs/specification/loyalty.md b/docs/specification/loyalty.md index 770503cf9..142eed4a4 100644 --- a/docs/specification/loyalty.md +++ b/docs/specification/loyalty.md @@ -110,28 +110,28 @@ extended. "dev.ucp.shopping.catalog.search": [ { "version": "{{ ucp_version }}", - "spec": "https://ucp.dev/{{ ucp_version }}/specification/catalog/search", + "spec": "https://ucp.dev/{{ ucp_version }}/specification/shopping/catalog/search", "schema": "https://ucp.dev/{{ ucp_version }}/schemas/shopping/catalog_search.json" } ], "dev.ucp.shopping.catalog.lookup": [ { "version": "{{ ucp_version }}", - "spec": "https://ucp.dev/{{ ucp_version }}/specification/catalog/lookup", + "spec": "https://ucp.dev/{{ ucp_version }}/specification/shopping/catalog/lookup", "schema": "https://ucp.dev/{{ ucp_version }}/schemas/shopping/catalog_lookup.json" } ], "dev.ucp.shopping.cart": [ { "version": "{{ ucp_version }}", - "spec": "https://ucp.dev/{{ ucp_version }}/specification/cart", + "spec": "https://ucp.dev/{{ ucp_version }}/specification/shopping/cart", "schema": "https://ucp.dev/{{ ucp_version }}/schemas/shopping/cart.json" } ], "dev.ucp.shopping.checkout": [ { "version": "{{ ucp_version }}", - "spec": "https://ucp.dev/{{ ucp_version }}/specification/checkout", + "spec": "https://ucp.dev/{{ ucp_version }}/specification/shopping/checkout", "schema": "https://ucp.dev/{{ ucp_version }}/schemas/shopping/checkout.json" } ], @@ -219,7 +219,7 @@ explicit eligibility claim. In this case, the map key MUST be the same reverse-d identifier the business would accept as a claim value. This is a specific instance of the general pattern where identity linking lets a business return its own user state on a response; see -[Business-Populated Response Values](identity-linking.md#business-populated-response-values). +[Business-Populated Response Values](common/identity-linking/index.md#business-populated-response-values). * When a business verifies a membership claim or determines membership from authenticated identity, it MUST return `provisional: false`. It MUST populate the @@ -237,7 +237,7 @@ response; see and proceed through checkout without loyalty benefits applied. At checkout completion, all accepted but unverified loyalty claims MUST be resolved per -the [Eligibility Verification at Completion](checkout.md#eligibility-verification-at-completion) +the [Eligibility Verification at Completion](shopping/checkout/index.md#eligibility-verification-at-completion) contract defined in the checkout capability. ### Monetary loyalty benefits @@ -279,7 +279,7 @@ complete cart and checkout responses also include base required fields such as ` `id`, `currency`, and `totals`. Building on the store loyalty card example from -[Eligibility Verification at Completion](checkout.md#eligibility-verification-at-completion), +[Eligibility Verification at Completion](shopping/checkout/index.md#eligibility-verification-at-completion), assume the card offers one unconditional product discount and one conditional discount that the current checkout cart fails to satisfy. The platform can surface the first provisional discount with disclaimers like "verified at purchase" and additionally show diff --git a/docs/specification/overview.md b/docs/specification/overview/index.md similarity index 98% rename from docs/specification/overview.md rename to docs/specification/overview/index.md index cd477679c..041f53473 100644 --- a/docs/specification/overview.md +++ b/docs/specification/overview/index.md @@ -69,7 +69,7 @@ language, and UCP therefore defines no rounding tolerances and no epsilon comparisons anywhere in the quantity lifecycle. A fulfilled quantity that legitimately differs from the ordered quantity — a 1.90 lb pick against a 2.00 lb order — is a commercial fact reconciled through -[adjustments](order.md#adjustments) that move money together with quantity, +[adjustments](../shopping/order/index.md#adjustments) that move money together with quantity, not a numeric error absorbed by comparison fuzz. Reading a quantity requires no arithmetic and no unit knowledge: shift the @@ -91,7 +91,7 @@ values Section 6) and within which [JCS](https://www.rfc-editor.org/rfc/rfc8785.html){ target="_blank" } canonicalization, required for -[AP2 mandate signing](ap2-mandates.md#canonicalization), is defined. The +[AP2 mandate signing](../ap2-mandates.md#canonicalization), is defined. The same cap derives `scale`'s maximum of 15: at scale 16, one whole unit (10^16 steps) would be unrepresentable. An out-of-range value is schema-invalid and is rejected like any other invalid payload. @@ -548,9 +548,9 @@ when its specification explicitly adopts it and defines the parent-specific behavior: where Actions appear, the effect each Action type gates, how Messages apply, and how a later response reflects processing. Schema composition alone does not establish support. Cart, Checkout, and Catalog adopt this shape; see -[Cart — Actions](cart.md#actions), -[Checkout — Actions](checkout.md#actions), and -[Catalog — Actions](catalog/index.md#actions) for their parent-specific +[Cart — Actions](../shopping/cart/index.md#actions), +[Checkout — Actions](../shopping/checkout/index.md#actions), and +[Catalog — Actions](../shopping/catalog/index.md#actions) for their parent-specific contracts. Actions and Messages have different roles. An Action represents outstanding @@ -593,7 +593,7 @@ explanatory Message (an illustrative, partial fragment): The Action identifies the outstanding work and carries extension-owned processing configuration under `config`. The Message's `path` selects the exact Action occurrence it explains. The -[checkout eligibility example](checkout.md#eligibility-verification-at-completion) +[checkout eligibility example](../shopping/checkout/index.md#eligibility-verification-at-completion) composes this pattern into a complete Student Verification flow. For a newly processed successful response from a capability that adopts Actions, @@ -603,7 +603,7 @@ the Business **MUST** include every outstanding Action and **MUST** omit Cart and Checkout define request idempotency separately. Duplicate requests follow those existing rules and can return the original cached response, including its `actions` (see -[Message Signatures — Replay Protection](signatures.md#replay-protection)). +[Message Signatures — Replay Protection](../signatures.md#replay-protection)). An Action's gate and an operation-specific outcome are orthogonal. Neither a parent status nor a Message's type or severity determines whether an Action @@ -624,7 +624,7 @@ contract. When an Action prevents a Cart or Checkout operation from succeeding, processing the Action does not repeat that operation. If the Platform wants to try again, it submits a new operation under the existing -[Replay Protection](signatures.md#replay-protection) rules. +[Replay Protection](../signatures.md#replay-protection) rules. Each Action key is a reverse-domain **Action type**: the name identifies the type of outstanding work, which is not necessarily the name of the extension @@ -641,7 +641,7 @@ Action type keys follow existing [Namespace Governance](#namespace-governance) rules: an extension can declare only types within a reverse-domain namespace controlled by its schema authority. An extension can use its own name as the key for a single Action type — as the -[Student Verification example](checkout.md#eligibility-verification-at-completion) +[Student Verification example](../shopping/checkout/index.md#eligibility-verification-at-completion) does — or declare several Action types under distinct keys. Each value is a non-empty array of outstanding instances of that one Action type. The key identifies the type, so an instance carries no separate type discriminator; a @@ -964,7 +964,7 @@ functionality is supported and where to find documentation and schemas. #### Capability Definition -{{ extension_schema_fields('capability.json#/$defs/platform_schema', 'capability-schema') }} +{{ extension_schema_fields('capability.json#/$defs/platform_schema', 'overview') }} #### Extensions @@ -1195,7 +1195,7 @@ effectively revoked until it is absent from `keys[]`. UCP defines two well-known key types: **EC** (ECDSA P-256, P-384) and **OKP** (EdDSA Ed25519); the key-type, curve, and algorithm vocabularies are open and verifiers skip keys they do not recognize. -See [Message Signatures](signatures.md) for key format, algorithms, +See [Message Signatures](../signatures.md) for key format, algorithms, lookup, and rotation. #### Business Profile @@ -1211,27 +1211,27 @@ Businesses publish their profile at `/.well-known/ucp`. An example: "dev.ucp.shopping": [ { "version": "{{ ucp_version }}", - "spec": "https://ucp.dev/{{ ucp_version }}/specification/overview", + "spec": "https://ucp.dev/{{ ucp_version }}/specification/overview/", "transport": "rest", "endpoint": "https://business.example.com/ucp/v1", "schema": "https://ucp.dev/{{ ucp_version }}/services/shopping/rest.openapi.json" }, { "version": "{{ ucp_version }}", - "spec": "https://ucp.dev/{{ ucp_version }}/specification/overview", + "spec": "https://ucp.dev/{{ ucp_version }}/specification/overview/", "transport": "mcp", "endpoint": "https://business.example.com/ucp/mcp", "schema": "https://ucp.dev/{{ ucp_version }}/services/shopping/mcp.openrpc.json" }, { "version": "{{ ucp_version }}", - "spec": "https://ucp.dev/{{ ucp_version }}/specification/overview", + "spec": "https://ucp.dev/{{ ucp_version }}/specification/overview/", "transport": "a2a", "endpoint": "https://business.example.com/.well-known/agent-card.json" }, { "version": "{{ ucp_version }}", - "spec": "https://ucp.dev/{{ ucp_version }}/specification/overview", + "spec": "https://ucp.dev/{{ ucp_version }}/specification/overview/", "transport": "embedded", "schema": "https://ucp.dev/{{ ucp_version }}/services/shopping/embedded.openrpc.json" } @@ -1241,7 +1241,7 @@ Businesses publish their profile at `/.well-known/ucp`. An example: "dev.ucp.shopping.checkout": [ { "version": "{{ ucp_version }}", - "spec": "https://ucp.dev/{{ ucp_version }}/specification/checkout", + "spec": "https://ucp.dev/{{ ucp_version }}/specification/shopping/checkout", "schema": "https://ucp.dev/{{ ucp_version }}/schemas/shopping/checkout.json" } ], @@ -1264,7 +1264,7 @@ Businesses publish their profile at `/.well-known/ucp`. An example: "dev.ucp.common.identity_linking": [ { "version": "{{ ucp_version }}", - "spec": "https://ucp.dev/{{ ucp_version }}/specification/identity-linking", + "spec": "https://ucp.dev/{{ ucp_version }}/specification/common/identity-linking/", "schema": "https://ucp.dev/{{ ucp_version }}/schemas/common/identity_linking.json", "config": { "providers": { @@ -1348,7 +1348,7 @@ it will not read `keys[]` from a static `/.well-known/ucp`. See This example uses two keys. Whether a deployment needs one or two depends on the algorithms its counterparties accept — many need only one; see -[Signature Algorithms](signatures.md#signature-algorithms). The two keys +[Signature Algorithms](../signatures.md#signature-algorithms). The two keys here: - An **Ed25519** key (OKP) for HTTP transport identity, WBA-compatible. @@ -1360,7 +1360,7 @@ A business that does not interact with AP2 or WBA may publish a single ES256 key in `keys[]` (the universal baseline). See [Key Discovery](#key-discovery) for key lookup and resolution, [Deployment Patterns for WBA Interop](#deployment-patterns-for-wba-interop) -for hosting choices, and [Message Signatures](signatures.md) for +for hosting choices, and [Message Signatures](../signatures.md) for signing mechanics. Businesses that support older protocol versions **SHOULD** include a @@ -1384,7 +1384,7 @@ example: "dev.ucp.shopping": [ { "version": "{{ ucp_version }}", - "spec": "https://ucp.dev/{{ ucp_version }}/specification/overview", + "spec": "https://ucp.dev/{{ ucp_version }}/specification/overview/", "transport": "rest", "schema": "https://ucp.dev/{{ ucp_version }}/services/shopping/rest.openapi.json", "endpoint": "https://platform.example.com/ucp/v1" @@ -1395,7 +1395,7 @@ example: "dev.ucp.shopping.checkout": [ { "version": "{{ ucp_version }}", - "spec": "https://ucp.dev/{{ ucp_version }}/specification/checkout", + "spec": "https://ucp.dev/{{ ucp_version }}/specification/shopping/checkout", "schema": "https://ucp.dev/{{ ucp_version }}/schemas/shopping/checkout.json" } ], @@ -1410,7 +1410,7 @@ example: "dev.ucp.shopping.order": [ { "version": "{{ ucp_version }}", - "spec": "https://ucp.dev/{{ ucp_version }}/specification/order", + "spec": "https://ucp.dev/{{ ucp_version }}/specification/shopping/order", "schema": "https://ucp.dev/{{ ucp_version }}/schemas/shopping/order.json", "config": { "webhook_url": "https://platform.example.com/webhooks/ucp/orders" @@ -1420,7 +1420,7 @@ example: "dev.ucp.common.identity_linking": [ { "version": "{{ ucp_version }}", - "spec": "https://ucp.dev/{{ ucp_version }}/specification/identity-linking", + "spec": "https://ucp.dev/{{ ucp_version }}/specification/common/identity-linking/", "schema": "https://ucp.dev/{{ ucp_version }}/schemas/common/identity_linking.json" } ] @@ -1791,7 +1791,7 @@ the result in the UCP response: | `digest_mismatch` | Body digest doesn't match `Content-Digest` header | 400 | -32600 | | `algorithm_unsupported`| Signature algorithm not supported | 400 | -32600 | -See [Message Signatures](signatures.md) for signature verification details. +See [Message Signatures](../signatures.md) for signature verification details. **Protocol Errors:** @@ -1812,7 +1812,7 @@ responses. The Embedded Protocol uses the same JSON-RPC error codes for peer-to-peer communication between host and embedded context. Server-specific scenarios (rate limiting, idempotency) do not apply to the embedded transport. See -[Embedded Protocol — Response Handling](embedded-protocol.md#response-handling) +[Embedded Protocol — Response Handling](../embedded-protocol.md#response-handling) for the full error handling specification. ##### The `continue_url` Field @@ -2084,7 +2084,7 @@ can interact with any business without prior registration. additionally emit a `Signature-Agent` header advertising their keys. See [Identity Resolution Algorithm](#identity-resolution-algorithm) for how verifiers resolve identity and -[Message Signatures — WBA Interop](signatures.md#wba-interop) for the +[Message Signatures — WBA Interop](../signatures.md#wba-interop) for the signature shape. ### Authentication Mechanisms @@ -2097,7 +2097,7 @@ message integrity. UCP is compatible with multiple authentication mechanisms: - **mTLS** — Mutual TLS with client certificates - **HTTP Message Signatures** — Cryptographic signatures per [RFC 9421](https://www.rfc-editor.org/rfc/rfc9421) (see - [Message Signatures](signatures.md) for full specification) + [Message Signatures](../signatures.md) for full specification) HTTP Message Signatures enable permissionless onboarding — businesses can verify platforms by their advertised public keys without negotiating shared @@ -2105,7 +2105,7 @@ secrets. The other mechanisms require prior credential exchange and imply a pre-established relationship. Business-to-platform webhooks **MUST** be signed. See -[Message Signatures — When Signatures Apply](signatures.md#when-signatures-apply). +[Message Signatures — When Signatures Apply](../signatures.md#when-signatures-apply). #### Identity Binding @@ -2144,7 +2144,7 @@ profile fetching, and covered-component enforcement — see [Identity Resolution Algorithm](#identity-resolution-algorithm) below. For key format (JWK), supported algorithms, key rotation procedures, and the Web Bot Auth interop signature shape, see -[Message Signatures](signatures.md). +[Message Signatures](../signatures.md). ### Profile Requirements @@ -2302,7 +2302,7 @@ below processes a single signature. need not implement Web Bot Auth key discovery. (Verifying a dual-audience signature does still require supporting the key's algorithm — whichever the signer used, per - [Signature Algorithms](signatures.md#signature-algorithms) — and + [Signature Algorithms](../signatures.md#signature-algorithms) — and RFC 9421 §2.1.2 Dictionary-member component selection to cover `signature-agent;key="