Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 54 additions & 4 deletions docs/documentation/schema-authoring.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,59 @@ The same registry structure appears in three contexts with different field requi
| Capabilities/extensions | `version`, `spec`, `schema` | `version`, `schema`; may add `config` | `version` |
| Payment handlers | `id`, `version`, `spec`, `schema` | `id`, `version`; may add `config` | `id`, `version` |

## The Reserved `ucp` Member

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)
for the normative rules. For schema authors this means:

- **Never mint a structured domain field named `ucp`.** Schema authors
**MUST NOT** declare a domain field named `ucp` in a structured object; the
name denotes the protocol namespace there.
- **Do not declare ambient `ucp` in open nested objects.** The root `ucp`
envelope is not ambient placement; UCP root schemas already declare its
required protocol metadata. Below the root, the member is UCP document grammar
defined centrally, so schema authors **MUST NOT** declare it in an open nested
object. A Business or Platform **MAY** include it in an eligible open
structured scope without the domain schema saying so. Ordinary instance
validation against an open UCP source domain schema treats it as an ignored
unknown object; validating its contents is a conformance-tooling concern.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not for this PR, but for the sake of implementors and the community, we should aim to bend schema-authoring.md to be (i) as obvious as possible and (ii) example driven.

So in this case something like:

- DO NOT declare ucp in open schemas; DO declare it if you close the schema.
  Because JSON Schema is open by default, ambient ucp metadata blocks are
  allowed on any structured object automatically. You only declare ucp in your
  .json file if you explicitly set `additionalProperties: false`.

❌ DON'T (Open Schema — default behavior):
{
  "type": "object",
  "properties": {
    "carrier_name": { "type": "string" }
    // DO NOT put "ucp" here! JSON Schema allows it automatically.
  }
}

✅ DO (Closed Schema — explicit restriction):
{
  "type": "object",
  "additionalProperties": false,
  "properties": {
    "carrier_name": { "type": "string" },
    "ucp": { "$ref": "https://.../ucp.json#/$defs/members" } // Required ONLY when closed
  }
}

More academic reasoning around why protocol level choices were made is rolled up into the specification itself.

- **Dictionary keys remain data.** A dictionary container cannot host the
protocol namespace. Schema authors **MUST NOT** model a dictionary key named
`ucp` as that namespace; the key is governed by the dictionary's key and
value schemas and is ordinary data. A structured object used as a
dictionary value remains an eligible scope and follows these rules. For
example, `attribution` is a dictionary of string values, so its key `ucp` is
ordinary attribution data.
- **The vocabulary grows only in UCP core.** New protocol members are added
in `ucp.json#/$defs/members`, never in domain or extension schemas, and a
member is admitted only if it is safe to ignore — a Business or Platform
that does not process it loses only that member's benefit, never
correctness. The container is open for forward compatibility with future
UCP versions, not as an extension point.
- **Registry maps can never host `ucp`.** Registry maps are dictionaries, so
they cannot host the protocol namespace. Their reverse-domain
`propertyNames` constraints additionally reject the literal `ucp` key.
This is why structural metadata about a registry map — such as `map_order`
— sits in the parent structured scope's protocol namespace rather than
inside the map itself.
- **Closed nested structured objects must declare optional `ucp`
explicitly.** Closing a nested structured object does not exempt it from the
protocol grammar. A schema author defining one with
`additionalProperties: false` **MUST** declare an optional `ucp` property
referencing `ucp.json#/$defs/members`. This exception applies only to nested
structured objects; closing a dictionary does not create an ambient namespace
there.
Comment thread
igrigorik marked this conversation as resolved.
- **Declare member applicability.** Schema authors **MUST** annotate every
property registered in `ucp.json#/$defs/members` with `ucp_request` (`omit`,
`optional`, or `required`, as appropriate). They **MUST** repeat the
annotation wherever the same member is exposed elsewhere in `ucp.json`. An
explicit ambient `ucp` property follows the applicability of its containing
schema and is not automatically omitted from requests.

## The Entity Pattern

All capabilities, services, and handlers extend a common `entity` base schema:
Expand Down Expand Up @@ -434,10 +487,7 @@ Marking an object as closed preemptively prevents any future non-breaking additi
protocol, what would otherwise be a backward-compatible field addition (e.g., adding a "gift_message" field to an order)
becomes a breaking change for any client validating against a closed schema.

By default, JSON Schema is open and ignores unknown properties. Authors should leave this keyword omitted except in rare
circumstances: polymorphic discriminators (where strictness prevents oneOf validation ambiguity), security-critical
payloads (where unknown fields may indicate tampering), or protocol envelopes (where strictness is useful to catch
typos in core metadata like the `ucp` block).
By default, JSON Schema is open and ignores unknown properties. Authors should leave this keyword omitted except in rare circumstances: polymorphic discriminators (where strictness prevents oneOf validation ambiguity) or security-critical payloads (where unknown fields may indicate tampering). The `ucp` protocol namespace itself is deliberately open (tolerant readers ignore unrecognized members); typo discipline there is an authoring-time concern, not a wire-validation one.

**Anti-Pattern (Prevents adding new fields without a reversion):**

Expand Down
6 changes: 6 additions & 0 deletions docs/specification/ap2-mandates.md
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,12 @@ immediately over the same HTTP connection. Mandates are different:
JCS ensures that semantically identical JSON produces byte-identical output,
making signatures reproducible across implementations and time.

Verification and mandate construction operate on the complete checkout JSON,
not a projection of schema-recognized fields; removing any member covered by
`merchant_authorization` changes the JCS payload and invalidates the signature.
Comment thread
igrigorik marked this conversation as resolved.
This coverage includes `ucp` protocol-namespace members present in the checkout;
only the `ap2` field is excluded as specified below.

**AP2-Specific Rule:** When computing the business's `merchant_authorization`
signature, exclude the `ap2` field entirely. This ensures future AP2 fields
are automatically handled.
Expand Down
23 changes: 12 additions & 11 deletions docs/specification/glossary.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,18 @@ acronym in each specification Markdown file spells out the full term (e.g.,

## Protocol

| Term | Acronym | Definition |
| :------------------------------ | :------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Action** | - | Outstanding extension-defined work for a Platform to process; appears only in the response-only `actions` map of adopting capabilities. |
| **Agent Payments Protocol** | AP2 | An open protocol designed to enable AI agents to securely interoperate and complete payments autonomously. UCP leverages AP2 for secure payment mandates. |
| **Agent2Agent Protocol** | A2A | An open standard for secure, collaborative communication between diverse AI agents. UCP can use A2A as a transport layer. |
| **Capability** | - | A standalone core feature that a business supports (e.g., Checkout, Identity Linking). Capabilities are the fundamental "verbs" of UCP. |
| **Credential Provider** | CP | A trusted entity (like a digital wallet) responsible for securely managing and executing the user's payment and identity credentials. |
| **Extension** | - | An optional capability that augments another capability via the `extends` field. Extensions appear in `ucp.capabilities[]` alongside core capabilities. |
| **Model Context Protocol** | MCP | A protocol standardizing how AI models connect to external data and tools. UCP capabilities map 1:1 to MCP tools. |
| **Profile** | - | A JSON document hosted by businesses and platforms at a well-known URI, declaring their identity, supported capabilities, and endpoints. |
| **Universal Commerce Protocol** | UCP | The standard defined in this document, enabling interoperability between commerce entities via standardized capabilities and discovery. |
| Term | Acronym | Definition |
| :------------------------------ | :------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Action** | - | Outstanding extension-defined work for a Platform to process; appears only in the response-only `actions` map of adopting capabilities. |
| **Agent Payments Protocol** | AP2 | An open protocol designed to enable AI agents to securely interoperate and complete payments autonomously. UCP leverages AP2 for secure payment mandates. |
| **Agent2Agent Protocol** | A2A | An open standard for secure, collaborative communication between diverse AI agents. UCP can use A2A as a transport layer. |
| **Capability** | - | A standalone core feature that a business supports (e.g., Checkout, Identity Linking). Capabilities are the fundamental "verbs" of UCP. |
| **Credential Provider** | CP | A trusted entity (like a digital wallet) responsible for securely managing and executing the user's payment and identity credentials. |
| **Extension** | - | An optional capability that augments another capability via the `extends` field. Extensions appear in `ucp.capabilities[]` alongside core capabilities. |
| **Model Context Protocol** | MCP | A protocol standardizing how AI models connect to external data and tools. UCP capabilities map 1:1 to MCP tools. |
| **Profile** | - | A JSON document hosted by businesses and platforms at a well-known URI, declaring their identity, supported capabilities, and endpoints. |
| **Protocol Namespace** | - | Reserved `ucp` member for protocol metadata and annotations in structured UCP objects with schema-defined fields. Dictionaries are excluded: `ucp` is key data there; structured object values remain eligible. Top-level envelope is its root. |
| **Universal Commerce Protocol** | UCP | The standard defined in this document, enabling interoperability between commerce entities via standardized capabilities and discovery. |

## Commerce

Expand Down
Loading
Loading