How UCP Implements Schema Composition Using the 'allOf' Keyword
UCP composes JSON Schemas by merging a mandatory base envelope containing version and profile fields with domain-specific constraints using the allOf keyword, enabling modular validation across platform, business, and service definitions in the Universal Commerce Protocol.
The Universal Commerce Protocol (UCP) leverages JSON Schema's allOf keyword to build a modular, extensible validation layer. By composing smaller schema fragments into unified definitions, UCP ensures that every message—whether a platform configuration, service definition, or shopping cart payload—inherits mandatory metadata while supporting domain-specific extensions. This approach centralizes common requirements like protocol versioning while allowing decentralized extensions.
The Base Envelope Pattern in UCP
UCP establishes a mandatory base envelope that every top-level schema must include. This pattern ensures version awareness and profile binding across all protocol messages.
The $defs/base Definition
In source/schemas/ucp.json, the $defs/base definition establishes the universal contract that every composed schema must satisfy:
{
"$defs": {
"base": {
"type": "object",
"required": ["version", "profile"],
"properties": {
"version": { "type": "string", "const": "1.0" },
"profile": { "type": "string", "format": "uri" }
}
}
}
}
Inheriting Base Constraints via allOf
Every concrete schema composes this base using allOf. For example, the Success schema in ucp.json (lines 124-130) implements the pattern:
{
"allOf": [
{ "$ref": "#/$defs/base" },
{ /* additional constraints */ }
]
}
Composing Platform and Business Configurations
UCP distinguishes between platform-level configurations (what a platform advertises) and business-level configurations (merchant-specific settings). Both compose the base envelope but extend it differently.
Platform Schema Aggregation
The platform schema aggregates services, capabilities, and payment handlers. Located in ucp.json (lines 144-172), it uses allOf to merge the base with platform-specific requirements:
{
"title": "UCP Platform Schema",
"allOf": [
{ "$ref": "#/$defs/base" },
{
"required": ["services", "payment_handlers"],
"properties": {
"services": { "additionalProperties": { "items": { "$ref": "service.json#/$defs/platform_schema" } } },
"capabilities": { "additionalProperties": { "items": { "$ref": "capability.json#/$defs/platform_schema" } } },
"payment_handlers": { "additionalProperties": { "items": { "$ref": "payment_handler.json#/$defs/platform_schema" } } }
}
}
]
}
Business Schema Specialization
Conversely, the business schema (lines 174-210 in ucp.json) reuses the same base but narrows the scope to merchant-specific fields like supported_versions. This ensures that business-level configurations carry the same protocol metadata while validating different required fields.
Hierarchical Definitions for Services and Handlers
Services, capabilities, and payment handlers follow a three-context composition model. Each entity defines schemas for how it appears in platform configurations, business configurations, and response payloads.
The Three Composition Contexts
Every service definition in source/schemas/service.json, capability.json, and payment_handler.json provides three $defs entries:
platform_schema: How the entity appears in platform configurationsbusiness_schema: How the entity appears in merchant configurationsresponse_schema: The shape when returned in API responses
Service Schema Implementation
In source/schemas/service.json (lines 9-33), the platform_schema uses allOf to inherit the base and add service-specific properties. This hierarchical nesting allows service definitions to reuse the universal metadata requirements while tailoring validation for each specific context.
Extending Shopping Domain Schemas
The shopping domain applies the same composition strategy. In source/schemas/shopping/checkout.json, a base checkout schema provides the foundation, with extensions using allOf to add fields like payment_instruments or shipping_destination. The base schema explicitly declares: "description": "Base checkout schema. Extensions compose onto this using allOf."
Practical Implementation Examples
Creating a Custom Service
To define a new service that inherits UCP's base requirements:
{
"$id": "myservice.json",
"$defs": {
"myservice": {
"allOf": [
{ "$ref": "#/$defs/base" },
{
"type": "object",
"required": ["my_setting"],
"properties": {
"my_setting": { "type": "string", "enum": ["alpha", "beta"] }
}
}
]
}
}
}
The first entry pulls in version and profile requirements. The second entry adds the custom setting. The resulting schema validates both sets of constraints simultaneously.
Referencing Services in Platform Configurations
Platform configurations reference these composed schemas:
{
"services": {
"my.namespace.myservice": {
"items": { "$ref": "myservice.json#/$defs/myservice" }
}
}
}
Because the service schema already contains an allOf with the base, any platform configuration automatically respects the core UCP contract.
Extending Shopping Types
To add custom validation to shopping schemas, create an extension that references the base discount definition:
{
"$id": "custom_discount.json",
"$defs": {
"custom_discount": {
"allOf": [
{ "$ref": "discount.json#/$defs/base" },
{
"type": "object",
"properties": {
"custom_code": { "type": "string", "pattern": "^[A-Z0-9]{6}$" }
},
"required": ["custom_code"]
}
]
}
}
}
Now any checkout payload that includes a discounts array can reference custom_discount to gain the extra validation while maintaining compatibility with the base discount structure.
Summary
- UCP uses
allOfinsource/schemas/ucp.jsonto merge a mandatory base envelope (containingversionandprofile) with domain-specific constraints. - Platform schemas (lines 144-172) and business schemas (lines 174-210) both inherit from
$defs/basebut extend it with different required fields. - Services, capabilities, and payment handlers in
service.json,capability.json, andpayment_handler.jsoneach provide three composable contexts:platform_schema,business_schema, andresponse_schema. - Shopping domains like checkout use
allOfto layer extensions onto base types without modifying core definitions. - This composition strategy ensures version consistency and profile binding across all UCP messages while supporting extensibility.
Frequently Asked Questions
What does allOf do in UCP JSON Schemas?
In UCP, allOf merges multiple subschemas so that data must validate against all of them simultaneously. This allows the protocol to layer the mandatory base envelope (with version and profile fields) atop domain-specific definitions, ensuring every message carries protocol metadata while satisfying specialized constraints.
How does UCP ensure version consistency across composed schemas?
UCP centralizes version requirements in $defs/base within source/schemas/ucp.json. By referencing this definition as the first element in every allOf array (such as in lines 124-130 for the Success schema), all composed schemas automatically inherit the version field requirement and its const value of "1.0".
Can developers extend UCP schemas with custom fields using allOf?
Yes. Developers can create new schema files that use allOf to reference existing UCP definitions (like discount.json#/$defs/base) and then add custom properties, required fields, or validation patterns. This extension method maintains compatibility with the core protocol while adding business-specific validation rules.
Where are the base schema definitions located in the repository?
The base envelope definition resides in source/schemas/ucp.json under the $defs/base key. This file also contains the primary platform and business schema compositions (lines 144-210), while service-specific compositions appear in source/schemas/service.json, capability.json, and payment_handler.json.
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 →