From 307ae575fafac3d1f99009fb8b02cde6a5fe02c1 Mon Sep 17 00:00:00 2001 From: Ryan Conigliaro Date: Mon, 24 Aug 2026 21:11:14 -0400 Subject: [PATCH 1/6] fix preprocess to expand properties dict instead of add as a node to avoid traversing properties with names that match json schema keywords. --- preprocess_schemas.py | 6 +- src/ucp_sdk/models/schemas/__init__.py | 1 + src/ucp_sdk/models/schemas/capability.py | 74 +---- src/ucp_sdk/models/schemas/common/__init__.py | 1 + .../models/schemas/common/identity_linking.py | 18 +- src/ucp_sdk/models/schemas/common/loyalty.py | 297 ++++++++++++++++++ .../models/schemas/common/types/__init__.py | 18 ++ .../models/schemas/common/types/actions.py | 56 ++++ .../{shopping => common}/types/amount.py | 3 +- .../{shopping => common}/types/binding.py | 14 +- .../common/types/constraint_expression.py | 101 ++++++ .../{shopping => common}/types/context.py | 33 +- .../types/context_create_request.py | 33 +- .../types/context_update_request.py | 33 +- .../{shopping => common}/types/description.py | 0 .../{shopping => common}/types/error_code.py | 2 +- .../types/error_code_create_request.py | 2 +- .../types/error_code_update_request.py | 2 +- .../types/error_response.py | 0 .../{shopping => common}/types/info_code.py | 2 +- .../types/info_code_create_request.py | 2 +- .../types/info_code_update_request.py | 2 +- .../{shopping => common}/types/link.py | 0 .../models/schemas/common/types/locality.py | 43 +++ .../common/types/locality_create_request.py | 43 +++ .../common/types/locality_update_request.py | 43 +++ .../types/location_summary.py} | 8 +- .../types/location_summary_create_request.py} | 8 +- .../types/location_summary_update_request.py} | 16 +- .../models/schemas/common/types/measure.py | 37 +++ .../common/types/measure_create_request.py | 37 +++ .../common/types/measure_update_request.py | 37 +++ .../{shopping => common}/types/media.py | 2 +- .../{shopping => common}/types/message.py | 0 .../types/message_create_request.py | 0 .../types/message_error.py | 4 +- .../types/message_error_create_request.py | 4 +- .../types/message_error_update_request.py | 4 +- .../types/message_info.py | 2 +- .../types/message_info_create_request.py | 2 +- .../types/message_info_update_request.py | 2 +- .../types/message_update_request.py | 0 .../types/message_warning.py | 2 +- .../types/message_warning_create_request.py | 2 +- .../types/message_warning_update_request.py | 2 +- .../{shopping => common}/types/pagination.py | 0 .../models/schemas/common/types/policy.py | 50 +++ .../types/postal_address.py | 0 .../types/postal_address_complete_request.py | 0 .../types/postal_address_create_request.py | 0 .../types/postal_address_update_request.py | 0 .../{shopping => common}/types/price.py | 0 .../types/price_filter.py | 0 .../{shopping => common}/types/price_range.py | 2 +- .../schemas/common/types/quantity_unit.py | 37 +++ .../types/quantity_unit_create_request.py | 37 +++ .../types/quantity_unit_update_request.py | 37 +++ .../common/types/request_constraints.py | 72 +++++ .../types/reverse_domain_name.py | 13 +- .../reverse_domain_name_create_request.py | 13 +- .../reverse_domain_name_update_request.py | 13 +- .../{shopping => common}/types/signals.py | 2 +- .../types/signals_complete_request.py | 2 +- .../types/signals_create_request.py | 2 +- .../types/signals_update_request.py | 2 +- .../types/signed_amount.py | 11 +- .../types/signed_amount_create_request.py | 10 +- .../types/signed_amount_update_request.py | 10 +- .../{shopping => common}/types/total.py | 0 .../types/total_create_request.py | 0 .../types/total_update_request.py | 0 .../{shopping => common}/types/totals.py | 0 .../types/totals_create_request.py | 0 .../types/totals_update_request.py | 0 .../models/schemas/common/types/unit.py | 43 +++ .../common/types/unit_create_request.py | 43 +++ .../common/types/unit_update_request.py | 43 +++ .../types/warning_code.py | 3 +- .../types/warning_code_create_request.py | 3 +- .../types/warning_code_update_request.py | 3 +- src/ucp_sdk/models/schemas/profile.py | 127 ++++++++ src/ucp_sdk/models/schemas/service.py | 26 +- .../models/schemas/shopping/__init__.py | 1 + .../models/schemas/shopping/buyer_consent.py | 86 ++++- src/ucp_sdk/models/schemas/shopping/cart.py | 18 +- .../schemas/shopping/cart_create_request.py | 3 +- .../schemas/shopping/cart_update_request.py | 7 +- .../models/schemas/shopping/catalog_lookup.py | 63 ++-- .../models/schemas/shopping/catalog_search.py | 18 +- .../models/schemas/shopping/checkout.py | 20 +- .../shopping/checkout_complete_request.py | 3 +- .../shopping/checkout_create_request.py | 3 +- .../shopping/checkout_update_request.py | 3 +- .../models/schemas/shopping/discount.py | 4 +- .../models/schemas/shopping/fulfillment.py | 202 +++++++++++- src/ucp_sdk/models/schemas/shopping/order.py | 9 +- .../schemas/shopping/order_create_request.py | 3 +- .../schemas/shopping/order_update_request.py | 3 +- .../shopping/payment_authentication.py | 101 ++++++ .../models/schemas/shopping/payment_terms.py | 99 ++++++ .../models/schemas/shopping/permalink.py | 52 +++ .../models/schemas/shopping/split_payments.py | 80 +++++ .../models/schemas/shopping/types/__init__.py | 1 + .../schemas/shopping/types/adjustment.py | 13 +- .../types/adjustment_create_request.py | 12 +- .../types/adjustment_update_request.py | 12 +- .../schemas/shopping/types/availability.py | 39 +++ .../types/available_payment_instrument.py | 8 +- .../types/business_fulfillment_config.py | 28 +- .../types/business_split_payments_config.py | 48 +++ .../schemas/shopping/types/card_credential.py | 4 +- .../shopping/types/card_payment_instrument.py | 45 +-- .../schemas/shopping/types/expectation.py | 12 +- .../types/expectation_create_request.py | 12 +- .../types/expectation_update_request.py | 12 +- .../types/fulfillment_available_method.py | 6 +- .../shopping/types/fulfillment_destination.py | 31 +- .../fulfillment_destination_create_request.py | 34 +- .../types/fulfillment_destination_filter.py | 37 +++ .../fulfillment_destination_update_request.py | 34 +- .../shopping/types/fulfillment_event.py | 4 +- .../types/fulfillment_event_create_request.py | 4 +- .../types/fulfillment_event_update_request.py | 4 +- .../shopping/types/fulfillment_method.py | 12 +- .../fulfillment_method_create_request.py | 28 +- .../fulfillment_method_update_request.py | 24 +- .../shopping/types/fulfillment_option.py | 21 +- ...t_config.py => fulfillment_option_base.py} | 38 +-- ...fulfillment_option_base_create_request.py} | 16 +- .../fulfillment_option_base_update_request.py | 31 ++ .../fulfillment_option_create_request.py | 10 +- .../fulfillment_option_update_request.py | 10 +- .../shopping/types/instrument_group.py | 43 +++ .../models/schemas/shopping/types/item.py | 14 +- .../shopping/types/item_create_request.py | 8 + .../shopping/types/item_update_request.py | 8 + .../schemas/shopping/types/line_item.py | 6 +- .../types/line_item_create_request.py | 4 +- .../types/line_item_update_request.py | 4 +- .../shopping/types/location_destination.py | 39 +++ .../location_destination_create_request.py | 35 +++ .../location_destination_update_request.py | 35 +++ .../types/network_token_credential.py | 67 ++++ .../schemas/shopping/types/order_line_item.py | 20 +- .../types/order_line_item_create_request.py | 21 +- .../types/order_line_item_update_request.py | 21 +- .../schemas/shopping/types/pan_credential.py | 59 ++++ .../shopping/types/payment_identity.py | 2 +- .../shopping/types/payment_instrument.py | 5 +- .../payment_instrument_complete_request.py | 8 +- .../payment_instrument_create_request.py | 5 +- .../payment_instrument_update_request.py | 5 +- .../shopping/types/payment_schedule.py | 54 ++++ .../schemas/shopping/types/payment_term.py | 50 +++ .../models/schemas/shopping/types/product.py | 9 +- .../schemas/shopping/types/search_filters.py | 2 +- .../shopping/types/shipping_destination.py | 8 +- .../shipping_destination_create_request.py | 10 +- .../shipping_destination_update_request.py | 10 +- .../schemas/shopping/types/unit_price.py | 74 +++++ .../models/schemas/shopping/types/variant.py | 108 +------ .../models/schemas/transports/__init__.py | 1 + .../models/schemas/transports/a2a_message.py | 133 ++++++++ .../schemas/transports/embedded_message.py | 109 +++++++ .../models/schemas/transports/jsonrpc.py | 121 +++++++ .../schemas/transports/mcp_tool_call.py | 157 +++++++++ src/ucp_sdk/models/schemas/ucp.py | 33 +- .../models/schemas/ucp_create_request.py | 33 +- .../models/schemas/ucp_update_request.py | 33 +- 169 files changed, 3643 insertions(+), 681 deletions(-) create mode 100644 src/ucp_sdk/models/schemas/common/loyalty.py create mode 100644 src/ucp_sdk/models/schemas/common/types/__init__.py create mode 100644 src/ucp_sdk/models/schemas/common/types/actions.py rename src/ucp_sdk/models/schemas/{shopping => common}/types/amount.py (91%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/binding.py (60%) create mode 100644 src/ucp_sdk/models/schemas/common/types/constraint_expression.py rename src/ucp_sdk/models/schemas/{shopping => common}/types/context.py (72%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/context_create_request.py (68%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/context_update_request.py (68%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/description.py (100%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/error_code.py (92%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/error_code_create_request.py (92%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/error_code_update_request.py (92%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/error_response.py (100%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/info_code.py (90%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/info_code_create_request.py (90%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/info_code_update_request.py (90%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/link.py (100%) create mode 100644 src/ucp_sdk/models/schemas/common/types/locality.py create mode 100644 src/ucp_sdk/models/schemas/common/types/locality_create_request.py create mode 100644 src/ucp_sdk/models/schemas/common/types/locality_update_request.py rename src/ucp_sdk/models/schemas/{shopping/types/retail_location.py => common/types/location_summary.py} (85%) rename src/ucp_sdk/models/schemas/{shopping/types/account_info.py => common/types/location_summary_create_request.py} (74%) rename src/ucp_sdk/models/schemas/{shopping/types/retail_location_update_request.py => common/types/location_summary_update_request.py} (70%) create mode 100644 src/ucp_sdk/models/schemas/common/types/measure.py create mode 100644 src/ucp_sdk/models/schemas/common/types/measure_create_request.py create mode 100644 src/ucp_sdk/models/schemas/common/types/measure_update_request.py rename src/ucp_sdk/models/schemas/{shopping => common}/types/media.py (96%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/message.py (100%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/message_create_request.py (100%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/message_error.py (71%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/message_error_create_request.py (72%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/message_error_update_request.py (72%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/message_info.py (93%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/message_info_create_request.py (93%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/message_info_update_request.py (93%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/message_update_request.py (100%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/message_warning.py (95%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/message_warning_create_request.py (95%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/message_warning_update_request.py (95%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/pagination.py (100%) create mode 100644 src/ucp_sdk/models/schemas/common/types/policy.py rename src/ucp_sdk/models/schemas/{shopping => common}/types/postal_address.py (100%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/postal_address_complete_request.py (100%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/postal_address_create_request.py (100%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/postal_address_update_request.py (100%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/price.py (100%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/price_filter.py (100%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/price_range.py (92%) create mode 100644 src/ucp_sdk/models/schemas/common/types/quantity_unit.py create mode 100644 src/ucp_sdk/models/schemas/common/types/quantity_unit_create_request.py create mode 100644 src/ucp_sdk/models/schemas/common/types/quantity_unit_update_request.py create mode 100644 src/ucp_sdk/models/schemas/common/types/request_constraints.py rename src/ucp_sdk/models/schemas/{shopping => common}/types/reverse_domain_name.py (57%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/reverse_domain_name_create_request.py (58%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/reverse_domain_name_update_request.py (58%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/signals.py (95%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/signals_complete_request.py (95%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/signals_create_request.py (95%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/signals_update_request.py (95%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/signed_amount.py (84%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/signed_amount_create_request.py (85%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/signed_amount_update_request.py (85%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/total.py (100%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/total_create_request.py (100%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/total_update_request.py (100%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/totals.py (100%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/totals_create_request.py (100%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/totals_update_request.py (100%) create mode 100644 src/ucp_sdk/models/schemas/common/types/unit.py create mode 100644 src/ucp_sdk/models/schemas/common/types/unit_create_request.py create mode 100644 src/ucp_sdk/models/schemas/common/types/unit_update_request.py rename src/ucp_sdk/models/schemas/{shopping => common}/types/warning_code.py (88%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/warning_code_create_request.py (88%) rename src/ucp_sdk/models/schemas/{shopping => common}/types/warning_code_update_request.py (88%) create mode 100644 src/ucp_sdk/models/schemas/profile.py create mode 100644 src/ucp_sdk/models/schemas/shopping/payment_authentication.py create mode 100644 src/ucp_sdk/models/schemas/shopping/payment_terms.py create mode 100644 src/ucp_sdk/models/schemas/shopping/permalink.py create mode 100644 src/ucp_sdk/models/schemas/shopping/split_payments.py create mode 100644 src/ucp_sdk/models/schemas/shopping/types/availability.py create mode 100644 src/ucp_sdk/models/schemas/shopping/types/business_split_payments_config.py create mode 100644 src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination_filter.py rename src/ucp_sdk/models/schemas/shopping/types/{merchant_fulfillment_config.py => fulfillment_option_base.py} (54%) rename src/ucp_sdk/models/schemas/shopping/types/{retail_location_create_request.py => fulfillment_option_base_create_request.py} (68%) create mode 100644 src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_base_update_request.py create mode 100644 src/ucp_sdk/models/schemas/shopping/types/instrument_group.py create mode 100644 src/ucp_sdk/models/schemas/shopping/types/location_destination.py create mode 100644 src/ucp_sdk/models/schemas/shopping/types/location_destination_create_request.py create mode 100644 src/ucp_sdk/models/schemas/shopping/types/location_destination_update_request.py create mode 100644 src/ucp_sdk/models/schemas/shopping/types/network_token_credential.py create mode 100644 src/ucp_sdk/models/schemas/shopping/types/pan_credential.py create mode 100644 src/ucp_sdk/models/schemas/shopping/types/payment_schedule.py create mode 100644 src/ucp_sdk/models/schemas/shopping/types/payment_term.py create mode 100644 src/ucp_sdk/models/schemas/shopping/types/unit_price.py create mode 100644 src/ucp_sdk/models/schemas/transports/a2a_message.py create mode 100644 src/ucp_sdk/models/schemas/transports/embedded_message.py create mode 100644 src/ucp_sdk/models/schemas/transports/jsonrpc.py create mode 100644 src/ucp_sdk/models/schemas/transports/mcp_tool_call.py diff --git a/preprocess_schemas.py b/preprocess_schemas.py index a9bba53..93b34a6 100644 --- a/preprocess_schemas.py +++ b/preprocess_schemas.py @@ -49,7 +49,11 @@ def iter_nodes(root): # Identify children for the next iteration children = [] if isinstance(curr, dict): - children = curr.values() + for k, v in curr.items(): + if k == "properties" and isinstance(v, dict): + children.extend(v.values()) + else: + children.append(v) elif isinstance(curr, list): children = curr diff --git a/src/ucp_sdk/models/schemas/__init__.py b/src/ucp_sdk/models/schemas/__init__.py index 1252d6b..421dc21 100644 --- a/src/ucp_sdk/models/schemas/__init__.py +++ b/src/ucp_sdk/models/schemas/__init__.py @@ -15,3 +15,4 @@ # generated by datamodel-codegen # pylint: disable=all # pyformat: disable + diff --git a/src/ucp_sdk/models/schemas/capability.py b/src/ucp_sdk/models/schemas/capability.py index 1a53ae0..3538563 100644 --- a/src/ucp_sdk/models/schemas/capability.py +++ b/src/ucp_sdk/models/schemas/capability.py @@ -23,6 +23,8 @@ from pydantic import AnyUrl, BaseModel, ConfigDict, Field from typing_extensions import TypeAliasType +from .common.types import reverse_domain_name + UcpCapability = TypeAliasType( "UcpCapability", Annotated[Any, Field(..., title="UCP Capability")] ) @@ -34,7 +36,7 @@ Extends = TypeAliasType( "Extends", Annotated[ - str, Field(..., pattern="^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$") + list[reverse_domain_name.ReverseDomainName], Field(..., min_length=1) ], ) """ @@ -42,22 +44,6 @@ """ -Extends1Item = TypeAliasType( - "Extends1Item", - Annotated[ - str, Field(..., pattern="^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$") - ], -) - - -Extends1 = TypeAliasType( - "Extends1", Annotated[list[Extends1Item], Field(..., min_length=1)] -) -""" -Parent capability(s) this extends. Present for extensions, absent for root capabilities. Use array for multi-parent extensions. -""" - - class Base(BaseModel): model_config = ConfigDict( extra="allow", @@ -82,26 +68,12 @@ class Base(BaseModel): """ Entity-specific configuration. Structure defined by each entity's schema. """ - extends: Extends | Extends1 | None = None + extends: reverse_domain_name.ReverseDomainName | Extends | None = None """ Parent capability(s) this extends. Present for extensions, absent for root capabilities. Use array for multi-parent extensions. """ -Extends2 = TypeAliasType("Extends2", Extends) - - -Extends3Item = TypeAliasType("Extends3Item", Extends1Item) - - -Extends3 = TypeAliasType( - "Extends3", Annotated[list[Extends3Item], Field(..., min_length=1)] -) -""" -Parent capability(s) this extends. Present for extensions, absent for root capabilities. Use array for multi-parent extensions. -""" - - class PlatformSchema(BaseModel): """ Full capability declaration for platform-level discovery. Includes spec/schema URLs for agent fetching. @@ -130,29 +102,15 @@ class PlatformSchema(BaseModel): """ Entity-specific configuration. Structure defined by each entity's schema. """ - extends: Extends2 | Extends3 | None = None + extends: reverse_domain_name.ReverseDomainName | Extends | None = None """ Parent capability(s) this extends. Present for extensions, absent for root capabilities. Use array for multi-parent extensions. """ -Extends4 = TypeAliasType("Extends4", Extends) - - -Extends5Item = TypeAliasType("Extends5Item", Extends1Item) - - -Extends5 = TypeAliasType( - "Extends5", Annotated[list[Extends5Item], Field(..., min_length=1)] -) -""" -Parent capability(s) this extends. Present for extensions, absent for root capabilities. Use array for multi-parent extensions. -""" - - class BusinessSchema(BaseModel): """ - Capability configuration for business/merchant level. May include business-specific config overrides. + Capability declaration for business/merchant discovery. Requires the `schema` URL so platforms can fetch and compose it during negotiation; may also include business-specific config overrides. """ model_config = ConfigDict( @@ -166,7 +124,7 @@ class BusinessSchema(BaseModel): """ URL to human-readable specification document. """ - schema_: AnyUrl | None = Field(None, alias="schema") + schema_: AnyUrl = Field(..., alias="schema") """ URL to JSON Schema defining this entity's structure and payloads. """ @@ -178,26 +136,12 @@ class BusinessSchema(BaseModel): """ Entity-specific configuration. Structure defined by each entity's schema. """ - extends: Extends4 | Extends5 | None = None + extends: reverse_domain_name.ReverseDomainName | Extends | None = None """ Parent capability(s) this extends. Present for extensions, absent for root capabilities. Use array for multi-parent extensions. """ -Extends6 = TypeAliasType("Extends6", Extends) - - -Extends7Item = TypeAliasType("Extends7Item", Extends1Item) - - -Extends7 = TypeAliasType( - "Extends7", Annotated[list[Extends7Item], Field(..., min_length=1)] -) -""" -Parent capability(s) this extends. Present for extensions, absent for root capabilities. Use array for multi-parent extensions. -""" - - class ResponseSchema(BaseModel): """ Capability reference in responses. Only name/version required to confirm active capabilities. @@ -226,7 +170,7 @@ class ResponseSchema(BaseModel): """ Entity-specific configuration. Structure defined by each entity's schema. """ - extends: Extends6 | Extends7 | None = None + extends: reverse_domain_name.ReverseDomainName | Extends | None = None """ Parent capability(s) this extends. Present for extensions, absent for root capabilities. Use array for multi-parent extensions. """ diff --git a/src/ucp_sdk/models/schemas/common/__init__.py b/src/ucp_sdk/models/schemas/common/__init__.py index 1252d6b..421dc21 100644 --- a/src/ucp_sdk/models/schemas/common/__init__.py +++ b/src/ucp_sdk/models/schemas/common/__init__.py @@ -15,3 +15,4 @@ # generated by datamodel-codegen # pylint: disable=all # pyformat: disable + diff --git a/src/ucp_sdk/models/schemas/common/identity_linking.py b/src/ucp_sdk/models/schemas/common/identity_linking.py index 5b32ea4..aebf51c 100644 --- a/src/ucp_sdk/models/schemas/common/identity_linking.py +++ b/src/ucp_sdk/models/schemas/common/identity_linking.py @@ -23,7 +23,7 @@ from pydantic import BaseModel, ConfigDict, Field from typing_extensions import TypeAliasType -from ..shopping.types import description as description_1 +from .types import description as description_1 IdentityLinking = TypeAliasType( "IdentityLinking", Annotated[Any, Field(..., title="Identity Linking")] @@ -53,7 +53,7 @@ class ScopePolicy(BaseModel): str, Field( ..., - pattern="^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+:[a-z][a-z0-9_]*$", + pattern="^[a-z](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9_])?)+:[a-z][a-z0-9_]*$", ), ], ) @@ -62,4 +62,18 @@ class ScopePolicy(BaseModel): """ +class Provider(BaseModel): + """ + A trusted identity provider for delegated authentication, keyed by the 'type' discriminator. 'oauth2' denotes an OAuth 2.0 / OIDC authorization server. Future versions MAY define additional types (e.g. wallet attestation) as non-breaking extensions; platforms MUST treat entries whose 'type' they do not support as filtered out (see Provider Selection). + """ + + model_config = ConfigDict( + extra="allow", + ) + type: str + """ + Provider mechanism discriminator. 'oauth2' for OAuth 2.0 / OIDC authorization servers. Additional values MAY be defined by future versions; the value is an open string, not a closed enum, so unrecognized types remain valid and are filtered at runtime. + """ + + IdentityLinking1 = TypeAliasType("IdentityLinking1", Any) diff --git a/src/ucp_sdk/models/schemas/common/loyalty.py b/src/ucp_sdk/models/schemas/common/loyalty.py new file mode 100644 index 0000000..009222d --- /dev/null +++ b/src/ucp_sdk/models/schemas/common/loyalty.py @@ -0,0 +1,297 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from typing import Annotated, Any + +from pydantic import BaseModel, ConfigDict, Field +from typing_extensions import TypeAliasType + +from ..shopping.cart import Cart as Cart_1 +from ..shopping.catalog_lookup import GetProductResponse, LookupResponse +from ..shopping.catalog_search import SearchResponse +from ..shopping.checkout import Checkout as Checkout_1 +from .types import reverse_domain_name + +LoyaltyExtension = TypeAliasType( + "LoyaltyExtension", Annotated[Any, Field(..., title="Loyalty Extension")] +) +""" +Extends various Capabilities with loyalty support using memberships info. +""" + + +RewardAmount = TypeAliasType("RewardAmount", Annotated[int, Field(..., ge=0)]) +""" +Non-negative integer amount denominated in the minor unit of the associated reward currency. The associated reward currency's `decimal_places` defines the minor-to-major ratio and defaults to 0 when omitted. +""" + + +class EarningBreakdown(BaseModel): + """ + Breakdown rule of the reward earnings + """ + + model_config = ConfigDict( + extra="allow", + ) + id: str + """ + Unique rewards breakdown rule identifier. + """ + amount: RewardAmount + """ + Rewards earned from this rule. + """ + description: str + """ + A display-ready, human-readable rationale for the specific rewards (e.g. 2x on footwear). + """ + benefit_id: str | None = None + """ + Optional `id` of the membership_tier_benefit that produced this rewards rule. Resolves against `membership_tier_benefit.id` within the same parent loyalty membership. + """ + + +class EarningForecast(BaseModel): + """ + Preview of rewards to be earned from the current transaction. + """ + + model_config = ConfigDict( + extra="allow", + ) + amount: RewardAmount + """ + Total rewards to be earned if the transaction completes. + """ + breakdown: list[EarningBreakdown] | None = None + """ + List of breakdown of earning contributing to the total. + """ + + +class RewardCurrency(BaseModel): + """ + The currency of the loyalty reward. + """ + + model_config = ConfigDict( + extra="allow", + ) + name: str + """ + Human-readable name of the currency (e.g. 'LoyaltyStars'). + """ + code: str + """ + Business-specific representation of the currency (e.g. 'LST'). + """ + decimal_places: int | None = Field(0, ge=0) + """ + The position of a digit to the right of a decimal point. Applies to all amount related fields for rewards. + """ + + +class Currency(BaseModel): + """ + A unit of value that customers can accumulate through various commercial activities. + """ + + model_config = ConfigDict( + extra="allow", + ) + name: str + """ + Human-readable name of the currency (e.g. 'LoyaltyStars'). + """ + code: str + """ + Business-specific representation of the currency (e.g. 'LST'). + """ + decimal_places: int | None = Field(0, ge=0) + """ + The position of a digit to the right of a decimal point. Applies to all amount related fields for rewards. + """ + + +class MembershipReward(BaseModel): + """ + Quantifiable reward type and optional earning forecast for the current transaction. + """ + + model_config = ConfigDict( + extra="allow", + ) + currency: Currency + """ + A unit of value that customers can accumulate through various commercial activities. + """ + earning_forecast: EarningForecast | None = None + """ + Preview of rewards to be earned from the current transaction. + """ + + +class MembershipTierBenefit(BaseModel): + """ + Benefits associated with a membership tier. + """ + + model_config = ConfigDict( + extra="allow", + ) + id: str + """ + Unique identifier for the tier benefit. + """ + description: str + """ + A display-ready, human-readable explanation of this benefit (e.g. 'Early access to sales'). + """ + + +class MembershipTier(BaseModel): + """ + Specific achievement rank or status milestone that unlocks escalating value as a member progresses through activity or spend. + """ + + model_config = ConfigDict( + extra="allow", + ) + id: str + """ + Unique identifier for the membership tier. + """ + name: str + """ + The human-readable name of the tier (e.g., 'Platinum'). + """ + benefits: list[MembershipTierBenefit] | None = None + """ + List of benefits associated with this tier. + """ + + +class LoyaltyMembership(BaseModel): + """ + Loyalty membership the business has accepted for the eligibility claim represented by the parent map key. Programs that can be joined independently MUST be modeled as separate sibling entries under the loyalty map, distinguished by reverse-domain naming (e.g., 'com.example.rewards' and 'com.example.rewards.card'). + """ + + model_config = ConfigDict( + extra="allow", + ) + id: str + """ + Unique loyalty membership identifier. + """ + name: str + """ + Business specific name of the loyalty membership/program. + """ + display_id: str | None = None + """ + A masked or partial version of the membership id for user recognition (e.g., '****5678'). MUST NOT be set if the membership has not been verified. + """ + tiers: list[MembershipTier] | None = None + """ + Active or display-safe tier context for this membership. Most programs are single-status (one entry); programs with parallel status dimensions (e.g., current and lifetime) populate one entry per active tier. Omitted when no tier context has been resolved. + """ + rewards: list[MembershipReward] | None = None + """ + Reward types and earning forecasts associated with this membership. Each object encapsulates one type of reward. + """ + provisional: bool + """ + True if this membership requires additional verification. + """ + + +Loyalty = TypeAliasType( + "Loyalty", dict[reverse_domain_name.ReverseDomainName, LoyaltyMembership] +) +""" +Key-value map whose keys represent buyer/platform asserted eligibility claims and whose values represent associated membership information. All loyalty keys MUST use reverse-domain naming to ensure provenance and prevent collisions when multiple extensions contribute to the shared namespace. +""" + + +class Search(SearchResponse): + """ + Catalog Search response extended with Loyalty capability. + """ + + model_config = ConfigDict( + extra="allow", + ) + loyalty: Loyalty | None = None + + +class Lookup1(LookupResponse): + """ + Catalog Lookup response extended with Loyalty capability. + """ + + model_config = ConfigDict( + extra="allow", + ) + loyalty: Loyalty | None = None + + +class Lookup2(GetProductResponse): + """ + Catalog Lookup response extended with Loyalty capability. + """ + + model_config = ConfigDict( + extra="allow", + ) + loyalty: Loyalty | None = None + + +Lookup = TypeAliasType( + "Lookup", + Annotated[ + Lookup1 | Lookup2, Field(..., title="Catalog Lookup with Loyalty") + ], +) +""" +Catalog Lookup response extended with Loyalty capability. +""" + + +class Cart(Cart_1): + """ + Cart extended with Loyalty capability. + """ + + model_config = ConfigDict( + extra="allow", + ) + loyalty: Loyalty | None = None + + +class Checkout(Checkout_1): + """ + Checkout extended with Loyalty capability. + """ + + model_config = ConfigDict( + extra="allow", + ) + loyalty: Loyalty | None = None diff --git a/src/ucp_sdk/models/schemas/common/types/__init__.py b/src/ucp_sdk/models/schemas/common/types/__init__.py new file mode 100644 index 0000000..421dc21 --- /dev/null +++ b/src/ucp_sdk/models/schemas/common/types/__init__.py @@ -0,0 +1,18 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + diff --git a/src/ucp_sdk/models/schemas/common/types/actions.py b/src/ucp_sdk/models/schemas/common/types/actions.py new file mode 100644 index 0000000..d67b151 --- /dev/null +++ b/src/ucp_sdk/models/schemas/common/types/actions.py @@ -0,0 +1,56 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from typing import Annotated, Any + +from pydantic import BaseModel, ConfigDict, Field +from typing_extensions import TypeAliasType + +from . import reverse_domain_name + + +class Instance(BaseModel): + """ + Common fields for one outstanding Action instance are id and optional config. The extension declaring the Action type defines type-specific processing data under config. Additional properties are permitted for forward compatibility. + """ + + model_config = ConfigDict( + extra="allow", + ) + id: str = Field(..., min_length=1) + """ + Identifier for this Action instance. + """ + config: dict[str, Any] | None = None + """ + Configuration defined by the extension that declares this Action type. + """ + + +Actions = TypeAliasType( + "Actions", + Annotated[ + dict[reverse_domain_name.ReverseDomainName, list[Instance]], + Field(..., title="Actions"), + ], +) +""" +Outstanding extension-defined Action instances, keyed by reverse-domain Action type, not extension name. +""" diff --git a/src/ucp_sdk/models/schemas/shopping/types/amount.py b/src/ucp_sdk/models/schemas/common/types/amount.py similarity index 91% rename from src/ucp_sdk/models/schemas/shopping/types/amount.py rename to src/ucp_sdk/models/schemas/common/types/amount.py index 0715e52..f4d901d 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/amount.py +++ b/src/ucp_sdk/models/schemas/common/types/amount.py @@ -24,7 +24,8 @@ from typing_extensions import TypeAliasType Amount = TypeAliasType( - "Amount", Annotated[int, Field(..., ge=0, title="Amount")] + "Amount", + Annotated[int, Field(..., ge=0, le=9007199254740991, title="Amount")], ) """ Monetary amount in the currency's minor unit as defined by ISO 4217. Refer to the currency's exponent to determine minor-to-major ratio (e.g., 2 for USD, 0 for JPY, 3 for KWD). diff --git a/src/ucp_sdk/models/schemas/shopping/types/binding.py b/src/ucp_sdk/models/schemas/common/types/binding.py similarity index 60% rename from src/ucp_sdk/models/schemas/shopping/types/binding.py rename to src/ucp_sdk/models/schemas/common/types/binding.py index 16f6961..021401e 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/binding.py +++ b/src/ucp_sdk/models/schemas/common/types/binding.py @@ -18,24 +18,24 @@ from __future__ import annotations -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field -from . import payment_identity +from . import reverse_domain_name class Binding(BaseModel): """ - Binds a token to a specific checkout session and participant. Prevents token reuse across different checkouts or participants. + Binds a credential or token to a specific capability resource. Prevents reuse across different resources. """ model_config = ConfigDict( extra="allow", ) - checkout_id: str + type: reverse_domain_name.ReverseDomainName """ - The checkout session identifier this token is bound to. + The capability that owns the bound resource, for example dev.ucp.shopping.checkout. MUST be a capability name declared in the UCP namespace. """ - identity: payment_identity.PaymentIdentity | None = None + id: str = Field(..., min_length=1) """ - The participant this token is bound to. Required when acting on behalf of another participant (e.g., agent tokenizing for merchant). Omit when the authenticated caller is the binding target. + Opaque identifier of the bound resource within the owning capability, for example a checkout identifier. """ diff --git a/src/ucp_sdk/models/schemas/common/types/constraint_expression.py b/src/ucp_sdk/models/schemas/common/types/constraint_expression.py new file mode 100644 index 0000000..236ae50 --- /dev/null +++ b/src/ucp_sdk/models/schemas/common/types/constraint_expression.py @@ -0,0 +1,101 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from typing import Any + +from pydantic import BaseModel, ConfigDict, Field, field_validator +from typing_extensions import TypeAliasType + + +class ValueConstraint1(BaseModel): + """ + A Value Constraint containing `enum`, `const`, or both. + """ + + model_config = ConfigDict( + extra="allow", + ) + enum: list[Any] = Field(..., min_length=1) + """ + A non-empty array of unique JSON values. + """ + const: Any | None = None + + +class ValueConstraint2(BaseModel): + """ + A Value Constraint containing `enum`, `const`, or both. + """ + + model_config = ConfigDict( + extra="allow", + ) + enum: list[Any] | None = Field(None, min_length=1) + """ + A non-empty array of unique JSON values. + """ + const: Any + + +ValueConstraint = TypeAliasType( + "ValueConstraint", ValueConstraint1 | ValueConstraint2 +) +""" +A Value Constraint containing `enum`, `const`, or both. +""" + + +class ConstraintExpression(BaseModel): + """ + A closed JSON Schema Draft 2020-12 constraint expression with Object and Value Constraint positions. + """ + + model_config = ConfigDict( + extra="forbid", + ) + required: list[str] | None = Field(None, min_length=1) + """ + Property names required by the constrained object. Must be non-empty: an empty array applies no constraint. + """ + properties: dict[str, ConstraintExpression | ValueConstraint] | None = None + """ + Constraints keyed by property name. Must be non-empty: an empty object applies no constraint. + """ + anyOf: list[ConstraintExpression] | None = None + """ + Alternative Object Constraints. The constrained object must satisfy at least one. A branch must be non-empty: an empty branch is satisfied by every object and neutralizes the alternation. + """ + + @field_validator("required", mode="after") + def _enforce_unique_items_required(cls, value): # noqa: N805 + """JSON Schema uniqueItems: reject duplicate entries.""" + if value is None: + return value + seen = [] + for item in value: + if item in seen: + raise ValueError( + "Items must be unique (schema uniqueItems=true)" + ) + seen.append(item) + return value + + +ConstraintExpression.model_rebuild() diff --git a/src/ucp_sdk/models/schemas/shopping/types/context.py b/src/ucp_sdk/models/schemas/common/types/context.py similarity index 72% rename from src/ucp_sdk/models/schemas/shopping/types/context.py rename to src/ucp_sdk/models/schemas/common/types/context.py index 66b4d73..b4bb158 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/context.py +++ b/src/ucp_sdk/models/schemas/common/types/context.py @@ -21,27 +21,34 @@ from pydantic import BaseModel, ConfigDict, field_validator from . import reverse_domain_name +from .locality import Locality -class Context(BaseModel): - """ - Provisional buyer signals for relevance and localization—not authoritative data. Businesses SHOULD use these values when verified inputs (e.g., shipping address) are absent, and MAY ignore or down-rank them if inconsistent with higher-confidence signals (authenticated account, risk detection) or regulatory constraints (export controls). Eligibility and policy enforcement MUST occur at checkout time using binding transaction data. Context SHOULD be non-identifying and can be disclosed progressively—coarse signals early, finer resolution as the session progresses. Higher-resolution data (shipping address, billing address) supersedes context. - """ - +class PaymentItem(BaseModel): model_config = ConfigDict( extra="allow", ) - address_country: str | None = None + handler: reverse_domain_name.ReverseDomainName """ - The country. Recommended to be in 2-letter ISO 3166-1 alpha-2 format, for example "US". For backward compatibility, a 3-letter ISO 3166-1 alpha-3 country code such as "SGP" or a full country name such as "Singapore" can also be used. Optional hint for market context (currency, availability, pricing)—higher-resolution data (e.g., shipping address) supersedes this value. + Handler registry key advertised in the Business profile's `ucp.payment_handlers`. """ - address_region: str | None = None + types: list[str] | None = None """ - The region in which the locality is, and which is in the country. For example, California or another appropriate first-level Administrative division. Optional hint for progressive localization—higher-resolution data (e.g., shipping address) supersedes this value. + Optional preferred instrument types for this handler, in priority order, aligned with the handler's advertised `payment_instrument.type` values (for example `card` or `bank`). Unrecognized values MUST be ignored. """ - postal_code: str | None = None + + +class Context(Locality): """ - The postal code. For example, 94043. Optional hint for regional refinement—higher-resolution data (e.g., shipping address) supersedes this value. + Provisional buyer signals for relevance and localization—not authoritative data. Businesses SHOULD use these values when verified inputs (e.g., shipping address) are absent, and MAY ignore or down-rank them if inconsistent with higher-confidence signals (authenticated account, risk detection) or regulatory constraints (export controls). Eligibility and policy enforcement MUST occur at checkout time using binding transaction data. Context SHOULD be non-identifying and can be disclosed progressively—coarse signals early, finer resolution as the session progresses. Higher-resolution data (shipping address, billing address) supersedes context. + """ + + model_config = ConfigDict( + extra="allow", + ) + location: str | None = None + """ + Stable, opaque identifier for a Location in the Business's namespace. This provisional, non-binding hint is distinct from the Buyer's locality. The operation specification or an active capability/extension defines its effects. A common example in retail shopping is the default home store ID selected and saved by the user when purchasing groceries. """ intent: str | None = None """ @@ -59,6 +66,10 @@ class Context(BaseModel): """ Buyer claims about eligible benefits such as loyalty membership, payment instrument perks, and similar. Recognized claims MAY inform the Business response (e.g., member-only product availability, adjusted pricing in catalog, provisional discounts at cart or checkout). Businesses MUST ignore unrecognized values without error. Values MUST use reverse-domain naming (e.g., 'com.example.loyalty_gold', 'org.school.student') and MUST be non-identifying. """ + payment: list[PaymentItem] | None = None + """ + Buyer-preferred payment handlers in priority order (most preferred first). Each entry names a handler advertised in the Business profile's `ucp.payment_handlers`, optionally narrowed to preferred instrument types. The Business SHOULD use it to preselect or prioritize the handler (and type, when given) and MAY ignore unavailable or ineligible entries; unrecognized values MUST be ignored without error. + """ @field_validator("eligibility", mode="after") def _enforce_unique_items_eligibility(cls, value): # noqa: N805 diff --git a/src/ucp_sdk/models/schemas/shopping/types/context_create_request.py b/src/ucp_sdk/models/schemas/common/types/context_create_request.py similarity index 68% rename from src/ucp_sdk/models/schemas/shopping/types/context_create_request.py rename to src/ucp_sdk/models/schemas/common/types/context_create_request.py index 6c86b1a..6efdcb9 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/context_create_request.py +++ b/src/ucp_sdk/models/schemas/common/types/context_create_request.py @@ -21,27 +21,34 @@ from pydantic import BaseModel, ConfigDict from . import reverse_domain_name_create_request +from .locality_create_request import LocalityCreateRequest -class ContextCreateRequest(BaseModel): - """ - Provisional buyer signals for relevance and localization—not authoritative data. Businesses SHOULD use these values when verified inputs (e.g., shipping address) are absent, and MAY ignore or down-rank them if inconsistent with higher-confidence signals (authenticated account, risk detection) or regulatory constraints (export controls). Eligibility and policy enforcement MUST occur at checkout time using binding transaction data. Context SHOULD be non-identifying and can be disclosed progressively—coarse signals early, finer resolution as the session progresses. Higher-resolution data (shipping address, billing address) supersedes context. - """ - +class PaymentItem(BaseModel): model_config = ConfigDict( extra="allow", ) - address_country: str | None = None + handler: reverse_domain_name_create_request.ReverseDomainNameCreateRequest """ - The country. Recommended to be in 2-letter ISO 3166-1 alpha-2 format, for example "US". For backward compatibility, a 3-letter ISO 3166-1 alpha-3 country code such as "SGP" or a full country name such as "Singapore" can also be used. Optional hint for market context (currency, availability, pricing)—higher-resolution data (e.g., shipping address) supersedes this value. + Handler registry key advertised in the Business profile's `ucp.payment_handlers`. """ - address_region: str | None = None + types: list[str] | None = None """ - The region in which the locality is, and which is in the country. For example, California or another appropriate first-level Administrative division. Optional hint for progressive localization—higher-resolution data (e.g., shipping address) supersedes this value. + Optional preferred instrument types for this handler, in priority order, aligned with the handler's advertised `payment_instrument.type` values (for example `card` or `bank`). Unrecognized values MUST be ignored. """ - postal_code: str | None = None + + +class ContextCreateRequest(LocalityCreateRequest): """ - The postal code. For example, 94043. Optional hint for regional refinement—higher-resolution data (e.g., shipping address) supersedes this value. + Provisional buyer signals for relevance and localization—not authoritative data. Businesses SHOULD use these values when verified inputs (e.g., shipping address) are absent, and MAY ignore or down-rank them if inconsistent with higher-confidence signals (authenticated account, risk detection) or regulatory constraints (export controls). Eligibility and policy enforcement MUST occur at checkout time using binding transaction data. Context SHOULD be non-identifying and can be disclosed progressively—coarse signals early, finer resolution as the session progresses. Higher-resolution data (shipping address, billing address) supersedes context. + """ + + model_config = ConfigDict( + extra="allow", + ) + location: str | None = None + """ + Stable, opaque identifier for a Location in the Business's namespace. This provisional, non-binding hint is distinct from the Buyer's locality. The operation specification or an active capability/extension defines its effects. A common example in retail shopping is the default home store ID selected and saved by the user when purchasing groceries. """ intent: str | None = None """ @@ -62,3 +69,7 @@ class ContextCreateRequest(BaseModel): """ Buyer claims about eligible benefits such as loyalty membership, payment instrument perks, and similar. Recognized claims MAY inform the Business response (e.g., member-only product availability, adjusted pricing in catalog, provisional discounts at cart or checkout). Businesses MUST ignore unrecognized values without error. Values MUST use reverse-domain naming (e.g., 'com.example.loyalty_gold', 'org.school.student') and MUST be non-identifying. """ + payment: list[PaymentItem] | None = None + """ + Buyer-preferred payment handlers in priority order (most preferred first). Each entry names a handler advertised in the Business profile's `ucp.payment_handlers`, optionally narrowed to preferred instrument types. The Business SHOULD use it to preselect or prioritize the handler (and type, when given) and MAY ignore unavailable or ineligible entries; unrecognized values MUST be ignored without error. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/context_update_request.py b/src/ucp_sdk/models/schemas/common/types/context_update_request.py similarity index 68% rename from src/ucp_sdk/models/schemas/shopping/types/context_update_request.py rename to src/ucp_sdk/models/schemas/common/types/context_update_request.py index 79610e9..b0bd4e1 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/context_update_request.py +++ b/src/ucp_sdk/models/schemas/common/types/context_update_request.py @@ -21,27 +21,34 @@ from pydantic import BaseModel, ConfigDict from . import reverse_domain_name_update_request +from .locality_update_request import LocalityUpdateRequest -class ContextUpdateRequest(BaseModel): - """ - Provisional buyer signals for relevance and localization—not authoritative data. Businesses SHOULD use these values when verified inputs (e.g., shipping address) are absent, and MAY ignore or down-rank them if inconsistent with higher-confidence signals (authenticated account, risk detection) or regulatory constraints (export controls). Eligibility and policy enforcement MUST occur at checkout time using binding transaction data. Context SHOULD be non-identifying and can be disclosed progressively—coarse signals early, finer resolution as the session progresses. Higher-resolution data (shipping address, billing address) supersedes context. - """ - +class PaymentItem(BaseModel): model_config = ConfigDict( extra="allow", ) - address_country: str | None = None + handler: reverse_domain_name_update_request.ReverseDomainNameUpdateRequest """ - The country. Recommended to be in 2-letter ISO 3166-1 alpha-2 format, for example "US". For backward compatibility, a 3-letter ISO 3166-1 alpha-3 country code such as "SGP" or a full country name such as "Singapore" can also be used. Optional hint for market context (currency, availability, pricing)—higher-resolution data (e.g., shipping address) supersedes this value. + Handler registry key advertised in the Business profile's `ucp.payment_handlers`. """ - address_region: str | None = None + types: list[str] | None = None """ - The region in which the locality is, and which is in the country. For example, California or another appropriate first-level Administrative division. Optional hint for progressive localization—higher-resolution data (e.g., shipping address) supersedes this value. + Optional preferred instrument types for this handler, in priority order, aligned with the handler's advertised `payment_instrument.type` values (for example `card` or `bank`). Unrecognized values MUST be ignored. """ - postal_code: str | None = None + + +class ContextUpdateRequest(LocalityUpdateRequest): """ - The postal code. For example, 94043. Optional hint for regional refinement—higher-resolution data (e.g., shipping address) supersedes this value. + Provisional buyer signals for relevance and localization—not authoritative data. Businesses SHOULD use these values when verified inputs (e.g., shipping address) are absent, and MAY ignore or down-rank them if inconsistent with higher-confidence signals (authenticated account, risk detection) or regulatory constraints (export controls). Eligibility and policy enforcement MUST occur at checkout time using binding transaction data. Context SHOULD be non-identifying and can be disclosed progressively—coarse signals early, finer resolution as the session progresses. Higher-resolution data (shipping address, billing address) supersedes context. + """ + + model_config = ConfigDict( + extra="allow", + ) + location: str | None = None + """ + Stable, opaque identifier for a Location in the Business's namespace. This provisional, non-binding hint is distinct from the Buyer's locality. The operation specification or an active capability/extension defines its effects. A common example in retail shopping is the default home store ID selected and saved by the user when purchasing groceries. """ intent: str | None = None """ @@ -62,3 +69,7 @@ class ContextUpdateRequest(BaseModel): """ Buyer claims about eligible benefits such as loyalty membership, payment instrument perks, and similar. Recognized claims MAY inform the Business response (e.g., member-only product availability, adjusted pricing in catalog, provisional discounts at cart or checkout). Businesses MUST ignore unrecognized values without error. Values MUST use reverse-domain naming (e.g., 'com.example.loyalty_gold', 'org.school.student') and MUST be non-identifying. """ + payment: list[PaymentItem] | None = None + """ + Buyer-preferred payment handlers in priority order (most preferred first). Each entry names a handler advertised in the Business profile's `ucp.payment_handlers`, optionally narrowed to preferred instrument types. The Business SHOULD use it to preselect or prioritize the handler (and type, when given) and MAY ignore unavailable or ineligible entries; unrecognized values MUST be ignored without error. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/description.py b/src/ucp_sdk/models/schemas/common/types/description.py similarity index 100% rename from src/ucp_sdk/models/schemas/shopping/types/description.py rename to src/ucp_sdk/models/schemas/common/types/description.py diff --git a/src/ucp_sdk/models/schemas/shopping/types/error_code.py b/src/ucp_sdk/models/schemas/common/types/error_code.py similarity index 92% rename from src/ucp_sdk/models/schemas/shopping/types/error_code.py rename to src/ucp_sdk/models/schemas/common/types/error_code.py index 346ac0c..07e34dd 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/error_code.py +++ b/src/ucp_sdk/models/schemas/common/types/error_code.py @@ -44,5 +44,5 @@ ], ) """ -Error code identifying the type of error. Standard errors are defined in specification (see examples), and have standardized semantics; freeform codes are permitted. +Error code identifying the type of error. Standard errors are defined in capability specifications (see examples) and have standardized semantics; freeform codes are permitted. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/error_code_create_request.py b/src/ucp_sdk/models/schemas/common/types/error_code_create_request.py similarity index 92% rename from src/ucp_sdk/models/schemas/shopping/types/error_code_create_request.py rename to src/ucp_sdk/models/schemas/common/types/error_code_create_request.py index c70c8e7..7ccc827 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/error_code_create_request.py +++ b/src/ucp_sdk/models/schemas/common/types/error_code_create_request.py @@ -44,5 +44,5 @@ ], ) """ -Error code identifying the type of error. Standard errors are defined in specification (see examples), and have standardized semantics; freeform codes are permitted. +Error code identifying the type of error. Standard errors are defined in capability specifications (see examples) and have standardized semantics; freeform codes are permitted. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/error_code_update_request.py b/src/ucp_sdk/models/schemas/common/types/error_code_update_request.py similarity index 92% rename from src/ucp_sdk/models/schemas/shopping/types/error_code_update_request.py rename to src/ucp_sdk/models/schemas/common/types/error_code_update_request.py index fab61ba..ec18e56 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/error_code_update_request.py +++ b/src/ucp_sdk/models/schemas/common/types/error_code_update_request.py @@ -44,5 +44,5 @@ ], ) """ -Error code identifying the type of error. Standard errors are defined in specification (see examples), and have standardized semantics; freeform codes are permitted. +Error code identifying the type of error. Standard errors are defined in capability specifications (see examples) and have standardized semantics; freeform codes are permitted. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/error_response.py b/src/ucp_sdk/models/schemas/common/types/error_response.py similarity index 100% rename from src/ucp_sdk/models/schemas/shopping/types/error_response.py rename to src/ucp_sdk/models/schemas/common/types/error_response.py diff --git a/src/ucp_sdk/models/schemas/shopping/types/info_code.py b/src/ucp_sdk/models/schemas/common/types/info_code.py similarity index 90% rename from src/ucp_sdk/models/schemas/shopping/types/info_code.py rename to src/ucp_sdk/models/schemas/common/types/info_code.py index a06eb3f..e691c86 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/info_code.py +++ b/src/ucp_sdk/models/schemas/common/types/info_code.py @@ -40,5 +40,5 @@ ], ) """ -Info code identifying the type of informational message. Standard codes are defined in capability specs (see examples), and have standardized semantics; freeform codes are permitted. +Info code identifying the type of informational message. Standard codes are defined in capability specifications (see examples) and have standardized semantics; freeform codes are permitted. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/info_code_create_request.py b/src/ucp_sdk/models/schemas/common/types/info_code_create_request.py similarity index 90% rename from src/ucp_sdk/models/schemas/shopping/types/info_code_create_request.py rename to src/ucp_sdk/models/schemas/common/types/info_code_create_request.py index 5a065eb..ad7cba6 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/info_code_create_request.py +++ b/src/ucp_sdk/models/schemas/common/types/info_code_create_request.py @@ -40,5 +40,5 @@ ], ) """ -Info code identifying the type of informational message. Standard codes are defined in capability specs (see examples), and have standardized semantics; freeform codes are permitted. +Info code identifying the type of informational message. Standard codes are defined in capability specifications (see examples) and have standardized semantics; freeform codes are permitted. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/info_code_update_request.py b/src/ucp_sdk/models/schemas/common/types/info_code_update_request.py similarity index 90% rename from src/ucp_sdk/models/schemas/shopping/types/info_code_update_request.py rename to src/ucp_sdk/models/schemas/common/types/info_code_update_request.py index ff78415..65c287f 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/info_code_update_request.py +++ b/src/ucp_sdk/models/schemas/common/types/info_code_update_request.py @@ -40,5 +40,5 @@ ], ) """ -Info code identifying the type of informational message. Standard codes are defined in capability specs (see examples), and have standardized semantics; freeform codes are permitted. +Info code identifying the type of informational message. Standard codes are defined in capability specifications (see examples) and have standardized semantics; freeform codes are permitted. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/link.py b/src/ucp_sdk/models/schemas/common/types/link.py similarity index 100% rename from src/ucp_sdk/models/schemas/shopping/types/link.py rename to src/ucp_sdk/models/schemas/common/types/link.py diff --git a/src/ucp_sdk/models/schemas/common/types/locality.py b/src/ucp_sdk/models/schemas/common/types/locality.py new file mode 100644 index 0000000..35ff9b8 --- /dev/null +++ b/src/ucp_sdk/models/schemas/common/types/locality.py @@ -0,0 +1,43 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from pydantic import BaseModel, ConfigDict + + +class Locality(BaseModel): + """ + A coarse geographic location — country, region, and postal code. A lightweight alternative to a full postal address. + """ + + model_config = ConfigDict( + extra="allow", + ) + address_country: str | None = None + """ + The country, as a 2-letter ISO 3166-1 alpha-2 code (e.g. "US"). A 3-letter alpha-3 code or full country name MAY also be used. + """ + address_region: str | None = None + """ + The first-level administrative region within the country (e.g. a state or province such as California). + """ + postal_code: str | None = None + """ + The postal code (e.g. "94043"). + """ diff --git a/src/ucp_sdk/models/schemas/common/types/locality_create_request.py b/src/ucp_sdk/models/schemas/common/types/locality_create_request.py new file mode 100644 index 0000000..2b6c4c6 --- /dev/null +++ b/src/ucp_sdk/models/schemas/common/types/locality_create_request.py @@ -0,0 +1,43 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from pydantic import BaseModel, ConfigDict + + +class LocalityCreateRequest(BaseModel): + """ + A coarse geographic location — country, region, and postal code. A lightweight alternative to a full postal address. + """ + + model_config = ConfigDict( + extra="allow", + ) + address_country: str | None = None + """ + The country, as a 2-letter ISO 3166-1 alpha-2 code (e.g. "US"). A 3-letter alpha-3 code or full country name MAY also be used. + """ + address_region: str | None = None + """ + The first-level administrative region within the country (e.g. a state or province such as California). + """ + postal_code: str | None = None + """ + The postal code (e.g. "94043"). + """ diff --git a/src/ucp_sdk/models/schemas/common/types/locality_update_request.py b/src/ucp_sdk/models/schemas/common/types/locality_update_request.py new file mode 100644 index 0000000..26c74ad --- /dev/null +++ b/src/ucp_sdk/models/schemas/common/types/locality_update_request.py @@ -0,0 +1,43 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from pydantic import BaseModel, ConfigDict + + +class LocalityUpdateRequest(BaseModel): + """ + A coarse geographic location — country, region, and postal code. A lightweight alternative to a full postal address. + """ + + model_config = ConfigDict( + extra="allow", + ) + address_country: str | None = None + """ + The country, as a 2-letter ISO 3166-1 alpha-2 code (e.g. "US"). A 3-letter alpha-3 code or full country name MAY also be used. + """ + address_region: str | None = None + """ + The first-level administrative region within the country (e.g. a state or province such as California). + """ + postal_code: str | None = None + """ + The postal code (e.g. "94043"). + """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/retail_location.py b/src/ucp_sdk/models/schemas/common/types/location_summary.py similarity index 85% rename from src/ucp_sdk/models/schemas/shopping/types/retail_location.py rename to src/ucp_sdk/models/schemas/common/types/location_summary.py index c0353af..8ae5eef 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/retail_location.py +++ b/src/ucp_sdk/models/schemas/common/types/location_summary.py @@ -23,9 +23,9 @@ from . import postal_address -class RetailLocation(BaseModel): +class LocationSummary(BaseModel): """ - A pickup location (retail store, locker, etc.). + A summary of a business location. """ model_config = ConfigDict( @@ -33,11 +33,11 @@ class RetailLocation(BaseModel): ) id: str """ - Unique location identifier. + Stable, opaque, Business-scoped Location identifier. """ name: str """ - Location name (e.g., store name). + Buyer-facing, Business-owned display name. """ address: postal_address.PostalAddress | None = None """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/account_info.py b/src/ucp_sdk/models/schemas/common/types/location_summary_create_request.py similarity index 74% rename from src/ucp_sdk/models/schemas/shopping/types/account_info.py rename to src/ucp_sdk/models/schemas/common/types/location_summary_create_request.py index aeb2665..683453b 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/account_info.py +++ b/src/ucp_sdk/models/schemas/common/types/location_summary_create_request.py @@ -21,15 +21,15 @@ from pydantic import BaseModel, ConfigDict -class PaymentAccountInfo(BaseModel): +class LocationSummaryCreateRequest(BaseModel): """ - Non-sensitive backend identifiers for linking. + A summary of a business location. """ model_config = ConfigDict( extra="allow", ) - payment_account_reference: str | None = None + id: str """ - EMVCo PAR. A unique identifier linking a payment card to a specific account, enabling tracking across tokens (Apple Pay, physical card, etc). + Stable, opaque, Business-scoped Location identifier. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/retail_location_update_request.py b/src/ucp_sdk/models/schemas/common/types/location_summary_update_request.py similarity index 70% rename from src/ucp_sdk/models/schemas/shopping/types/retail_location_update_request.py rename to src/ucp_sdk/models/schemas/common/types/location_summary_update_request.py index b5aa0de..7102a5e 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/retail_location_update_request.py +++ b/src/ucp_sdk/models/schemas/common/types/location_summary_update_request.py @@ -20,24 +20,16 @@ from pydantic import BaseModel, ConfigDict -from . import postal_address_update_request - -class RetailLocationUpdateRequest(BaseModel): +class LocationSummaryUpdateRequest(BaseModel): """ - A pickup location (retail store, locker, etc.). + A summary of a business location. """ model_config = ConfigDict( extra="allow", ) - name: str - """ - Location name (e.g., store name). - """ - address: postal_address_update_request.PostalAddressUpdateRequest | None = ( - None - ) + id: str """ - Physical address of the location. + Stable, opaque, Business-scoped Location identifier. """ diff --git a/src/ucp_sdk/models/schemas/common/types/measure.py b/src/ucp_sdk/models/schemas/common/types/measure.py new file mode 100644 index 0000000..f085f51 --- /dev/null +++ b/src/ucp_sdk/models/schemas/common/types/measure.py @@ -0,0 +1,37 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from pydantic import ConfigDict, Field + +from .unit import Unit + + +class Measure(Unit): + """ + A measure composed of an integer value and a unit descriptor. Its value is the integer count of `10^-scale` units of `unit`. + """ + + model_config = ConfigDict( + extra="allow", + ) + value: int = Field(..., ge=-9007199254740991, le=9007199254740991) + """ + Integer count of `10^-scale` units of `unit`. + """ diff --git a/src/ucp_sdk/models/schemas/common/types/measure_create_request.py b/src/ucp_sdk/models/schemas/common/types/measure_create_request.py new file mode 100644 index 0000000..006326d --- /dev/null +++ b/src/ucp_sdk/models/schemas/common/types/measure_create_request.py @@ -0,0 +1,37 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from pydantic import ConfigDict, Field + +from .unit_create_request import UnitCreateRequest + + +class MeasureCreateRequest(UnitCreateRequest): + """ + A measure composed of an integer value and a unit descriptor. Its value is the integer count of `10^-scale` units of `unit`. + """ + + model_config = ConfigDict( + extra="allow", + ) + value: int = Field(..., ge=-9007199254740991, le=9007199254740991) + """ + Integer count of `10^-scale` units of `unit`. + """ diff --git a/src/ucp_sdk/models/schemas/common/types/measure_update_request.py b/src/ucp_sdk/models/schemas/common/types/measure_update_request.py new file mode 100644 index 0000000..b2b08ea --- /dev/null +++ b/src/ucp_sdk/models/schemas/common/types/measure_update_request.py @@ -0,0 +1,37 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from pydantic import ConfigDict, Field + +from .unit_update_request import UnitUpdateRequest + + +class MeasureUpdateRequest(UnitUpdateRequest): + """ + A measure composed of an integer value and a unit descriptor. Its value is the integer count of `10^-scale` units of `unit`. + """ + + model_config = ConfigDict( + extra="allow", + ) + value: int = Field(..., ge=-9007199254740991, le=9007199254740991) + """ + Integer count of `10^-scale` units of `unit`. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/media.py b/src/ucp_sdk/models/schemas/common/types/media.py similarity index 96% rename from src/ucp_sdk/models/schemas/shopping/types/media.py rename to src/ucp_sdk/models/schemas/common/types/media.py index dc8338a..b716792 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/media.py +++ b/src/ucp_sdk/models/schemas/common/types/media.py @@ -23,7 +23,7 @@ class Media(BaseModel): """ - Product media item (image, video, etc.). + Media item (image, video, etc.). """ model_config = ConfigDict( diff --git a/src/ucp_sdk/models/schemas/shopping/types/message.py b/src/ucp_sdk/models/schemas/common/types/message.py similarity index 100% rename from src/ucp_sdk/models/schemas/shopping/types/message.py rename to src/ucp_sdk/models/schemas/common/types/message.py diff --git a/src/ucp_sdk/models/schemas/shopping/types/message_create_request.py b/src/ucp_sdk/models/schemas/common/types/message_create_request.py similarity index 100% rename from src/ucp_sdk/models/schemas/shopping/types/message_create_request.py rename to src/ucp_sdk/models/schemas/common/types/message_create_request.py diff --git a/src/ucp_sdk/models/schemas/shopping/types/message_error.py b/src/ucp_sdk/models/schemas/common/types/message_error.py similarity index 71% rename from src/ucp_sdk/models/schemas/shopping/types/message_error.py rename to src/ucp_sdk/models/schemas/common/types/message_error.py index e74117c..9ac973c 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/message_error.py +++ b/src/ucp_sdk/models/schemas/common/types/message_error.py @@ -36,7 +36,7 @@ class MessageError(BaseModel): code: error_code.ErrorCode path: str | None = None """ - RFC 9535 JSONPath to the component the message refers to (e.g., $.items[1]). + RFC 9535 JSONPath to the component the message refers to (e.g., $.line_items[0]). """ content_type: Literal["plain", "markdown"] | None = "plain" """ @@ -53,5 +53,5 @@ class MessageError(BaseModel): "unrecoverable", ] """ - Reflects the resource state and recommended action. 'recoverable': platform can resolve by modifying inputs and retrying via API. 'requires_buyer_input': merchant requires information their API doesn't support collecting programmatically (checkout incomplete). 'requires_buyer_review': buyer must authorize before order placement due to policy, regulatory, or entitlement rules. 'unrecoverable': no valid resource exists to act on, retry with new resource or inputs. Errors with 'requires_*' severity contribute to 'status: requires_escalation'. + Reflects the resource state and recommended action. 'recoverable': platform can resolve the condition in band, for example by modifying inputs or processing a related Action, and submit a new operation when needed. 'requires_buyer_input': merchant requires information their API doesn't support collecting programmatically (checkout incomplete). 'requires_buyer_review': buyer must authorize before order placement due to policy, regulatory, or entitlement rules. 'unrecoverable': no valid resource exists to act on, retry with new resource or inputs. Errors with 'requires_*' severity contribute to 'status: requires_escalation'. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/message_error_create_request.py b/src/ucp_sdk/models/schemas/common/types/message_error_create_request.py similarity index 72% rename from src/ucp_sdk/models/schemas/shopping/types/message_error_create_request.py rename to src/ucp_sdk/models/schemas/common/types/message_error_create_request.py index 9375f6c..cd13b78 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/message_error_create_request.py +++ b/src/ucp_sdk/models/schemas/common/types/message_error_create_request.py @@ -36,7 +36,7 @@ class MessageErrorCreateRequest(BaseModel): code: error_code_create_request.ErrorCodeCreateRequest path: str | None = None """ - RFC 9535 JSONPath to the component the message refers to (e.g., $.items[1]). + RFC 9535 JSONPath to the component the message refers to (e.g., $.line_items[0]). """ content_type: Literal["plain", "markdown"] | None = "plain" """ @@ -53,5 +53,5 @@ class MessageErrorCreateRequest(BaseModel): "unrecoverable", ] """ - Reflects the resource state and recommended action. 'recoverable': platform can resolve by modifying inputs and retrying via API. 'requires_buyer_input': merchant requires information their API doesn't support collecting programmatically (checkout incomplete). 'requires_buyer_review': buyer must authorize before order placement due to policy, regulatory, or entitlement rules. 'unrecoverable': no valid resource exists to act on, retry with new resource or inputs. Errors with 'requires_*' severity contribute to 'status: requires_escalation'. + Reflects the resource state and recommended action. 'recoverable': platform can resolve the condition in band, for example by modifying inputs or processing a related Action, and submit a new operation when needed. 'requires_buyer_input': merchant requires information their API doesn't support collecting programmatically (checkout incomplete). 'requires_buyer_review': buyer must authorize before order placement due to policy, regulatory, or entitlement rules. 'unrecoverable': no valid resource exists to act on, retry with new resource or inputs. Errors with 'requires_*' severity contribute to 'status: requires_escalation'. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/message_error_update_request.py b/src/ucp_sdk/models/schemas/common/types/message_error_update_request.py similarity index 72% rename from src/ucp_sdk/models/schemas/shopping/types/message_error_update_request.py rename to src/ucp_sdk/models/schemas/common/types/message_error_update_request.py index 3ad566d..94fcb77 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/message_error_update_request.py +++ b/src/ucp_sdk/models/schemas/common/types/message_error_update_request.py @@ -36,7 +36,7 @@ class MessageErrorUpdateRequest(BaseModel): code: error_code_update_request.ErrorCodeUpdateRequest path: str | None = None """ - RFC 9535 JSONPath to the component the message refers to (e.g., $.items[1]). + RFC 9535 JSONPath to the component the message refers to (e.g., $.line_items[0]). """ content_type: Literal["plain", "markdown"] | None = "plain" """ @@ -53,5 +53,5 @@ class MessageErrorUpdateRequest(BaseModel): "unrecoverable", ] """ - Reflects the resource state and recommended action. 'recoverable': platform can resolve by modifying inputs and retrying via API. 'requires_buyer_input': merchant requires information their API doesn't support collecting programmatically (checkout incomplete). 'requires_buyer_review': buyer must authorize before order placement due to policy, regulatory, or entitlement rules. 'unrecoverable': no valid resource exists to act on, retry with new resource or inputs. Errors with 'requires_*' severity contribute to 'status: requires_escalation'. + Reflects the resource state and recommended action. 'recoverable': platform can resolve the condition in band, for example by modifying inputs or processing a related Action, and submit a new operation when needed. 'requires_buyer_input': merchant requires information their API doesn't support collecting programmatically (checkout incomplete). 'requires_buyer_review': buyer must authorize before order placement due to policy, regulatory, or entitlement rules. 'unrecoverable': no valid resource exists to act on, retry with new resource or inputs. Errors with 'requires_*' severity contribute to 'status: requires_escalation'. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/message_info.py b/src/ucp_sdk/models/schemas/common/types/message_info.py similarity index 93% rename from src/ucp_sdk/models/schemas/shopping/types/message_info.py rename to src/ucp_sdk/models/schemas/common/types/message_info.py index b8ef016..2057e35 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/message_info.py +++ b/src/ucp_sdk/models/schemas/common/types/message_info.py @@ -35,7 +35,7 @@ class MessageInfo(BaseModel): """ path: str | None = None """ - RFC 9535 JSONPath to the component the message refers to. + RFC 9535 JSONPath to the component the message refers to (e.g., $.line_items[0]). """ code: info_code.InfoCode | None = None content_type: Literal["plain", "markdown"] | None = "plain" diff --git a/src/ucp_sdk/models/schemas/shopping/types/message_info_create_request.py b/src/ucp_sdk/models/schemas/common/types/message_info_create_request.py similarity index 93% rename from src/ucp_sdk/models/schemas/shopping/types/message_info_create_request.py rename to src/ucp_sdk/models/schemas/common/types/message_info_create_request.py index aa715d7..79b7738 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/message_info_create_request.py +++ b/src/ucp_sdk/models/schemas/common/types/message_info_create_request.py @@ -35,7 +35,7 @@ class MessageInfoCreateRequest(BaseModel): """ path: str | None = None """ - RFC 9535 JSONPath to the component the message refers to. + RFC 9535 JSONPath to the component the message refers to (e.g., $.line_items[0]). """ code: info_code_create_request.InfoCodeCreateRequest | None = None content_type: Literal["plain", "markdown"] | None = "plain" diff --git a/src/ucp_sdk/models/schemas/shopping/types/message_info_update_request.py b/src/ucp_sdk/models/schemas/common/types/message_info_update_request.py similarity index 93% rename from src/ucp_sdk/models/schemas/shopping/types/message_info_update_request.py rename to src/ucp_sdk/models/schemas/common/types/message_info_update_request.py index 5f206ad..6a9f79c 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/message_info_update_request.py +++ b/src/ucp_sdk/models/schemas/common/types/message_info_update_request.py @@ -35,7 +35,7 @@ class MessageInfoUpdateRequest(BaseModel): """ path: str | None = None """ - RFC 9535 JSONPath to the component the message refers to. + RFC 9535 JSONPath to the component the message refers to (e.g., $.line_items[0]). """ code: info_code_update_request.InfoCodeUpdateRequest | None = None content_type: Literal["plain", "markdown"] | None = "plain" diff --git a/src/ucp_sdk/models/schemas/shopping/types/message_update_request.py b/src/ucp_sdk/models/schemas/common/types/message_update_request.py similarity index 100% rename from src/ucp_sdk/models/schemas/shopping/types/message_update_request.py rename to src/ucp_sdk/models/schemas/common/types/message_update_request.py diff --git a/src/ucp_sdk/models/schemas/shopping/types/message_warning.py b/src/ucp_sdk/models/schemas/common/types/message_warning.py similarity index 95% rename from src/ucp_sdk/models/schemas/shopping/types/message_warning.py rename to src/ucp_sdk/models/schemas/common/types/message_warning.py index 772134f..e816234 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/message_warning.py +++ b/src/ucp_sdk/models/schemas/common/types/message_warning.py @@ -35,7 +35,7 @@ class MessageWarning(BaseModel): """ path: str | None = None """ - JSONPath (RFC 9535) to related field (e.g., $.line_items[0]). + RFC 9535 JSONPath to the component the message refers to (e.g., $.line_items[0]). """ code: warning_code.WarningCode content: str diff --git a/src/ucp_sdk/models/schemas/shopping/types/message_warning_create_request.py b/src/ucp_sdk/models/schemas/common/types/message_warning_create_request.py similarity index 95% rename from src/ucp_sdk/models/schemas/shopping/types/message_warning_create_request.py rename to src/ucp_sdk/models/schemas/common/types/message_warning_create_request.py index 5294a25..712c72f 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/message_warning_create_request.py +++ b/src/ucp_sdk/models/schemas/common/types/message_warning_create_request.py @@ -35,7 +35,7 @@ class MessageWarningCreateRequest(BaseModel): """ path: str | None = None """ - JSONPath (RFC 9535) to related field (e.g., $.line_items[0]). + RFC 9535 JSONPath to the component the message refers to (e.g., $.line_items[0]). """ code: warning_code_create_request.WarningCodeCreateRequest content: str diff --git a/src/ucp_sdk/models/schemas/shopping/types/message_warning_update_request.py b/src/ucp_sdk/models/schemas/common/types/message_warning_update_request.py similarity index 95% rename from src/ucp_sdk/models/schemas/shopping/types/message_warning_update_request.py rename to src/ucp_sdk/models/schemas/common/types/message_warning_update_request.py index 44cd08d..83944e6 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/message_warning_update_request.py +++ b/src/ucp_sdk/models/schemas/common/types/message_warning_update_request.py @@ -35,7 +35,7 @@ class MessageWarningUpdateRequest(BaseModel): """ path: str | None = None """ - JSONPath (RFC 9535) to related field (e.g., $.line_items[0]). + RFC 9535 JSONPath to the component the message refers to (e.g., $.line_items[0]). """ code: warning_code_update_request.WarningCodeUpdateRequest content: str diff --git a/src/ucp_sdk/models/schemas/shopping/types/pagination.py b/src/ucp_sdk/models/schemas/common/types/pagination.py similarity index 100% rename from src/ucp_sdk/models/schemas/shopping/types/pagination.py rename to src/ucp_sdk/models/schemas/common/types/pagination.py diff --git a/src/ucp_sdk/models/schemas/common/types/policy.py b/src/ucp_sdk/models/schemas/common/types/policy.py new file mode 100644 index 0000000..9db2ca7 --- /dev/null +++ b/src/ucp_sdk/models/schemas/common/types/policy.py @@ -0,0 +1,50 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from pydantic import AnyUrl, BaseModel, ConfigDict + +from . import description as description_1 +from . import reverse_domain_name + + +class Policy(BaseModel): + """ + A durable business rule about the items in a response — return/refund terms, warranty, and the like — at the time of purchase. Every policy carries a `type` (an open reverse-DNS vocabulary) and a `description` so a platform can present it without understanding its type-specific fields; type-specific fields (gated by `type`) add structured context for platforms that model that type. Policies are reference data; the obligation to display a term to the buyer is carried by a `messages[]` warning whose `code` equals the policy `type` — see the Policies section of the specification. + """ + + model_config = ConfigDict( + extra="allow", + ) + type: reverse_domain_name.ReverseDomainName + """ + Policy type discriminator. Open reverse-DNS vocabulary. Well-known values: `dev.ucp.shopping.policy.return` (return terms), `dev.ucp.shopping.policy.warranty` (warranty terms). Businesses MAY define custom types in their own domain (e.g., `com.example.policy.price_match`). Platforms MUST tolerate unknown values. + """ + description: description_1.Description + """ + Human-readable policy summary in one or more formats (plain, markdown, html). Required on every policy so a platform can present it without understanding any type-specific fields. This is not the buyer-facing disclosure — display is compelled by a `messages[]` warning (see the Policies section). + """ + applies_to: list[str] | None = None + """ + RFC 9535 JSONPath expressions identifying the nodes this policy applies to, relative to the embedding response root (e.g., `$.line_items[0]` in cart/checkout, `$.products[2]` in catalog). Each target covers the node it names and everything nested under it, so a target on a product also covers its variants. A singular query (RFC 9535 Section 2.3.5.1; name and index selectors only) names a single node; filters, wildcards, and slices match a set. When omitted, the policy applies to the entire response. When policies of the same `type` contest a node, the narrowest target wins and overrides the rest. See the Policies section for how specificity resolves. + """ + url: AnyUrl | None = None + """ + Optional link to the full policy document. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/postal_address.py b/src/ucp_sdk/models/schemas/common/types/postal_address.py similarity index 100% rename from src/ucp_sdk/models/schemas/shopping/types/postal_address.py rename to src/ucp_sdk/models/schemas/common/types/postal_address.py diff --git a/src/ucp_sdk/models/schemas/shopping/types/postal_address_complete_request.py b/src/ucp_sdk/models/schemas/common/types/postal_address_complete_request.py similarity index 100% rename from src/ucp_sdk/models/schemas/shopping/types/postal_address_complete_request.py rename to src/ucp_sdk/models/schemas/common/types/postal_address_complete_request.py diff --git a/src/ucp_sdk/models/schemas/shopping/types/postal_address_create_request.py b/src/ucp_sdk/models/schemas/common/types/postal_address_create_request.py similarity index 100% rename from src/ucp_sdk/models/schemas/shopping/types/postal_address_create_request.py rename to src/ucp_sdk/models/schemas/common/types/postal_address_create_request.py diff --git a/src/ucp_sdk/models/schemas/shopping/types/postal_address_update_request.py b/src/ucp_sdk/models/schemas/common/types/postal_address_update_request.py similarity index 100% rename from src/ucp_sdk/models/schemas/shopping/types/postal_address_update_request.py rename to src/ucp_sdk/models/schemas/common/types/postal_address_update_request.py diff --git a/src/ucp_sdk/models/schemas/shopping/types/price.py b/src/ucp_sdk/models/schemas/common/types/price.py similarity index 100% rename from src/ucp_sdk/models/schemas/shopping/types/price.py rename to src/ucp_sdk/models/schemas/common/types/price.py diff --git a/src/ucp_sdk/models/schemas/shopping/types/price_filter.py b/src/ucp_sdk/models/schemas/common/types/price_filter.py similarity index 100% rename from src/ucp_sdk/models/schemas/shopping/types/price_filter.py rename to src/ucp_sdk/models/schemas/common/types/price_filter.py diff --git a/src/ucp_sdk/models/schemas/shopping/types/price_range.py b/src/ucp_sdk/models/schemas/common/types/price_range.py similarity index 92% rename from src/ucp_sdk/models/schemas/shopping/types/price_range.py rename to src/ucp_sdk/models/schemas/common/types/price_range.py index d3129db..1c8e47b 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/price_range.py +++ b/src/ucp_sdk/models/schemas/common/types/price_range.py @@ -25,7 +25,7 @@ class PriceRange(BaseModel): """ - A price range representing minimum and maximum values (e.g., across product variants). + A price range representing minimum and maximum values (e.g., a common example in retail shopping is when prices vary across product variants). """ model_config = ConfigDict( diff --git a/src/ucp_sdk/models/schemas/common/types/quantity_unit.py b/src/ucp_sdk/models/schemas/common/types/quantity_unit.py new file mode 100644 index 0000000..44d14dd --- /dev/null +++ b/src/ucp_sdk/models/schemas/common/types/quantity_unit.py @@ -0,0 +1,37 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from pydantic import ConfigDict, Field + +from .unit import Unit + + +class QuantityUnit(Unit): + """ + Sale-basis descriptor for quantities: the shared unit descriptor plus the Business's ordering policy. Its unit-descriptor machine identity remains (`unit`, effective `scale`); `display_text` and `increment` are excluded from identity and mismatch comparison. + """ + + model_config = ConfigDict( + extra="allow", + ) + increment: int | None = Field(1, ge=1) + """ + Ordering granularity, denominated in steps: the Business sells this item in integer multiples of `increment` steps. Its effective value is the provided value or 1. Advisory merchandising policy, not a representational bound: Platform-authored quantities SHOULD be integer multiples of the effective increment; the Business MAY accept, revise, or reject an off-increment request with a recoverable business outcome and MUST NOT silently reinterpret it. Business-authored quantities (checkout revisions, fulfillment events, adjustments) are bounded only by `scale`. + """ diff --git a/src/ucp_sdk/models/schemas/common/types/quantity_unit_create_request.py b/src/ucp_sdk/models/schemas/common/types/quantity_unit_create_request.py new file mode 100644 index 0000000..7a38b38 --- /dev/null +++ b/src/ucp_sdk/models/schemas/common/types/quantity_unit_create_request.py @@ -0,0 +1,37 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from pydantic import ConfigDict, Field + +from .unit_create_request import UnitCreateRequest + + +class QuantityUnitCreateRequest(UnitCreateRequest): + """ + Sale-basis descriptor for quantities: the shared unit descriptor plus the Business's ordering policy. Its unit-descriptor machine identity remains (`unit`, effective `scale`); `display_text` and `increment` are excluded from identity and mismatch comparison. + """ + + model_config = ConfigDict( + extra="allow", + ) + increment: int | None = Field(1, ge=1) + """ + Ordering granularity, denominated in steps: the Business sells this item in integer multiples of `increment` steps. Its effective value is the provided value or 1. Advisory merchandising policy, not a representational bound: Platform-authored quantities SHOULD be integer multiples of the effective increment; the Business MAY accept, revise, or reject an off-increment request with a recoverable business outcome and MUST NOT silently reinterpret it. Business-authored quantities (checkout revisions, fulfillment events, adjustments) are bounded only by `scale`. + """ diff --git a/src/ucp_sdk/models/schemas/common/types/quantity_unit_update_request.py b/src/ucp_sdk/models/schemas/common/types/quantity_unit_update_request.py new file mode 100644 index 0000000..cadcad3 --- /dev/null +++ b/src/ucp_sdk/models/schemas/common/types/quantity_unit_update_request.py @@ -0,0 +1,37 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from pydantic import ConfigDict, Field + +from .unit_update_request import UnitUpdateRequest + + +class QuantityUnitUpdateRequest(UnitUpdateRequest): + """ + Sale-basis descriptor for quantities: the shared unit descriptor plus the Business's ordering policy. Its unit-descriptor machine identity remains (`unit`, effective `scale`); `display_text` and `increment` are excluded from identity and mismatch comparison. + """ + + model_config = ConfigDict( + extra="allow", + ) + increment: int | None = Field(1, ge=1) + """ + Ordering granularity, denominated in steps: the Business sells this item in integer multiples of `increment` steps. Its effective value is the provided value or 1. Advisory merchandising policy, not a representational bound: Platform-authored quantities SHOULD be integer multiples of the effective increment; the Business MAY accept, revise, or reject an off-increment request with a recoverable business outcome and MUST NOT silently reinterpret it. Business-authored quantities (checkout revisions, fulfillment events, adjustments) are bounded only by `scale`. + """ diff --git a/src/ucp_sdk/models/schemas/common/types/request_constraints.py b/src/ucp_sdk/models/schemas/common/types/request_constraints.py new file mode 100644 index 0000000..58b3294 --- /dev/null +++ b/src/ucp_sdk/models/schemas/common/types/request_constraints.py @@ -0,0 +1,72 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from pydantic import BaseModel, ConfigDict, Field, field_validator + +from . import constraint_expression + + +class RequestConstraints(BaseModel): + """ + Binds the shared Constraint Expression grammar to data in the next UCP request to the same resource. + """ + + model_config = ConfigDict( + extra="forbid", + ) + path: str | None = None + """ + A complete RFC 9535 JSONPath query evaluated against the next logical UCP request to the same resource. + """ + required: list[str] | None = Field(None, min_length=1) + """ + Property names required by the constrained object. Must be non-empty: an empty array applies no constraint. + """ + properties: ( + dict[ + str, + constraint_expression.ConstraintExpression + | constraint_expression.ValueConstraint, + ] + | None + ) = Field(None, min_length=1) + """ + Constraints keyed by property name. Must be non-empty: an empty object applies no constraint. + """ + anyOf: list[constraint_expression.ConstraintExpression] | None = Field( + None, min_length=1 + ) + """ + Alternative Object Constraints. The constrained object must satisfy at least one. A branch must be non-empty: an empty branch is satisfied by every object and neutralizes the alternation. + """ + + @field_validator("required", mode="after") + def _enforce_unique_items_required(cls, value): # noqa: N805 + """JSON Schema uniqueItems: reject duplicate entries.""" + if value is None: + return value + seen = [] + for item in value: + if item in seen: + raise ValueError( + "Items must be unique (schema uniqueItems=true)" + ) + seen.append(item) + return value diff --git a/src/ucp_sdk/models/schemas/shopping/types/reverse_domain_name.py b/src/ucp_sdk/models/schemas/common/types/reverse_domain_name.py similarity index 57% rename from src/ucp_sdk/models/schemas/shopping/types/reverse_domain_name.py rename to src/ucp_sdk/models/schemas/common/types/reverse_domain_name.py index 3905247..733442e 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/reverse_domain_name.py +++ b/src/ucp_sdk/models/schemas/common/types/reverse_domain_name.py @@ -29,11 +29,20 @@ str, Field( ..., - pattern="^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$", + examples=[ + "dev.ucp.shopping.checkout", + "dev.ucp.common.identity_linking", + "com.example.loyalty_gold", + "com.example-shop.checkout", + "com.2example.cart", + "uk.co.example-shop.checkout", + "xn--p1ai.example.checkout", + ], + pattern="^[a-z](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9_])?)+$", title="Reverse Domain Name", ), ], ) """ -Reverse-domain identifier used for collision-safe namespacing of capabilities, services, handlers, eligibility claims, and extension-contributed keys. Must contain at least two dot-separated segments (e.g., 'dev.ucp.shopping.checkout', 'com.example.loyalty_gold'). +Reverse-domain identifier used for collision-safe namespacing of capabilities, services, handlers, eligibility claims, and extension-contributed keys. Must contain at least two dot-separated segments (e.g., 'dev.ucp.shopping.checkout', 'com.example.loyalty_gold'). Segments after the first are domain- or identifier-derived: they may contain interior hyphens, may start with a digit, and may contain underscores (e.g., 'com.example-shop.checkout', 'com.2example.cart', 'dev.ucp.common.identity_linking'), but must not start or end with a hyphen. The first segment (the reversed top-level domain) is letters and digits, and may contain interior hyphens to support internationalized (punycode) top-level domains such as 'xn--p1ai'. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/reverse_domain_name_create_request.py b/src/ucp_sdk/models/schemas/common/types/reverse_domain_name_create_request.py similarity index 58% rename from src/ucp_sdk/models/schemas/shopping/types/reverse_domain_name_create_request.py rename to src/ucp_sdk/models/schemas/common/types/reverse_domain_name_create_request.py index 01bec46..b8ae8ba 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/reverse_domain_name_create_request.py +++ b/src/ucp_sdk/models/schemas/common/types/reverse_domain_name_create_request.py @@ -29,11 +29,20 @@ str, Field( ..., - pattern="^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$", + examples=[ + "dev.ucp.shopping.checkout", + "dev.ucp.common.identity_linking", + "com.example.loyalty_gold", + "com.example-shop.checkout", + "com.2example.cart", + "uk.co.example-shop.checkout", + "xn--p1ai.example.checkout", + ], + pattern="^[a-z](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9_])?)+$", title="Reverse Domain Name Create Request", ), ], ) """ -Reverse-domain identifier used for collision-safe namespacing of capabilities, services, handlers, eligibility claims, and extension-contributed keys. Must contain at least two dot-separated segments (e.g., 'dev.ucp.shopping.checkout', 'com.example.loyalty_gold'). +Reverse-domain identifier used for collision-safe namespacing of capabilities, services, handlers, eligibility claims, and extension-contributed keys. Must contain at least two dot-separated segments (e.g., 'dev.ucp.shopping.checkout', 'com.example.loyalty_gold'). Segments after the first are domain- or identifier-derived: they may contain interior hyphens, may start with a digit, and may contain underscores (e.g., 'com.example-shop.checkout', 'com.2example.cart', 'dev.ucp.common.identity_linking'), but must not start or end with a hyphen. The first segment (the reversed top-level domain) is letters and digits, and may contain interior hyphens to support internationalized (punycode) top-level domains such as 'xn--p1ai'. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/reverse_domain_name_update_request.py b/src/ucp_sdk/models/schemas/common/types/reverse_domain_name_update_request.py similarity index 58% rename from src/ucp_sdk/models/schemas/shopping/types/reverse_domain_name_update_request.py rename to src/ucp_sdk/models/schemas/common/types/reverse_domain_name_update_request.py index 613ed16..f0beeca 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/reverse_domain_name_update_request.py +++ b/src/ucp_sdk/models/schemas/common/types/reverse_domain_name_update_request.py @@ -29,11 +29,20 @@ str, Field( ..., - pattern="^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$", + examples=[ + "dev.ucp.shopping.checkout", + "dev.ucp.common.identity_linking", + "com.example.loyalty_gold", + "com.example-shop.checkout", + "com.2example.cart", + "uk.co.example-shop.checkout", + "xn--p1ai.example.checkout", + ], + pattern="^[a-z](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9_])?)+$", title="Reverse Domain Name Update Request", ), ], ) """ -Reverse-domain identifier used for collision-safe namespacing of capabilities, services, handlers, eligibility claims, and extension-contributed keys. Must contain at least two dot-separated segments (e.g., 'dev.ucp.shopping.checkout', 'com.example.loyalty_gold'). +Reverse-domain identifier used for collision-safe namespacing of capabilities, services, handlers, eligibility claims, and extension-contributed keys. Must contain at least two dot-separated segments (e.g., 'dev.ucp.shopping.checkout', 'com.example.loyalty_gold'). Segments after the first are domain- or identifier-derived: they may contain interior hyphens, may start with a digit, and may contain underscores (e.g., 'com.example-shop.checkout', 'com.2example.cart', 'dev.ucp.common.identity_linking'), but must not start or end with a hyphen. The first segment (the reversed top-level domain) is letters and digits, and may contain interior hyphens to support internationalized (punycode) top-level domains such as 'xn--p1ai'. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/signals.py b/src/ucp_sdk/models/schemas/common/types/signals.py similarity index 95% rename from src/ucp_sdk/models/schemas/shopping/types/signals.py rename to src/ucp_sdk/models/schemas/common/types/signals.py index 2e0ad9c..7176f00 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/signals.py +++ b/src/ucp_sdk/models/schemas/common/types/signals.py @@ -44,7 +44,7 @@ class Signals(BaseModel): def _enforce_property_names(self): """JSON Schema propertyNames: every extra key must match the declared reverse-domain pattern (schema propertyNames).""" - pattern = "^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$" + pattern = "^[a-z](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9_])?)+$" for key in self.model_extra or {}: if re.fullmatch(pattern, key) is None: raise ValueError( diff --git a/src/ucp_sdk/models/schemas/shopping/types/signals_complete_request.py b/src/ucp_sdk/models/schemas/common/types/signals_complete_request.py similarity index 95% rename from src/ucp_sdk/models/schemas/shopping/types/signals_complete_request.py rename to src/ucp_sdk/models/schemas/common/types/signals_complete_request.py index fa2ecbf..0e46c33 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/signals_complete_request.py +++ b/src/ucp_sdk/models/schemas/common/types/signals_complete_request.py @@ -44,7 +44,7 @@ class SignalsCompleteRequest(BaseModel): def _enforce_property_names(self): """JSON Schema propertyNames: every extra key must match the declared reverse-domain pattern (schema propertyNames).""" - pattern = "^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$" + pattern = "^[a-z](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9_])?)+$" for key in self.model_extra or {}: if re.fullmatch(pattern, key) is None: raise ValueError( diff --git a/src/ucp_sdk/models/schemas/shopping/types/signals_create_request.py b/src/ucp_sdk/models/schemas/common/types/signals_create_request.py similarity index 95% rename from src/ucp_sdk/models/schemas/shopping/types/signals_create_request.py rename to src/ucp_sdk/models/schemas/common/types/signals_create_request.py index df0b091..6857861 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/signals_create_request.py +++ b/src/ucp_sdk/models/schemas/common/types/signals_create_request.py @@ -44,7 +44,7 @@ class SignalsCreateRequest(BaseModel): def _enforce_property_names(self): """JSON Schema propertyNames: every extra key must match the declared reverse-domain pattern (schema propertyNames).""" - pattern = "^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$" + pattern = "^[a-z](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9_])?)+$" for key in self.model_extra or {}: if re.fullmatch(pattern, key) is None: raise ValueError( diff --git a/src/ucp_sdk/models/schemas/shopping/types/signals_update_request.py b/src/ucp_sdk/models/schemas/common/types/signals_update_request.py similarity index 95% rename from src/ucp_sdk/models/schemas/shopping/types/signals_update_request.py rename to src/ucp_sdk/models/schemas/common/types/signals_update_request.py index 37d37a8..6d6a714 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/signals_update_request.py +++ b/src/ucp_sdk/models/schemas/common/types/signals_update_request.py @@ -44,7 +44,7 @@ class SignalsUpdateRequest(BaseModel): def _enforce_property_names(self): """JSON Schema propertyNames: every extra key must match the declared reverse-domain pattern (schema propertyNames).""" - pattern = "^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$" + pattern = "^[a-z](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9_])?)+$" for key in self.model_extra or {}: if re.fullmatch(pattern, key) is None: raise ValueError( diff --git a/src/ucp_sdk/models/schemas/shopping/types/signed_amount.py b/src/ucp_sdk/models/schemas/common/types/signed_amount.py similarity index 84% rename from src/ucp_sdk/models/schemas/shopping/types/signed_amount.py rename to src/ucp_sdk/models/schemas/common/types/signed_amount.py index 481b1c2..95a93cd 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/signed_amount.py +++ b/src/ucp_sdk/models/schemas/common/types/signed_amount.py @@ -24,7 +24,16 @@ from typing_extensions import TypeAliasType SignedAmount = TypeAliasType( - "SignedAmount", Annotated[int, Field(..., title="Signed Amount")] + "SignedAmount", + Annotated[ + int, + Field( + ..., + ge=-9007199254740991, + le=9007199254740991, + title="Signed Amount", + ), + ], ) """ Monetary amount in the currency's minor unit as defined by ISO 4217. Refer to the currency's exponent to determine minor-to-major ratio (e.g., 2 for USD, 0 for JPY, 3 for KWD). May be negative — the sign is intrinsic to the value (e.g., discounts are negative, charges are positive). diff --git a/src/ucp_sdk/models/schemas/shopping/types/signed_amount_create_request.py b/src/ucp_sdk/models/schemas/common/types/signed_amount_create_request.py similarity index 85% rename from src/ucp_sdk/models/schemas/shopping/types/signed_amount_create_request.py rename to src/ucp_sdk/models/schemas/common/types/signed_amount_create_request.py index 436d0f2..baec495 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/signed_amount_create_request.py +++ b/src/ucp_sdk/models/schemas/common/types/signed_amount_create_request.py @@ -25,7 +25,15 @@ SignedAmountCreateRequest = TypeAliasType( "SignedAmountCreateRequest", - Annotated[int, Field(..., title="Signed Amount Create Request")], + Annotated[ + int, + Field( + ..., + ge=-9007199254740991, + le=9007199254740991, + title="Signed Amount Create Request", + ), + ], ) """ Monetary amount in the currency's minor unit as defined by ISO 4217. Refer to the currency's exponent to determine minor-to-major ratio (e.g., 2 for USD, 0 for JPY, 3 for KWD). May be negative — the sign is intrinsic to the value (e.g., discounts are negative, charges are positive). diff --git a/src/ucp_sdk/models/schemas/shopping/types/signed_amount_update_request.py b/src/ucp_sdk/models/schemas/common/types/signed_amount_update_request.py similarity index 85% rename from src/ucp_sdk/models/schemas/shopping/types/signed_amount_update_request.py rename to src/ucp_sdk/models/schemas/common/types/signed_amount_update_request.py index 985bd10..3e09efe 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/signed_amount_update_request.py +++ b/src/ucp_sdk/models/schemas/common/types/signed_amount_update_request.py @@ -25,7 +25,15 @@ SignedAmountUpdateRequest = TypeAliasType( "SignedAmountUpdateRequest", - Annotated[int, Field(..., title="Signed Amount Update Request")], + Annotated[ + int, + Field( + ..., + ge=-9007199254740991, + le=9007199254740991, + title="Signed Amount Update Request", + ), + ], ) """ Monetary amount in the currency's minor unit as defined by ISO 4217. Refer to the currency's exponent to determine minor-to-major ratio (e.g., 2 for USD, 0 for JPY, 3 for KWD). May be negative — the sign is intrinsic to the value (e.g., discounts are negative, charges are positive). diff --git a/src/ucp_sdk/models/schemas/shopping/types/total.py b/src/ucp_sdk/models/schemas/common/types/total.py similarity index 100% rename from src/ucp_sdk/models/schemas/shopping/types/total.py rename to src/ucp_sdk/models/schemas/common/types/total.py diff --git a/src/ucp_sdk/models/schemas/shopping/types/total_create_request.py b/src/ucp_sdk/models/schemas/common/types/total_create_request.py similarity index 100% rename from src/ucp_sdk/models/schemas/shopping/types/total_create_request.py rename to src/ucp_sdk/models/schemas/common/types/total_create_request.py diff --git a/src/ucp_sdk/models/schemas/shopping/types/total_update_request.py b/src/ucp_sdk/models/schemas/common/types/total_update_request.py similarity index 100% rename from src/ucp_sdk/models/schemas/shopping/types/total_update_request.py rename to src/ucp_sdk/models/schemas/common/types/total_update_request.py diff --git a/src/ucp_sdk/models/schemas/shopping/types/totals.py b/src/ucp_sdk/models/schemas/common/types/totals.py similarity index 100% rename from src/ucp_sdk/models/schemas/shopping/types/totals.py rename to src/ucp_sdk/models/schemas/common/types/totals.py diff --git a/src/ucp_sdk/models/schemas/shopping/types/totals_create_request.py b/src/ucp_sdk/models/schemas/common/types/totals_create_request.py similarity index 100% rename from src/ucp_sdk/models/schemas/shopping/types/totals_create_request.py rename to src/ucp_sdk/models/schemas/common/types/totals_create_request.py diff --git a/src/ucp_sdk/models/schemas/shopping/types/totals_update_request.py b/src/ucp_sdk/models/schemas/common/types/totals_update_request.py similarity index 100% rename from src/ucp_sdk/models/schemas/shopping/types/totals_update_request.py rename to src/ucp_sdk/models/schemas/common/types/totals_update_request.py diff --git a/src/ucp_sdk/models/schemas/common/types/unit.py b/src/ucp_sdk/models/schemas/common/types/unit.py new file mode 100644 index 0000000..bddaa3b --- /dev/null +++ b/src/ucp_sdk/models/schemas/common/types/unit.py @@ -0,0 +1,43 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from pydantic import BaseModel, ConfigDict, Field + + +class Unit(BaseModel): + """ + A reusable unit descriptor for quantities and measures. Its unit-descriptor machine identity is (`unit`, effective `scale`), where effective `scale` is the provided `scale` or 0; `display_text` is excluded. + """ + + model_config = ConfigDict( + extra="allow", + ) + unit: str + """ + Stable machine identifier. The Business SHOULD use the exact UN/CEFACT Rec20 Common Code when one accurately identifies the unit. Otherwise, the Business MAY use a custom unit identifier and MUST use it consistently for the same unit. The Platform MUST treat an unrecognized identifier as opaque. + """ + scale: int | None = Field(0, ge=0, le=15) + """ + One step equals `10^-scale` of `unit`. When `unit` is `C62`, `scale`, if present, MUST be 0. The maximum of 15 is derived from the interoperable integer range: at scale 16 a single whole unit (10^16 steps) is no longer representable, so larger scales cannot denominate one unit of their own basis. Businesses needing finer granularity use a smaller unit. + """ + display_text: str + """ + Required printable unit label provided by the Business. The Platform MUST use it when it does not recognize `unit`; for a recognized UN/CEFACT Rec 20 Common Code, the Platform MAY substitute its own localized label. It does not participate in unit identity or mismatch comparison. + """ diff --git a/src/ucp_sdk/models/schemas/common/types/unit_create_request.py b/src/ucp_sdk/models/schemas/common/types/unit_create_request.py new file mode 100644 index 0000000..2fd5282 --- /dev/null +++ b/src/ucp_sdk/models/schemas/common/types/unit_create_request.py @@ -0,0 +1,43 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from pydantic import BaseModel, ConfigDict, Field + + +class UnitCreateRequest(BaseModel): + """ + A reusable unit descriptor for quantities and measures. Its unit-descriptor machine identity is (`unit`, effective `scale`), where effective `scale` is the provided `scale` or 0; `display_text` is excluded. + """ + + model_config = ConfigDict( + extra="allow", + ) + unit: str + """ + Stable machine identifier. The Business SHOULD use the exact UN/CEFACT Rec20 Common Code when one accurately identifies the unit. Otherwise, the Business MAY use a custom unit identifier and MUST use it consistently for the same unit. The Platform MUST treat an unrecognized identifier as opaque. + """ + scale: int | None = Field(0, ge=0, le=15) + """ + One step equals `10^-scale` of `unit`. When `unit` is `C62`, `scale`, if present, MUST be 0. The maximum of 15 is derived from the interoperable integer range: at scale 16 a single whole unit (10^16 steps) is no longer representable, so larger scales cannot denominate one unit of their own basis. Businesses needing finer granularity use a smaller unit. + """ + display_text: str + """ + Required printable unit label provided by the Business. The Platform MUST use it when it does not recognize `unit`; for a recognized UN/CEFACT Rec 20 Common Code, the Platform MAY substitute its own localized label. It does not participate in unit identity or mismatch comparison. + """ diff --git a/src/ucp_sdk/models/schemas/common/types/unit_update_request.py b/src/ucp_sdk/models/schemas/common/types/unit_update_request.py new file mode 100644 index 0000000..a38f7d5 --- /dev/null +++ b/src/ucp_sdk/models/schemas/common/types/unit_update_request.py @@ -0,0 +1,43 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from pydantic import BaseModel, ConfigDict, Field + + +class UnitUpdateRequest(BaseModel): + """ + A reusable unit descriptor for quantities and measures. Its unit-descriptor machine identity is (`unit`, effective `scale`), where effective `scale` is the provided `scale` or 0; `display_text` is excluded. + """ + + model_config = ConfigDict( + extra="allow", + ) + unit: str + """ + Stable machine identifier. The Business SHOULD use the exact UN/CEFACT Rec20 Common Code when one accurately identifies the unit. Otherwise, the Business MAY use a custom unit identifier and MUST use it consistently for the same unit. The Platform MUST treat an unrecognized identifier as opaque. + """ + scale: int | None = Field(0, ge=0, le=15) + """ + One step equals `10^-scale` of `unit`. When `unit` is `C62`, `scale`, if present, MUST be 0. The maximum of 15 is derived from the interoperable integer range: at scale 16 a single whole unit (10^16 steps) is no longer representable, so larger scales cannot denominate one unit of their own basis. Businesses needing finer granularity use a smaller unit. + """ + display_text: str + """ + Required printable unit label provided by the Business. The Platform MUST use it when it does not recognize `unit`; for a recognized UN/CEFACT Rec 20 Common Code, the Platform MAY substitute its own localized label. It does not participate in unit identity or mismatch comparison. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/warning_code.py b/src/ucp_sdk/models/schemas/common/types/warning_code.py similarity index 88% rename from src/ucp_sdk/models/schemas/shopping/types/warning_code.py rename to src/ucp_sdk/models/schemas/common/types/warning_code.py index 753a9ca..e14ff58 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/warning_code.py +++ b/src/ucp_sdk/models/schemas/common/types/warning_code.py @@ -33,6 +33,7 @@ "final_sale", "prop65", "fulfillment_changed", + "payment_term_changed", "age_restricted", ], title="Warning Code", @@ -40,5 +41,5 @@ ], ) """ -Warning code identifying the type of warning. Standard codes are defined in capability specs (see examples), and have standardized semantics; freeform codes are permitted. +Warning code identifying the type of warning. Standard codes are defined in capability specifications (see examples) and have standardized semantics; freeform codes are permitted. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/warning_code_create_request.py b/src/ucp_sdk/models/schemas/common/types/warning_code_create_request.py similarity index 88% rename from src/ucp_sdk/models/schemas/shopping/types/warning_code_create_request.py rename to src/ucp_sdk/models/schemas/common/types/warning_code_create_request.py index e6dd78d..27d72d9 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/warning_code_create_request.py +++ b/src/ucp_sdk/models/schemas/common/types/warning_code_create_request.py @@ -33,6 +33,7 @@ "final_sale", "prop65", "fulfillment_changed", + "payment_term_changed", "age_restricted", ], title="Warning Code Create Request", @@ -40,5 +41,5 @@ ], ) """ -Warning code identifying the type of warning. Standard codes are defined in capability specs (see examples), and have standardized semantics; freeform codes are permitted. +Warning code identifying the type of warning. Standard codes are defined in capability specifications (see examples) and have standardized semantics; freeform codes are permitted. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/warning_code_update_request.py b/src/ucp_sdk/models/schemas/common/types/warning_code_update_request.py similarity index 88% rename from src/ucp_sdk/models/schemas/shopping/types/warning_code_update_request.py rename to src/ucp_sdk/models/schemas/common/types/warning_code_update_request.py index 0ef6133..e9cb732 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/warning_code_update_request.py +++ b/src/ucp_sdk/models/schemas/common/types/warning_code_update_request.py @@ -33,6 +33,7 @@ "final_sale", "prop65", "fulfillment_changed", + "payment_term_changed", "age_restricted", ], title="Warning Code Update Request", @@ -40,5 +41,5 @@ ], ) """ -Warning code identifying the type of warning. Standard codes are defined in capability specs (see examples), and have standardized semantics; freeform codes are permitted. +Warning code identifying the type of warning. Standard codes are defined in capability specifications (see examples) and have standardized semantics; freeform codes are permitted. """ diff --git a/src/ucp_sdk/models/schemas/profile.py b/src/ucp_sdk/models/schemas/profile.py new file mode 100644 index 0000000..500c36d --- /dev/null +++ b/src/ucp_sdk/models/schemas/profile.py @@ -0,0 +1,127 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from pydantic import BaseModel, ConfigDict, Field + +from . import ucp as ucp_1 + + +class JwkPublicKey(BaseModel): + """ + Public JSON Web Key used for HTTP Message Signatures and signed webhook verification. UCP profiles publish public keys only; private key material MUST NOT appear in a profile. Well-known key types: EC (ECDSA P-256, P-384) and OKP (EdDSA Ed25519); OKP keys are RECOMMENDED for signers opting into Web Bot Auth (WBA) interop on HTTP transport. A single profile MAY publish keys of either or both types; consumers select keys by kid. The kty, crv, and alg vocabularies are OPEN: verifiers MUST tolerate key types, curves, and algorithms they do not recognize, selecting keys by kid at verification time. An unsupported key affects only the signature that references it (algorithm_unsupported) and MUST NOT cause whole-profile rejection. Additional public JWK members are permitted; consumers ignore unknown members. + """ + + model_config = ConfigDict( + extra="allow", + ) + kid: str + """ + Key identifier referenced by Signature-Input keyid. For keys used in dual-audience (Web Bot Auth) signatures, the kid MUST be the key's JWK SHA-256 Thumbprint (RFC 7638) so UCP-Agent and Signature-Agent lookups resolve the same key; otherwise the kid MAY be any stable string. + """ + kty: str = Field(..., examples=["EC", "OKP"]) + """ + JWK key type. Well-known values: EC for ECDSA (P-256, P-384); OKP for EdDSA (Ed25519). Open vocabulary; verifiers tolerate unrecognized types and select keys by kid. + """ + crv: str | None = Field(None, examples=["P-256", "P-384", "Ed25519"]) + """ + Curve name. Well-known values: P-256, P-384 (EC); Ed25519 (OKP). Open vocabulary. + """ + x: str | None = None + """ + Public key value, base64url-encoded. For EC, the x coordinate (RFC 7518 §6.2); for OKP, the public key (RFC 8037 §2). + """ + y: str | None = None + """ + EC public key y coordinate, base64url-encoded (RFC 7518 §6.2). Not used by OKP keys. + """ + alg: str | None = Field(None, examples=["ES256", "ES384", "EdDSA"]) + """ + JWA algorithm associated with this public key. Optional; verifiers derive the algorithm from crv when alg is omitted. When present for a well-known curve it MUST match: ES256 with P-256, ES384 with P-384, EdDSA with Ed25519. + """ + use: str | None = None + """ + JWK public key use. UCP examples use sig for signatures. + """ + + +class UcpProfileDocument(BaseModel): + """ + Variant-neutral wrapper schema for UCP profile documents. Use the business_schema definition to validate business profiles and the platform_schema definition to validate platform profiles. + """ + + model_config = ConfigDict( + extra="allow", + ) + ucp: ucp_1.Base + """ + Protocol metadata, capabilities, services, and payment handlers advertised by this party. + """ + keys: list[JwkPublicKey] | None = None + """ + Canonical UCP profile field for publishing signing keys, as a JWK Set per RFC 7517. When a profile publishes signing keys, they MUST appear here; this is where every UCP verifier reads them. Publishing keys[] makes the UCP profile a valid JWK Set that a signer can reuse as its Web Bot Auth key source: a WBA-shape verifier resolving via Signature-Agent type=jwks_uri pointed at this profile reads these keys, and the cimd and directory variants reach them through their own documents. See the Deployment Patterns for WBA Interop section in the overview for hosting patterns. + """ + + +class Base(BaseModel): + """ + Common wrapper for UCP profile documents. + """ + + model_config = ConfigDict( + extra="allow", + ) + ucp: ucp_1.Base + """ + Protocol metadata, capabilities, services, and payment handlers advertised by this party. + """ + keys: list[JwkPublicKey] | None = None + """ + Canonical UCP profile field for publishing signing keys, as a JWK Set per RFC 7517. When a profile publishes signing keys, they MUST appear here; this is where every UCP verifier reads them. Publishing keys[] makes the UCP profile a valid JWK Set that a signer can reuse as its Web Bot Auth key source: a WBA-shape verifier resolving via Signature-Agent type=jwks_uri pointed at this profile reads these keys, and the cimd and directory variants reach them through their own documents. See the Deployment Patterns for WBA Interop section in the overview for hosting patterns. + """ + + +class BusinessSchema(BaseModel): + """ + Profile document hosted by a business at /.well-known/ucp. + """ + + model_config = ConfigDict( + extra="allow", + ) + ucp: ucp_1.BusinessSchema + keys: list[JwkPublicKey] | None = None + """ + Canonical UCP profile field for publishing signing keys, as a JWK Set per RFC 7517. When a profile publishes signing keys, they MUST appear here; this is where every UCP verifier reads them. Publishing keys[] makes the UCP profile a valid JWK Set that a signer can reuse as its Web Bot Auth key source: a WBA-shape verifier resolving via Signature-Agent type=jwks_uri pointed at this profile reads these keys, and the cimd and directory variants reach them through their own documents. See the Deployment Patterns for WBA Interop section in the overview for hosting patterns. + """ + + +class PlatformSchema(BaseModel): + """ + Profile document hosted by a platform and advertised to businesses via UCP-Agent. + """ + + model_config = ConfigDict( + extra="allow", + ) + ucp: ucp_1.PlatformSchema + keys: list[JwkPublicKey] | None = None + """ + Canonical UCP profile field for publishing signing keys, as a JWK Set per RFC 7517. When a profile publishes signing keys, they MUST appear here; this is where every UCP verifier reads them. Publishing keys[] makes the UCP profile a valid JWK Set that a signer can reuse as its Web Bot Auth key source: a WBA-shape verifier resolving via Signature-Agent type=jwks_uri pointed at this profile reads these keys, and the cimd and directory variants reach them through their own documents. See the Deployment Patterns for WBA Interop section in the overview for hosting patterns. + """ diff --git a/src/ucp_sdk/models/schemas/service.py b/src/ucp_sdk/models/schemas/service.py index cf33914..c7638e0 100644 --- a/src/ucp_sdk/models/schemas/service.py +++ b/src/ucp_sdk/models/schemas/service.py @@ -27,7 +27,7 @@ "UcpService", Annotated[Any, Field(..., title="UCP Service")] ) """ -Service binding for a specific transport. Each transport binding is a separate entry in the service array. +Service declaration with one transport binding. Each transport binding is a separate entry in the service array; `version` identifies the service, not the transport. """ @@ -103,7 +103,7 @@ class PlatformSchema(BaseModel): """ -class PlatformSchema7(BaseModel): +class PlatformSchema8(BaseModel): """ Full service declaration for platform-level discovery. All transports require `version`, `spec`, and `transport`. REST, MCP, and embedded additionally require `schema`. """ @@ -141,7 +141,7 @@ class PlatformSchema7(BaseModel): """ -class PlatformSchema8(BaseModel): +class PlatformSchema9(BaseModel): """ Full service declaration for platform-level discovery. All transports require `version`, `spec`, and `transport`. REST, MCP, and embedded additionally require `schema`. """ @@ -179,7 +179,7 @@ class PlatformSchema8(BaseModel): """ -class PlatformSchema9(BaseModel): +class PlatformSchema10(BaseModel): """ Full service declaration for platform-level discovery. All transports require `version`, `spec`, and `transport`. REST, MCP, and embedded additionally require `schema`. """ @@ -217,10 +217,10 @@ class PlatformSchema9(BaseModel): """ -PlatformSchema5 = TypeAliasType( - "PlatformSchema5", +PlatformSchema6 = TypeAliasType( + "PlatformSchema6", Annotated[ - PlatformSchema | PlatformSchema7 | PlatformSchema8 | PlatformSchema9, + PlatformSchema | PlatformSchema8 | PlatformSchema9 | PlatformSchema10, Field(..., title="Service (Platform Schema)"), ], ) @@ -267,7 +267,7 @@ class BusinessSchema(BaseModel): """ -class BusinessSchema4(BaseModel): +class BusinessSchema5(BaseModel): """ Service binding for business/merchant configuration. May override platform endpoints. """ @@ -305,7 +305,7 @@ class BusinessSchema4(BaseModel): """ -class BusinessSchema5(BaseModel): +class BusinessSchema6(BaseModel): """ Service binding for business/merchant configuration. May override platform endpoints. """ @@ -361,7 +361,7 @@ class Config(BaseModel): """ -class BusinessSchema6(BaseModel): +class BusinessSchema7(BaseModel): """ Service binding for business/merchant configuration. May override platform endpoints. """ @@ -399,10 +399,10 @@ class BusinessSchema6(BaseModel): """ -BusinessSchema2 = TypeAliasType( - "BusinessSchema2", +BusinessSchema3 = TypeAliasType( + "BusinessSchema3", Annotated[ - BusinessSchema | BusinessSchema4 | BusinessSchema5 | BusinessSchema6, + BusinessSchema | BusinessSchema5 | BusinessSchema6 | BusinessSchema7, Field(..., title="Service (Business Schema)"), ], ) diff --git a/src/ucp_sdk/models/schemas/shopping/__init__.py b/src/ucp_sdk/models/schemas/shopping/__init__.py index 1252d6b..421dc21 100644 --- a/src/ucp_sdk/models/schemas/shopping/__init__.py +++ b/src/ucp_sdk/models/schemas/shopping/__init__.py @@ -15,3 +15,4 @@ # generated by datamodel-codegen # pylint: disable=all # pyformat: disable + diff --git a/src/ucp_sdk/models/schemas/shopping/buyer_consent.py b/src/ucp_sdk/models/schemas/shopping/buyer_consent.py index 830a810..dbcb931 100644 --- a/src/ucp_sdk/models/schemas/shopping/buyer_consent.py +++ b/src/ucp_sdk/models/schemas/shopping/buyer_consent.py @@ -18,11 +18,13 @@ from __future__ import annotations -from typing import Annotated, Any +from typing import Annotated, Any, Literal from pydantic import BaseModel, ConfigDict, Field from typing_extensions import TypeAliasType +from ..common.types import link, reverse_domain_name +from .cart import Cart as Cart_1 from .checkout import Checkout as Checkout_1 from .types.buyer import Buyer as Buyer_1 @@ -31,39 +33,79 @@ Annotated[Any, Field(..., title="Buyer Consent Extension")], ) """ -Extends Checkout with buyer consent tracking for privacy compliance via the buyer object. +Extends the buyer object with per-purpose consent. Each purpose is keyed by a reverse-DNS identifier and carries the current `granted` state, the `source` of that state (business default or platform-captured buyer decision), a `description`, optional `links`, and optional `segments` for finer-grained channel, vendor, or program decisions scoped to that purpose. """ -class Consent(BaseModel): +class ConsentSegment(BaseModel): """ - User consent states for data processing + A buyer's consent decision for a specific refinement of a parent purpose (e.g., email marketing under the marketing purpose). Overrides the parent's `granted` value for this scope. Segments do not nest further. """ model_config = ConfigDict( extra="allow", ) - analytics: bool | None = None + granted: bool """ - Consent for analytics and performance tracking. + Whether consent has been granted for this segment. Overrides the parent purpose's `granted` value for this specific scope. """ - preferences: bool | None = None + source: Literal["business", "platform"] """ - Consent for storing user preferences. + Identifies the party that asserted the current `granted` value for this segment. `business` means the value reflects the business's default policy; `platform` means the value reflects an explicit buyer decision captured by the platform. """ - marketing: bool | None = None + description: str """ - Consent for marketing communications. + Human-readable description of what the buyer is consenting to within this segment (e.g., 'Promotional emails and exclusive offers'). """ - sale_of_data: bool | None = None + links: list[link.Link] | None = None """ - Consent for selling data to third parties (CCPA). + Optional segment-specific links (e.g., channel terms or privacy disclosures). """ +class ConsentPurpose(BaseModel): + """ + A buyer's consent decision for a purpose (e.g., marketing, analytics). Carries the current binary state, its source (business default or platform-captured buyer decision), human-readable context, and optional refinements scoping the decision to specific channels, vendors, or programs. + """ + + model_config = ConfigDict( + extra="allow", + ) + granted: bool + """ + Whether consent has been granted for this purpose. The `source` field identifies who asserted this state (business default or platform-captured buyer preference). + """ + source: Literal["business", "platform"] + """ + Identifies the party that asserted the current `granted` value. `business` means the value reflects the business's default policy; `platform` means the value reflects an explicit buyer decision captured by the platform. + """ + description: str + """ + Human-readable description of what the buyer is consenting to (e.g., 'Promotional communications across all channels'). + """ + links: list[link.Link] | None = None + """ + Optional links providing context (e.g., privacy policy, terms). + """ + segments: ( + dict[reverse_domain_name.ReverseDomainName, ConsentSegment] | None + ) = None + """ + Optional refinements scoping this purpose to specific channels, vendors, or programs. Keys are reverse-DNS identifiers. UCP currently defines two well-known segment identifiers under `dev.ucp.consent.marketing`: `dev.ucp.consent.marketing.email`, `dev.ucp.consent.marketing.sms`. Other segments follow vendor or merchant reverse-DNS conventions. + """ + + +Consent = TypeAliasType( + "Consent", dict[reverse_domain_name.ReverseDomainName, ConsentPurpose] +) +""" +Per-purpose consent. Keys are reverse-DNS purpose identifiers. UCP defines four well-known purposes: `dev.ucp.consent.marketing`, `dev.ucp.consent.analytics`, `dev.ucp.consent.preferences`, `dev.ucp.consent.sale_or_sharing`. Vendors and merchants may define additional purposes under their own reverse-DNS namespace. +""" + + class Buyer(Buyer_1): """ - Buyer object extended with consent tracking. + Buyer object extended with per-purpose consent. """ model_config = ConfigDict( @@ -71,13 +113,27 @@ class Buyer(Buyer_1): ) consent: Consent | None = None """ - Consent tracking fields. + Per-purpose consent decisions and business-advertised consent options. + """ + + +class Cart(Cart_1): + """ + Cart extended with buyer consent. + """ + + model_config = ConfigDict( + extra="allow", + ) + buyer: Buyer | None = None + """ + Buyer with consent tracking. """ class Checkout(Checkout_1): """ - Checkout extended with consent tracking via buyer object. + Checkout extended with buyer consent. """ model_config = ConfigDict( diff --git a/src/ucp_sdk/models/schemas/shopping/cart.py b/src/ucp_sdk/models/schemas/shopping/cart.py index 97caa5c..96b14aa 100644 --- a/src/ucp_sdk/models/schemas/shopping/cart.py +++ b/src/ucp_sdk/models/schemas/shopping/cart.py @@ -21,13 +21,15 @@ from pydantic import AnyUrl, AwareDatetime, BaseModel, ConfigDict from .. import ucp as ucp_1 +from ..common.types import actions as actions_1 +from ..common.types import context as context_1 +from ..common.types import link, message, policy +from ..common.types import signals as signals_1 +from ..common.types import totals as totals_1 from .checkout import Checkout as Checkout_1 from .types import attribution as attribution_1 from .types import buyer as buyer_1 -from .types import context as context_1 -from .types import line_item, link, message -from .types import signals as signals_1 -from .types import totals as totals_1 +from .types import line_item class Cart(BaseModel): @@ -65,6 +67,10 @@ class Cart(BaseModel): """ Estimated cost breakdown. May be partial if shipping/tax not yet calculable. """ + actions: actions_1.Actions | None = None + """ + Outstanding extension-defined Actions for this cart. + """ messages: list[message.Message] | None = None """ Validation messages, warnings, or informational notices. @@ -73,6 +79,10 @@ class Cart(BaseModel): """ Optional merchant links (policies, FAQs). """ + policies: list[policy.Policy] | None = None + """ + Policies (e.g., return/refund terms) that apply to the items in this cart. `applies_to` targets are relative to the response root; when absent or empty, refer to the URLs in `links[]`. + """ continue_url: AnyUrl | None = None """ URL for cart handoff and session recovery. Enables sharing and human-in-the-loop flows. diff --git a/src/ucp_sdk/models/schemas/shopping/cart_create_request.py b/src/ucp_sdk/models/schemas/shopping/cart_create_request.py index d7a93f6..42788fa 100644 --- a/src/ucp_sdk/models/schemas/shopping/cart_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/cart_create_request.py @@ -20,13 +20,12 @@ from pydantic import BaseModel, ConfigDict +from ..common.types import context_create_request, signals_create_request from .checkout_create_request import CheckoutCreateRequest from .types import ( attribution_create_request, buyer_create_request, - context_create_request, line_item_create_request, - signals_create_request, ) diff --git a/src/ucp_sdk/models/schemas/shopping/cart_update_request.py b/src/ucp_sdk/models/schemas/shopping/cart_update_request.py index 7c523ac..83c6418 100644 --- a/src/ucp_sdk/models/schemas/shopping/cart_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/cart_update_request.py @@ -20,13 +20,12 @@ from pydantic import BaseModel, ConfigDict +from ..common.types import context_update_request, signals_update_request from .checkout_update_request import CheckoutUpdateRequest from .types import ( attribution_update_request, buyer_update_request, - context_update_request, line_item_update_request, - signals_update_request, ) @@ -38,10 +37,6 @@ class CartUpdateRequest(BaseModel): model_config = ConfigDict( extra="allow", ) - id: str - """ - Unique cart identifier. - """ line_items: list[line_item_update_request.LineItemUpdateRequest] """ Cart line items. Same structure as checkout. Full replacement on update. diff --git a/src/ucp_sdk/models/schemas/shopping/catalog_lookup.py b/src/ucp_sdk/models/schemas/shopping/catalog_lookup.py index fed3d93..a6f02fc 100644 --- a/src/ucp_sdk/models/schemas/shopping/catalog_lookup.py +++ b/src/ucp_sdk/models/schemas/shopping/catalog_lookup.py @@ -21,16 +21,17 @@ from pydantic import BaseModel, ConfigDict, Field from .. import ucp as ucp_1 +from ..common.types import actions as actions_1 +from ..common.types import context as context_1 +from ..common.types import message, policy +from ..common.types import signals as signals_1 from .types import attribution as attribution_1 -from .types import context as context_1 from .types import ( detail_option_value, input_correlation, - message, search_filters, selected_option, ) -from .types import signals as signals_1 from .types.product import Product as Product_1 from .types.variant import Variant @@ -80,13 +81,6 @@ class LookupRequest(BaseModel): attribution: attribution_1.Attribution | None = None -class Product(Product_1): - model_config = ConfigDict( - extra="allow", - ) - variants: list[LookupVariant] | None = None - - class GetProductRequest(BaseModel): """ Request body for single-product retrieval. Supports interactive variant narrowing via selected and preferences. @@ -126,22 +120,11 @@ class Option(BaseModel): ) -class DetailProduct(Product_1): - """ - A product in a get_product response, extended with effective selections and availability signals on option values. - """ - +class Product(Product_1): model_config = ConfigDict( extra="allow", ) - selected: list[selected_option.SelectedOption] | None = None - """ - Effective option selections that anchor the featured variant and availability signals. Required when the product has configurable options; may be empty or omitted for products with no option axes. - """ - options: list[Option] | None = None - """ - Product options with availability signals relative to the effective selections. - """ + variants: list[LookupVariant] | None = None class LookupResponse(BaseModel): @@ -153,10 +136,36 @@ class LookupResponse(BaseModel): """ Products matching the requested identifiers. May contain fewer items if some identifiers not found, or more if identifiers match multiple products. """ + actions: actions_1.Actions | None = None + """ + Outstanding extension-defined Actions for this catalog lookup response. + """ messages: list[message.Message] | None = None """ Errors, warnings, or informational messages about the requested items. """ + policies: list[policy.Policy] | None = None + """ + Policies (e.g., return/refund terms) that apply to the products in this response. `applies_to` targets are relative to the response root; when absent or empty, refer to the URLs in `links[]`. + """ + + +class DetailProduct(Product_1): + """ + A product in a get_product response, extended with effective selections and availability signals on option values. + """ + + model_config = ConfigDict( + extra="allow", + ) + selected: list[selected_option.SelectedOption] | None = None + """ + Effective option selections that anchor the featured variant and availability signals. Required when the product has configurable options; may be empty or omitted for products with no option axes. + """ + options: list[Option] | None = None + """ + Product options with availability signals relative to the effective selections. + """ class GetProductResponse(BaseModel): @@ -168,7 +177,15 @@ class GetProductResponse(BaseModel): """ The requested product with full detail. Singular — this is a single-resource operation. """ + actions: actions_1.Actions | None = None + """ + Outstanding extension-defined Actions for this product response. + """ messages: list[message.Message] | None = None """ Warnings or informational messages about the product (e.g., price recently changed, limited availability). """ + policies: list[policy.Policy] | None = None + """ + Policies (e.g., return/refund terms) that apply to this product. `applies_to` targets are relative to the response root; when absent or empty, refer to the URLs in `links[]`. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/catalog_search.py b/src/ucp_sdk/models/schemas/shopping/catalog_search.py index d405d19..6fef5d6 100644 --- a/src/ucp_sdk/models/schemas/shopping/catalog_search.py +++ b/src/ucp_sdk/models/schemas/shopping/catalog_search.py @@ -21,12 +21,14 @@ from pydantic import BaseModel, ConfigDict from .. import ucp as ucp_1 +from ..common.types import actions as actions_1 +from ..common.types import context as context_1 +from ..common.types import message +from ..common.types import pagination as pagination_1 +from ..common.types import policy +from ..common.types import signals as signals_1 from .types import attribution as attribution_1 -from .types import context as context_1 -from .types import message -from .types import pagination as pagination_1 from .types import product, search_filters -from .types import signals as signals_1 class CatalogSearch(BaseModel): @@ -64,7 +66,15 @@ class SearchResponse(BaseModel): Products matching the search criteria. """ pagination: pagination_1.Response | None = None + actions: actions_1.Actions | None = None + """ + Outstanding extension-defined Actions for this catalog search response. + """ messages: list[message.Message] | None = None """ Errors, warnings, or informational messages about the search results. """ + policies: list[policy.Policy] | None = None + """ + Policies (e.g., return/refund terms) that apply to the products in these search results. `applies_to` targets are relative to the response root; when absent or empty, refer to the URLs in `links[]`. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/checkout.py b/src/ucp_sdk/models/schemas/shopping/checkout.py index 5a4259f..768f2d4 100644 --- a/src/ucp_sdk/models/schemas/shopping/checkout.py +++ b/src/ucp_sdk/models/schemas/shopping/checkout.py @@ -23,13 +23,15 @@ from pydantic import AnyUrl, AwareDatetime, BaseModel, ConfigDict from .. import ucp as ucp_1 +from ..common.types import actions as actions_1 +from ..common.types import context as context_1 +from ..common.types import link, message, policy +from ..common.types import signals as signals_1 +from ..common.types import totals as totals_1 from . import payment as payment_1 from .types import attribution as attribution_1 from .types import buyer as buyer_1 -from .types import context as context_1 -from .types import line_item, link, message, order_confirmation -from .types import signals as signals_1 -from .types import totals as totals_1 +from .types import line_item, order_confirmation class Checkout(BaseModel): @@ -65,7 +67,7 @@ class Checkout(BaseModel): "canceled", ] """ - Checkout state indicating the current phase and required action. See Checkout Status lifecycle documentation for state transition details. + Checkout state indicating the current phase and required processing. See Checkout Status lifecycle documentation for state transition details. """ currency: str """ @@ -75,6 +77,10 @@ class Checkout(BaseModel): """ Different cart totals. """ + actions: actions_1.Actions | None = None + """ + Outstanding extension-defined Actions for this checkout. + """ messages: list[message.Message] | None = None """ List of messages with error and info about the checkout session state. @@ -83,6 +89,10 @@ class Checkout(BaseModel): """ Links to be displayed by the platform (Privacy Policy, TOS). Mandatory for legal compliance. """ + policies: list[policy.Policy] | None = None + """ + Policies (e.g., return/refund terms) that apply to the items in this checkout. `applies_to` targets are relative to the response root; when absent or empty, refer to the URLs in `links[]`. + """ expires_at: AwareDatetime | None = None """ RFC 3339 expiry timestamp. Default TTL is 6 hours from creation if not sent. diff --git a/src/ucp_sdk/models/schemas/shopping/checkout_complete_request.py b/src/ucp_sdk/models/schemas/shopping/checkout_complete_request.py index 31a56c6..bcfd2af 100644 --- a/src/ucp_sdk/models/schemas/shopping/checkout_complete_request.py +++ b/src/ucp_sdk/models/schemas/shopping/checkout_complete_request.py @@ -20,8 +20,9 @@ from pydantic import BaseModel, ConfigDict +from ..common.types import signals_complete_request from . import payment_complete_request -from .types import attribution_complete_request, signals_complete_request +from .types import attribution_complete_request class CheckoutCompleteRequest(BaseModel): diff --git a/src/ucp_sdk/models/schemas/shopping/checkout_create_request.py b/src/ucp_sdk/models/schemas/shopping/checkout_create_request.py index eaea128..5d18403 100644 --- a/src/ucp_sdk/models/schemas/shopping/checkout_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/checkout_create_request.py @@ -20,13 +20,12 @@ from pydantic import BaseModel, ConfigDict +from ..common.types import context_create_request, signals_create_request from . import payment_create_request from .types import ( attribution_create_request, buyer_create_request, - context_create_request, line_item_create_request, - signals_create_request, ) diff --git a/src/ucp_sdk/models/schemas/shopping/checkout_update_request.py b/src/ucp_sdk/models/schemas/shopping/checkout_update_request.py index 045042d..564df8e 100644 --- a/src/ucp_sdk/models/schemas/shopping/checkout_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/checkout_update_request.py @@ -20,13 +20,12 @@ from pydantic import BaseModel, ConfigDict +from ..common.types import context_update_request, signals_update_request from . import payment_update_request from .types import ( attribution_update_request, buyer_update_request, - context_update_request, line_item_update_request, - signals_update_request, ) diff --git a/src/ucp_sdk/models/schemas/shopping/discount.py b/src/ucp_sdk/models/schemas/shopping/discount.py index f0121ee..c69a549 100644 --- a/src/ucp_sdk/models/schemas/shopping/discount.py +++ b/src/ucp_sdk/models/schemas/shopping/discount.py @@ -23,10 +23,10 @@ from pydantic import BaseModel, ConfigDict, Field from typing_extensions import TypeAliasType +from ..common.types import amount as amount_1 +from ..common.types import reverse_domain_name from .cart import Cart as Cart_1 from .checkout import Checkout as Checkout_1 -from .types import amount as amount_1 -from .types import reverse_domain_name DiscountExtension = TypeAliasType( "DiscountExtension", Annotated[Any, Field(..., title="Discount Extension")] diff --git a/src/ucp_sdk/models/schemas/shopping/fulfillment.py b/src/ucp_sdk/models/schemas/shopping/fulfillment.py index fd919f5..07238e5 100644 --- a/src/ucp_sdk/models/schemas/shopping/fulfillment.py +++ b/src/ucp_sdk/models/schemas/shopping/fulfillment.py @@ -20,24 +20,39 @@ from typing import Annotated, Any -from pydantic import ConfigDict, Field +from pydantic import BaseModel, ConfigDict, Field from typing_extensions import TypeAliasType +from ..common.types import description as description_1 +from .catalog_lookup import DetailProduct +from .catalog_lookup import GetProductRequest as GetProductRequest_1 +from .catalog_lookup import GetProductResponse as GetProductResponse_1 +from .catalog_lookup import LookupRequest as LookupRequest_1 +from .catalog_lookup import LookupResponse as LookupResponse_1 +from .catalog_lookup import LookupVariant +from .catalog_search import SearchRequest as SearchRequest_1 +from .catalog_search import SearchResponse as SearchResponse_1 from .checkout import Checkout as Checkout_1 +from .types import availability as availability_1 from .types import fulfillment as fulfillment_1 from .types import ( fulfillment_available_method, + fulfillment_destination_filter, fulfillment_group, fulfillment_method, fulfillment_option, + fulfillment_option_base, ) +from .types.product import Product +from .types.search_filters import SearchFilters +from .types.variant import Variant FulfillmentExtension = TypeAliasType( "FulfillmentExtension", Annotated[Any, Field(..., title="Fulfillment Extension")], ) """ -Extends Checkout with fulfillment support using methods, destinations, and groups. +Extends Catalog with fulfillment discovery and Checkout with hierarchical fulfillment. """ @@ -50,11 +65,129 @@ ) +class CatalogFulfillmentMethod(BaseModel): + """ + A fulfillment method on a catalog variant: how the variant can be fulfilled, and its availability. + """ + + model_config = ConfigDict( + extra="allow", + ) + type: str + """ + Fulfillment method type. Well-known values: `shipping`, `pickup`. Businesses MAY use additional values. + """ + description: description_1.Description | None = None + """ + Short buyer-facing summary (e.g. 'Ships in 2–4 business days'). + """ + availability: availability_1.Availability | None = None + """ + Availability of this variant via this method at the specified or inferred location. + """ + location: str | None = None + """ + Stable, opaque identifier for the Business Location resolved for this place-based fulfillment method. The Business recognizes the same ID when submitted as `selected_destination_id` for that method; recognition does not reserve inventory or guarantee eligibility, and current terms are revalidated. + """ + options: list[fulfillment_option_base.FulfillmentOptionBase] | None = None + """ + Representative fulfillment options for this method (e.g. Standard, Express). Without a destination or full cart, a Business SHOULD preview meaningful boundary options (e.g. cheapest, fastest); more specific options are negotiated in Checkout once line items and destination are known. + """ + + +class CatalogFulfillment(BaseModel): + """ + How a catalog variant can be fulfilled. Mirrors checkout `fulfillment`. + """ + + model_config = ConfigDict( + extra="allow", + ) + methods: list[CatalogFulfillmentMethod] | None = None + """ + Fulfillment methods for this variant. + """ + + FulfillmentOption = TypeAliasType( "FulfillmentOption", fulfillment_option.FulfillmentOption ) +class FulfillmentVariant(Variant): + """ + A catalog variant with fulfillment. + """ + + model_config = ConfigDict( + extra="allow", + ) + fulfillment: CatalogFulfillment | None = None + + +class FulfillmentLookupVariant(LookupVariant): + """ + A lookup variant (carrying input correlation) enriched with fulfillment. + """ + + model_config = ConfigDict( + extra="allow", + ) + fulfillment: CatalogFulfillment | None = None + + +class FulfillmentSearchFilters(SearchFilters): + """ + Catalog filters extended with a fulfillment destination filter and a method-type filter. + """ + + model_config = ConfigDict( + extra="allow", + ) + fulfills_to: ( + fulfillment_destination_filter.FulfillmentDestinationFilter | None + ) = None + """ + Explicit destination where items are fulfilled. It may differ from the locality or Business Location supplied in `context` (e.g. a gift delivered directly to the recipient). The filter restricts results to what can be fulfilled there and seeds method `availability`. It supersedes `context` only for fulfillment destination and availability resolution. + """ + methods: list[str] | None = None + """ + Restrict results to these fulfillment method types (e.g. ["pickup"]). Well-known values: `shipping`, `pickup`. + """ + + +class FulfillmentSearchRequest(SearchRequest_1): + model_config = ConfigDict( + extra="allow", + ) + filters: FulfillmentSearchFilters | None = None + + +class FulfillmentLookupRequest(LookupRequest_1): + model_config = ConfigDict( + extra="allow", + ) + filters: FulfillmentSearchFilters | None = None + + +class FulfillmentGetProductRequest(GetProductRequest_1): + model_config = ConfigDict( + extra="allow", + ) + filters: FulfillmentSearchFilters | None = None + + +SearchRequest = TypeAliasType("SearchRequest", FulfillmentSearchRequest) + + +LookupRequest = TypeAliasType("LookupRequest", FulfillmentLookupRequest) + + +GetProductRequest = TypeAliasType( + "GetProductRequest", FulfillmentGetProductRequest +) + + FulfillmentGroup = TypeAliasType( "FulfillmentGroup", fulfillment_group.FulfillmentGroup ) @@ -65,6 +198,71 @@ ) +class FulfillmentProduct(Product): + """ + A catalog product whose variants are fulfillment-enriched. Used by search. + """ + + model_config = ConfigDict( + extra="allow", + ) + variants: list[FulfillmentVariant] | None = None + + +class FulfillmentLookupProduct(Product): + """ + A lookup product whose variants are fulfillment-enriched, preserving input correlation. Used by lookup. + """ + + model_config = ConfigDict( + extra="allow", + ) + variants: list[FulfillmentLookupVariant] | None = None + + +class FulfillmentDetailProduct(DetailProduct): + """ + A get_product detail product (carrying selected/options availability signals) whose variants are fulfillment-enriched. Used by get_product. + """ + + model_config = ConfigDict( + extra="allow", + ) + variants: list[FulfillmentVariant] | None = None + + +class FulfillmentSearchResponse(SearchResponse_1): + model_config = ConfigDict( + extra="allow", + ) + products: list[FulfillmentProduct] | None = None + + +class FulfillmentLookupResponse(LookupResponse_1): + model_config = ConfigDict( + extra="allow", + ) + products: list[FulfillmentLookupProduct] | None = None + + +class FulfillmentGetProductResponse(GetProductResponse_1): + model_config = ConfigDict( + extra="allow", + ) + product: FulfillmentDetailProduct | None = None + + +SearchResponse = TypeAliasType("SearchResponse", FulfillmentSearchResponse) + + +LookupResponse = TypeAliasType("LookupResponse", FulfillmentLookupResponse) + + +GetProductResponse = TypeAliasType( + "GetProductResponse", FulfillmentGetProductResponse +) + + Fulfillment = TypeAliasType("Fulfillment", fulfillment_1.Fulfillment) diff --git a/src/ucp_sdk/models/schemas/shopping/order.py b/src/ucp_sdk/models/schemas/shopping/order.py index ede4135..47e95f0 100644 --- a/src/ucp_sdk/models/schemas/shopping/order.py +++ b/src/ucp_sdk/models/schemas/shopping/order.py @@ -21,10 +21,11 @@ from pydantic import AnyUrl, BaseModel, ConfigDict from .. import ucp as ucp_1 +from ..common.types import message, policy +from ..common.types import totals as totals_1 from .types import adjustment from .types import attribution as attribution_1 -from .types import expectation, fulfillment_event, message, order_line_item -from .types import totals as totals_1 +from .types import expectation, fulfillment_event, order_line_item class PlatformSchema(BaseModel): @@ -104,6 +105,10 @@ class Order(BaseModel): """ Different totals for the order. """ + policies: list[policy.Policy] | None = None + """ + Snapshot of the policies that applied to the items at checkout, captured on the order as a durable record. `applies_to` targets are relative to the response root. + """ messages: list[message.Message] | None = None """ Business outcome messages (errors, warnings, informational). Present when the business needs to communicate status or issues to the platform. diff --git a/src/ucp_sdk/models/schemas/shopping/order_create_request.py b/src/ucp_sdk/models/schemas/shopping/order_create_request.py index a31c315..e5f36ca 100644 --- a/src/ucp_sdk/models/schemas/shopping/order_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/order_create_request.py @@ -21,13 +21,12 @@ from pydantic import AnyUrl, BaseModel, ConfigDict from .. import ucp_create_request +from ..common.types import message_create_request, totals_create_request from .types import ( adjustment_create_request, expectation_create_request, fulfillment_event_create_request, - message_create_request, order_line_item_create_request, - totals_create_request, ) diff --git a/src/ucp_sdk/models/schemas/shopping/order_update_request.py b/src/ucp_sdk/models/schemas/shopping/order_update_request.py index fd4a285..959b3ae 100644 --- a/src/ucp_sdk/models/schemas/shopping/order_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/order_update_request.py @@ -21,13 +21,12 @@ from pydantic import AnyUrl, BaseModel, ConfigDict from .. import ucp_update_request +from ..common.types import message_update_request, totals_update_request from .types import ( adjustment_update_request, expectation_update_request, fulfillment_event_update_request, - message_update_request, order_line_item_update_request, - totals_update_request, ) diff --git a/src/ucp_sdk/models/schemas/shopping/payment_authentication.py b/src/ucp_sdk/models/schemas/shopping/payment_authentication.py new file mode 100644 index 0000000..41d5ccb --- /dev/null +++ b/src/ucp_sdk/models/schemas/shopping/payment_authentication.py @@ -0,0 +1,101 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from typing import Annotated, Any + +from pydantic import AnyUrl, BaseModel, ConfigDict, Field +from typing_extensions import TypeAliasType + +from .checkout import Checkout as Checkout_1 + +PaymentAuthenticationExtension = TypeAliasType( + "PaymentAuthenticationExtension", + Annotated[Any, Field(..., title="Payment Authentication Extension")], +) +""" +Extends Checkout with standard device data collection and 3DS challenge Action types used during payment authentication. +""" + + +class Config(BaseModel): + model_config = ConfigDict( + extra="allow", + ) + payment_instrument_id: str = Field(..., min_length=1) + """ + ID of the payment instrument in the containing Checkout associated with this device data collection Action. + """ + url: AnyUrl + """ + URL for the invisible device data collection surface. + """ + + +class DevUcpPaymentDeviceDataCollectionItem(BaseModel): + model_config = ConfigDict( + extra="allow", + ) + config: Config + + +class Config1(BaseModel): + model_config = ConfigDict( + extra="allow", + ) + payment_instrument_id: str = Field(..., min_length=1) + """ + ID of the payment instrument in the containing Checkout associated with this 3DS challenge Action. + """ + url: AnyUrl + """ + URL for the buyer-facing 3DS challenge surface. + """ + + +class DevUcpPaymentThreeDsChallengeItem(BaseModel): + model_config = ConfigDict( + extra="allow", + ) + config: Config1 + + +class Actions(BaseModel): + model_config = ConfigDict( + extra="allow", + ) + dev_ucp_payment_device_data_collection: ( + list[DevUcpPaymentDeviceDataCollectionItem] | None + ) = Field(None, alias="dev.ucp.payment.device_data_collection") + """ + A 3DS device data collection Action. + """ + dev_ucp_payment_three_ds_challenge: ( + list[DevUcpPaymentThreeDsChallengeItem] | None + ) = Field(None, alias="dev.ucp.payment.three_ds_challenge") + """ + A 3DS challenge Action. + """ + + +class Checkout(Checkout_1): + model_config = ConfigDict( + extra="allow", + ) + actions: Actions | None = None diff --git a/src/ucp_sdk/models/schemas/shopping/payment_terms.py b/src/ucp_sdk/models/schemas/shopping/payment_terms.py new file mode 100644 index 0000000..7b75937 --- /dev/null +++ b/src/ucp_sdk/models/schemas/shopping/payment_terms.py @@ -0,0 +1,99 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from typing import Annotated, Any + +from pydantic import BaseModel, ConfigDict, Field +from typing_extensions import TypeAliasType + +from .checkout import Checkout as Checkout_1 +from .order import Order as Order_1 +from .types import payment_term + +PaymentTermsExtension = TypeAliasType( + "PaymentTermsExtension", + Annotated[Any, Field(..., title="Payment Terms Extension")], +) +""" +Extends Checkout with selectable payment terms, letting a Business offer alternative schedules for when payment for the checkout is due, and projects the accepted term onto the resulting Order. +""" + + +PaymentTerm = TypeAliasType("PaymentTerm", payment_term.PaymentTerm) + + +class Payment(BaseModel): + """ + Payment object extended with selectable payment terms. + """ + + model_config = ConfigDict( + extra="allow", + ) + terms: list[PaymentTerm] | None = Field(None, min_length=1) + """ + Payment terms the Buyer can choose from. An unselected term's amounts are indicative; the selected term's schedule amounts sum to the checkout total. + """ + selected_term_id: str | None = None + """ + ID of the selected payment term. MUST match one `terms[].id` from the latest Checkout response. Present in a response whenever `terms` is, and absent when it is not: the Checkout total is the selected term's total, so a list of terms without a selection would show an amount that matches no stated term. Where the Buyer has made no choice, the Business selects a default. Omitted on create requests because term IDs are checkout-scoped and no terms exist yet, and on complete requests because the term is already agreed by then. Selecting a term is an Update Checkout mutation: the Business response is authoritative for all derived state. + """ + + +class OrderPayment(BaseModel): + """ + Order payment details carrying the term the Buyer accepted at checkout. + """ + + model_config = ConfigDict( + extra="allow", + ) + accepted_term: PaymentTerm | None = None + """ + The payment term the Buyer accepted at checkout. Businesses MUST carry it forward so the Order states the amounts owed and when, and MUST ensure its schedule amounts sum to the Order total. The available terms are checkout state and are not projected. + """ + + +class Checkout(Checkout_1): + """ + Checkout extended with selectable payment terms. + """ + + model_config = ConfigDict( + extra="allow", + ) + payment: Payment | None = None + """ + Payment details with available and selected payment terms. + """ + + +class Order(Order_1): + """ + Order extended with the payment term accepted at checkout. + """ + + model_config = ConfigDict( + extra="allow", + ) + payment: OrderPayment | None = None + """ + Payment details for the Order, including the accepted payment term. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/permalink.py b/src/ucp_sdk/models/schemas/shopping/permalink.py new file mode 100644 index 0000000..b05c9a2 --- /dev/null +++ b/src/ucp_sdk/models/schemas/shopping/permalink.py @@ -0,0 +1,52 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from typing import Annotated, Any + +from pydantic import AnyUrl, BaseModel, ConfigDict, Field +from typing_extensions import TypeAliasType + +PermalinkCapability = TypeAliasType( + "PermalinkCapability", + Annotated[Any, Field(..., title="Permalink Capability")], +) +""" +Browser-addressable shopping intent capability: defines a Business browser endpoint and redirect resolution. It defines no shopping-state fields of its own; permalink query parameters address existing UCP field paths. +""" + + +Endpoint = TypeAliasType("Endpoint", AnyUrl) +""" +Absolute HTTPS browser endpoint with a non-empty authority and without userinfo, query, fragment, whitespace, backslashes, or trailing slash. Optional compact item path and query parameters are appended to this endpoint. +""" + + +class Config(BaseModel): + """ + Business browser endpoint configuration for shopping permalinks. + """ + + model_config = ConfigDict( + extra="allow", + ) + endpoint: Endpoint + + +Permalink = TypeAliasType("Permalink", Any) diff --git a/src/ucp_sdk/models/schemas/shopping/split_payments.py b/src/ucp_sdk/models/schemas/shopping/split_payments.py new file mode 100644 index 0000000..b98f336 --- /dev/null +++ b/src/ucp_sdk/models/schemas/shopping/split_payments.py @@ -0,0 +1,80 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from typing import Annotated, Any + +from pydantic import BaseModel, ConfigDict, Field +from typing_extensions import TypeAliasType + +from ..common.types import amount as amount_1 +from .checkout import Checkout as Checkout_1 +from .types import instrument_group +from .types.payment_instrument import PaymentInstrument as PaymentInstrument_1 + +SplitPaymentsExtension = TypeAliasType( + "SplitPaymentsExtension", + Annotated[Any, Field(..., title="Split Payments Extension")], +) +""" +Enables buyers to use multiple payment instruments for a single checkout. +""" + + +InstrumentGroup = TypeAliasType( + "InstrumentGroup", instrument_group.InstrumentGroup +) + + +SplitPayments = TypeAliasType("SplitPayments", Any) + + +class PaymentInstrument(PaymentInstrument_1): + """ + Payment instrument extended with an optional per-instrument amount for split payments. + """ + + model_config = ConfigDict( + extra="allow", + ) + amount: amount_1.Amount | None = None + """ + Contribution amount for this instrument in `checkout.currency` minor units (ISO 4217). On request: the platform's requested contribution (omit for open-amount). On response: the actual amount authorized or charged (omitted when not finally processed). + """ + + +class Payment(BaseModel): + model_config = ConfigDict( + extra="allow", + ) + instruments: list[PaymentInstrument] | None = None + """ + Payment instruments in allocation priority order. + """ + + +class Checkout(Checkout_1): + """ + Checkout extended with split payment instrument amounts. + """ + + model_config = ConfigDict( + extra="allow", + ) + payment: Payment | None = None diff --git a/src/ucp_sdk/models/schemas/shopping/types/__init__.py b/src/ucp_sdk/models/schemas/shopping/types/__init__.py index 1252d6b..421dc21 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/__init__.py +++ b/src/ucp_sdk/models/schemas/shopping/types/__init__.py @@ -15,3 +15,4 @@ # generated by datamodel-codegen # pylint: disable=all # pyformat: disable + diff --git a/src/ucp_sdk/models/schemas/shopping/types/adjustment.py b/src/ucp_sdk/models/schemas/shopping/types/adjustment.py index 99cdfe4..3ae0b00 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/adjustment.py +++ b/src/ucp_sdk/models/schemas/shopping/types/adjustment.py @@ -20,9 +20,10 @@ from typing import Literal -from pydantic import AwareDatetime, BaseModel, ConfigDict +from pydantic import AwareDatetime, BaseModel, ConfigDict, Field -from . import total +from ...common.types import measure as measure_1 +from ...common.types import total class LineItem(BaseModel): @@ -33,9 +34,13 @@ class LineItem(BaseModel): """ Line item ID reference. """ - quantity: int + quantity: int = Field(..., ge=-9007199254740991, le=9007199254740991) """ - Signed quantity affected by this adjustment. Negative values represent reductions (e.g. returns); positive values represent additions (e.g. exchanges). + Signed integer count of steps of the referenced line item's `quantity_unit` (`10^-scale` × `unit`); when `quantity_unit` is absent, it counts whole items (`each`). Negative values represent reductions (e.g. returns); positive values represent additions (e.g. exchanges). + """ + measure: measure_1.Measure | None = None + """ + The settled measurement this adjustment reconciles (for example, actual picked weight), present when the line's price settles by measurement. Its unit identity MUST match the line's pricing basis (`item.unit_price` measure/reference unit); no unit conversion. A pure price settlement uses `quantity: 0` together with `measure` and a totals delta. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/adjustment_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/adjustment_create_request.py index 44881cd..f3a7abb 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/adjustment_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/adjustment_create_request.py @@ -20,9 +20,9 @@ from typing import Literal -from pydantic import AwareDatetime, BaseModel, ConfigDict +from pydantic import AwareDatetime, BaseModel, ConfigDict, Field -from . import total_create_request +from ...common.types import measure_create_request, total_create_request class LineItem(BaseModel): @@ -33,9 +33,13 @@ class LineItem(BaseModel): """ Line item ID reference. """ - quantity: int + quantity: int = Field(..., ge=-9007199254740991, le=9007199254740991) """ - Signed quantity affected by this adjustment. Negative values represent reductions (e.g. returns); positive values represent additions (e.g. exchanges). + Signed integer count of steps of the referenced line item's `quantity_unit` (`10^-scale` × `unit`); when `quantity_unit` is absent, it counts whole items (`each`). Negative values represent reductions (e.g. returns); positive values represent additions (e.g. exchanges). + """ + measure: measure_create_request.MeasureCreateRequest | None = None + """ + The settled measurement this adjustment reconciles (for example, actual picked weight), present when the line's price settles by measurement. Its unit identity MUST match the line's pricing basis (`item.unit_price` measure/reference unit); no unit conversion. A pure price settlement uses `quantity: 0` together with `measure` and a totals delta. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/adjustment_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/adjustment_update_request.py index 632c2e7..3fd1b3b 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/adjustment_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/adjustment_update_request.py @@ -20,9 +20,9 @@ from typing import Literal -from pydantic import AwareDatetime, BaseModel, ConfigDict +from pydantic import AwareDatetime, BaseModel, ConfigDict, Field -from . import total_update_request +from ...common.types import measure_update_request, total_update_request class LineItem(BaseModel): @@ -33,9 +33,13 @@ class LineItem(BaseModel): """ Line item ID reference. """ - quantity: int + quantity: int = Field(..., ge=-9007199254740991, le=9007199254740991) """ - Signed quantity affected by this adjustment. Negative values represent reductions (e.g. returns); positive values represent additions (e.g. exchanges). + Signed integer count of steps of the referenced line item's `quantity_unit` (`10^-scale` × `unit`); when `quantity_unit` is absent, it counts whole items (`each`). Negative values represent reductions (e.g. returns); positive values represent additions (e.g. exchanges). + """ + measure: measure_update_request.MeasureUpdateRequest | None = None + """ + The settled measurement this adjustment reconciles (for example, actual picked weight), present when the line's price settles by measurement. Its unit identity MUST match the line's pricing basis (`item.unit_price` measure/reference unit); no unit conversion. A pure price settlement uses `quantity: 0` together with `measure` and a totals delta. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/availability.py b/src/ucp_sdk/models/schemas/shopping/types/availability.py new file mode 100644 index 0000000..46b9ab9 --- /dev/null +++ b/src/ucp_sdk/models/schemas/shopping/types/availability.py @@ -0,0 +1,39 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from pydantic import BaseModel, ConfigDict + + +class Availability(BaseModel): + """ + Availability of an item: whether it can be obtained, and a qualifying status. + """ + + model_config = ConfigDict( + extra="allow", + ) + available: bool | None = None + """ + Whether this can be obtained. See status for fulfillment details. + """ + status: str | None = None + """ + Qualifies available with fulfillment state. Well-known values: `in_stock`, `backorder`, `preorder`, `out_of_stock`, `discontinued`. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/available_payment_instrument.py b/src/ucp_sdk/models/schemas/shopping/types/available_payment_instrument.py index dda328c..b58ae7c 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/available_payment_instrument.py +++ b/src/ucp_sdk/models/schemas/shopping/types/available_payment_instrument.py @@ -18,9 +18,9 @@ from __future__ import annotations -from typing import Any +from pydantic import BaseModel, ConfigDict -from pydantic import BaseModel, ConfigDict, Field +from ...common.types import constraint_expression class AvailablePaymentInstrument(BaseModel): @@ -35,7 +35,7 @@ class AvailablePaymentInstrument(BaseModel): """ The instrument type identifier (e.g., 'card', 'gift_card'). References an instrument schema's type constant. """ - constraints: dict[str, Any] | None = Field(None, min_length=1) + constraints: constraint_expression.ConstraintExpression | None = None """ - Constraints on this instrument type. Structure depends on instrument type and active capabilities. + A Constraint Expression describing the instrument this entry makes available. Keys in `properties` name members of the `constraint_target` declared by the instrument schema for this `type`. Requirements on submitted request data belong in `ucp.request_constraints` instead. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/business_fulfillment_config.py b/src/ucp_sdk/models/schemas/shopping/types/business_fulfillment_config.py index 55a9007..7515f7e 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/business_fulfillment_config.py +++ b/src/ucp_sdk/models/schemas/shopping/types/business_fulfillment_config.py @@ -18,26 +18,16 @@ from __future__ import annotations -from typing import Literal - from pydantic import BaseModel, ConfigDict -class AllowsMultiDestination(BaseModel): - """ - Permits multiple destinations per method type. - """ - +class MultiDestinationItem(BaseModel): model_config = ConfigDict( - extra="forbid", + extra="allow", ) - shipping: bool | None = None - """ - Multiple shipping destinations allowed. - """ - pickup: bool | None = None + method: str """ - Multiple pickup locations allowed. + Fulfillment method type (e.g. `shipping`, `pickup`). Optional per-method constraints MAY be added alongside. """ @@ -49,13 +39,11 @@ class BusinessFulfillmentConfig(BaseModel): model_config = ConfigDict( extra="allow", ) - allows_multi_destination: AllowsMultiDestination | None = None + multi_destination: list[MultiDestinationItem] | None = None """ - Permits multiple destinations per method type. + Method types that permit multiple destinations within one cart (e.g. split shipping across addresses). Listing a method permits it; an omitted method does not. Open — businesses MAY list any method type. """ - allows_method_combinations: ( - list[list[Literal["shipping", "pickup"]]] | None - ) = None + method_combinations: list[list[str]] | None = None """ - Allowed method type combinations. + Method-type combinations the business permits within one cart. Each inner array is a permitted set of method `type` values (e.g. shipping + pickup). """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/business_split_payments_config.py b/src/ucp_sdk/models/schemas/shopping/types/business_split_payments_config.py new file mode 100644 index 0000000..0f87555 --- /dev/null +++ b/src/ucp_sdk/models/schemas/shopping/types/business_split_payments_config.py @@ -0,0 +1,48 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from typing import Annotated + +from pydantic import BaseModel, ConfigDict, Field +from typing_extensions import TypeAliasType + +from . import instrument_group + +AllowedCombination = TypeAliasType( + "AllowedCombination", + Annotated[list[instrument_group.InstrumentGroup], Field(..., min_length=1)], +) +""" +A single valid combination: an array of instrument groups that together define the constraints. All groups must be satisfied (AND logic). +""" + + +class BusinessSplitPaymentsConfig(BaseModel): + """ + Business-level configuration for split payments. Declaring the capability means multiple payment instruments are supported; this config declares which combinations are valid. + """ + + model_config = ConfigDict( + extra="allow", + ) + allowed_combinations: list[AllowedCombination] = Field(..., min_length=1) + """ + Array of valid instrument combinations. Each combination is an array of instrument groups. A payment is valid if it matches any combination. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/card_credential.py b/src/ucp_sdk/models/schemas/shopping/types/card_credential.py index 43b231a..b7f671a 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/card_credential.py +++ b/src/ucp_sdk/models/schemas/shopping/types/card_credential.py @@ -27,7 +27,7 @@ class CardCredential(PaymentCredential): """ - A card credential containing sensitive payment card details including raw Primary Account Numbers (PANs). This credential type MUST NOT be used for checkout, only with payment handlers that tokenize or encrypt credentials. CRITICAL: Both parties handling CardCredential (sender and receiver) MUST be PCI DSS compliant. Transmission MUST use HTTPS/TLS with strong cipher suites. + Deprecated: use PAN Credential (`pan_credential.json`) or Network Token Credential (`network_token_credential.json`). A card credential containing sensitive payment card details including raw Primary Account Numbers (PANs). This credential type MUST NOT be used for checkout, only with payment handlers that tokenize or encrypt credentials. CRITICAL: Both parties handling CardCredential (sender and receiver) MUST be PCI DSS compliant. Transmission MUST use HTTPS/TLS with strong cipher suites. """ model_config = ConfigDict( @@ -39,7 +39,7 @@ class CardCredential(PaymentCredential): """ card_number_type: Literal["fpan", "network_token", "dpan"] """ - The type of card number. Network tokens are preferred with fallback to FPAN. See PCI Scope for more details. + Deprecated: the credential type now carries this distinction. The type of card number. Network tokens are preferred with fallback to FPAN. See PCI Scope for more details. """ number: str | None = Field(None, examples=["4242424242424242"]) """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/card_payment_instrument.py b/src/ucp_sdk/models/schemas/shopping/types/card_payment_instrument.py index e75ecd4..ea5ba62 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/card_payment_instrument.py +++ b/src/ucp_sdk/models/schemas/shopping/types/card_payment_instrument.py @@ -20,9 +20,8 @@ from typing import Literal -from pydantic import AnyUrl, BaseModel, ConfigDict, Field, field_validator +from pydantic import AnyUrl, BaseModel, ConfigDict, Field -from .available_payment_instrument import AvailablePaymentInstrument from .payment_instrument import PaymentInstrument @@ -36,7 +35,7 @@ class Display(BaseModel): ) brand: str | None = None """ - The card brand/network (e.g., visa, mastercard, amex). + The card brand/network shown to the buyer (e.g., visa, mastercard, amex). Presentational only. """ last_digits: str | None = None """ @@ -60,40 +59,20 @@ class Display(BaseModel): """ -class Constraints(BaseModel): - model_config = ConfigDict( - extra="allow", - ) - brands: list[str] | None = Field(None, min_length=1) +class ConstraintTarget(BaseModel): """ - Limit to specific card brands (e.g., ['visa', 'mastercard', 'amex']). - """ - - @field_validator("brands", mode="after") - def _enforce_unique_items_brands(cls, value): # noqa: N805 - """JSON Schema uniqueItems: reject duplicate entries.""" - if value is None: - return value - seen = [] - for item in value: - if item in seen: - raise ValueError( - "Items must be unique (schema uniqueItems=true)" - ) - seen.append(item) - return value - - -class AvailableCardPaymentInstrument(AvailablePaymentInstrument): - """ - Declares card instrument availability with card-specific constraints. + The object an available card instrument's `constraints` describes. It declares the constrainable members and their types and is never carried in a payload. """ model_config = ConfigDict( extra="allow", ) - type: Literal["card"] | None = None - constraints: Constraints | None = None + brand: str | None = Field( + None, examples=["visa", "mastercard", "cartebancaire"] + ) + """ + Card scheme. Derived from the account number, not submitted. + """ class CardPaymentInstrument(PaymentInstrument): @@ -108,6 +87,10 @@ class CardPaymentInstrument(PaymentInstrument): """ Indicates this is a card payment instrument. """ + network: str | None = None + """ + Card network elected for this transaction, typically a co-badged selection. When present, the business MAY decline if the card cannot route over it and MUST NOT substitute another. + """ display: Display | None = None """ Display information for this card payment instrument. diff --git a/src/ucp_sdk/models/schemas/shopping/types/expectation.py b/src/ucp_sdk/models/schemas/shopping/types/expectation.py index 03e8182..59163e2 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/expectation.py +++ b/src/ucp_sdk/models/schemas/shopping/types/expectation.py @@ -18,11 +18,9 @@ from __future__ import annotations -from typing import Literal - from pydantic import BaseModel, ConfigDict, Field -from . import postal_address +from ...common.types import postal_address class LineItem(BaseModel): @@ -33,9 +31,9 @@ class LineItem(BaseModel): """ Line item ID reference. """ - quantity: int = Field(..., ge=1) + quantity: int = Field(..., ge=1, le=9007199254740991) """ - Quantity of this item in this expectation. + Integer count of steps of the referenced line item's `quantity_unit` (`10^-scale` × `unit`); when `quantity_unit` is absent, it counts whole items (`each`). """ @@ -55,9 +53,9 @@ class Expectation(BaseModel): """ Which line items and quantities are in this expectation. """ - method_type: Literal["shipping", "pickup", "digital"] + method_type: str """ - Delivery method type (shipping, pickup, digital). + Delivery method type. Well-known values: `shipping`, `pickup`, `digital`; additional values MAY be used. """ destination: postal_address.PostalAddress """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/expectation_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/expectation_create_request.py index c1084bf..55f491f 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/expectation_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/expectation_create_request.py @@ -18,11 +18,9 @@ from __future__ import annotations -from typing import Literal - from pydantic import BaseModel, ConfigDict, Field -from . import postal_address_create_request +from ...common.types import postal_address_create_request class LineItem(BaseModel): @@ -33,9 +31,9 @@ class LineItem(BaseModel): """ Line item ID reference. """ - quantity: int = Field(..., ge=1) + quantity: int = Field(..., ge=1, le=9007199254740991) """ - Quantity of this item in this expectation. + Integer count of steps of the referenced line item's `quantity_unit` (`10^-scale` × `unit`); when `quantity_unit` is absent, it counts whole items (`each`). """ @@ -55,9 +53,9 @@ class ExpectationCreateRequest(BaseModel): """ Which line items and quantities are in this expectation. """ - method_type: Literal["shipping", "pickup", "digital"] + method_type: str """ - Delivery method type (shipping, pickup, digital). + Delivery method type. Well-known values: `shipping`, `pickup`, `digital`; additional values MAY be used. """ destination: postal_address_create_request.PostalAddressCreateRequest """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/expectation_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/expectation_update_request.py index f0780a9..a49a2d8 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/expectation_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/expectation_update_request.py @@ -18,11 +18,9 @@ from __future__ import annotations -from typing import Literal - from pydantic import BaseModel, ConfigDict, Field -from . import postal_address_update_request +from ...common.types import postal_address_update_request class LineItem(BaseModel): @@ -33,9 +31,9 @@ class LineItem(BaseModel): """ Line item ID reference. """ - quantity: int = Field(..., ge=1) + quantity: int = Field(..., ge=1, le=9007199254740991) """ - Quantity of this item in this expectation. + Integer count of steps of the referenced line item's `quantity_unit` (`10^-scale` × `unit`); when `quantity_unit` is absent, it counts whole items (`each`). """ @@ -55,9 +53,9 @@ class ExpectationUpdateRequest(BaseModel): """ Which line items and quantities are in this expectation. """ - method_type: Literal["shipping", "pickup", "digital"] + method_type: str """ - Delivery method type (shipping, pickup, digital). + Delivery method type. Well-known values: `shipping`, `pickup`, `digital`; additional values MAY be used. """ destination: postal_address_update_request.PostalAddressUpdateRequest """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_available_method.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_available_method.py index 4c9a1bb..d5df375 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_available_method.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_available_method.py @@ -18,8 +18,6 @@ from __future__ import annotations -from typing import Literal - from pydantic import BaseModel, ConfigDict @@ -31,9 +29,9 @@ class FulfillmentAvailableMethod(BaseModel): model_config = ConfigDict( extra="allow", ) - type: Literal["shipping", "pickup"] + type: str """ - Fulfillment method type this availability applies to. + Fulfillment method type this availability applies to. Well-known values: `shipping`, `pickup`; businesses MAY use additional values. """ line_item_ids: list[str] """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination.py index b26f3e3..fa07edf 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination.py @@ -18,21 +18,22 @@ from __future__ import annotations -from typing import Annotated +from pydantic import BaseModel, ConfigDict -from pydantic import Field -from typing_extensions import TypeAliasType -from . import retail_location, shipping_destination +class FulfillmentDestination(BaseModel): + """ + A destination for fulfillment. + """ -FulfillmentDestination = TypeAliasType( - "FulfillmentDestination", - Annotated[ - shipping_destination.ShippingDestination - | retail_location.RetailLocation, - Field(..., title="Fulfillment Destination"), - ], -) -""" -A destination for fulfillment. -""" + model_config = ConfigDict( + extra="allow", + ) + type: str + """ + Destination contract discriminator. Required in Business responses and optional in Platform requests. Well-known values: `shipping_address`, `business_location`. The enclosing method contract defines request defaults and which fields the Platform may write; negotiated extensions define additional values. + """ + id: str + """ + Fulfillment destination identifier. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination_create_request.py index 4d7bbb5..d46a2e8 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination_create_request.py @@ -18,24 +18,22 @@ from __future__ import annotations -from typing import Annotated +from pydantic import BaseModel, ConfigDict -from pydantic import Field -from typing_extensions import TypeAliasType -from . import ( - retail_location_create_request, - shipping_destination_create_request, -) +class FulfillmentDestinationCreateRequest(BaseModel): + """ + A destination for fulfillment. + """ -FulfillmentDestinationCreateRequest = TypeAliasType( - "FulfillmentDestinationCreateRequest", - Annotated[ - shipping_destination_create_request.ShippingDestinationCreateRequest - | retail_location_create_request.RetailLocationCreateRequest, - Field(..., title="Fulfillment Destination Create Request"), - ], -) -""" -A destination for fulfillment. -""" + model_config = ConfigDict( + extra="allow", + ) + type: str | None = None + """ + Destination contract discriminator. Required in Business responses and optional in Platform requests. Well-known values: `shipping_address`, `business_location`. The enclosing method contract defines request defaults and which fields the Platform may write; negotiated extensions define additional values. + """ + id: str | None = None + """ + Fulfillment destination identifier. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination_filter.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination_filter.py new file mode 100644 index 0000000..b2af2b1 --- /dev/null +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination_filter.py @@ -0,0 +1,37 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from pydantic import ConfigDict + +from ...common.types.locality import Locality + + +class FulfillmentDestinationFilter(Locality): + """ + A specific destination, named by value or by reference: a coarse locality (`address_country` / `address_region` / `postal_code`), or a `location` id. Platforms SHOULD provide one or the other, not both; if both are present, a business SHOULD use the more specific — typically `location`. + """ + + model_config = ConfigDict( + extra="allow", + ) + location: str | None = None + """ + A reference to the destination (e.g. store, pickup location, saved address). + """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination_update_request.py index add2079..0ea2cd1 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination_update_request.py @@ -18,24 +18,22 @@ from __future__ import annotations -from typing import Annotated +from pydantic import BaseModel, ConfigDict -from pydantic import Field -from typing_extensions import TypeAliasType -from . import ( - retail_location_update_request, - shipping_destination_update_request, -) +class FulfillmentDestinationUpdateRequest(BaseModel): + """ + A destination for fulfillment. + """ -FulfillmentDestinationUpdateRequest = TypeAliasType( - "FulfillmentDestinationUpdateRequest", - Annotated[ - shipping_destination_update_request.ShippingDestinationUpdateRequest - | retail_location_update_request.RetailLocationUpdateRequest, - Field(..., title="Fulfillment Destination Update Request"), - ], -) -""" -A destination for fulfillment. -""" + model_config = ConfigDict( + extra="allow", + ) + type: str | None = None + """ + Destination contract discriminator. Required in Business responses and optional in Platform requests. Well-known values: `shipping_address`, `business_location`. The enclosing method contract defines request defaults and which fields the Platform may write; negotiated extensions define additional values. + """ + id: str | None = None + """ + Fulfillment destination identifier. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_event.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_event.py index 68e09c6..7ae5f99 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_event.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_event.py @@ -29,9 +29,9 @@ class LineItem(BaseModel): """ Line item ID reference. """ - quantity: int = Field(..., ge=1) + quantity: int = Field(..., ge=1, le=9007199254740991) """ - Quantity fulfilled in this event. + Integer count of steps of the referenced line item's `quantity_unit` (`10^-scale` × `unit`); when `quantity_unit` is absent, it counts whole items (`each`). """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_event_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_event_create_request.py index a40632c..633d362 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_event_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_event_create_request.py @@ -29,9 +29,9 @@ class LineItem(BaseModel): """ Line item ID reference. """ - quantity: int = Field(..., ge=1) + quantity: int = Field(..., ge=1, le=9007199254740991) """ - Quantity fulfilled in this event. + Integer count of steps of the referenced line item's `quantity_unit` (`10^-scale` × `unit`); when `quantity_unit` is absent, it counts whole items (`each`). """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_event_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_event_update_request.py index 2462a71..a67550e 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_event_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_event_update_request.py @@ -29,9 +29,9 @@ class LineItem(BaseModel): """ Line item ID reference. """ - quantity: int = Field(..., ge=1) + quantity: int = Field(..., ge=1, le=9007199254740991) """ - Quantity fulfilled in this event. + Integer count of steps of the referenced line item's `quantity_unit` (`10^-scale` × `unit`); when `quantity_unit` is absent, it counts whole items (`each`). """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method.py index e022d8d..b9f7c06 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method.py @@ -18,8 +18,6 @@ from __future__ import annotations -from typing import Literal - from pydantic import BaseModel, ConfigDict from . import fulfillment_destination, fulfillment_group @@ -27,7 +25,7 @@ class FulfillmentMethod(BaseModel): """ - A fulfillment method (shipping or pickup) with destinations and groups. + A fulfillment method with destinations and groups. """ model_config = ConfigDict( @@ -37,9 +35,9 @@ class FulfillmentMethod(BaseModel): """ Unique fulfillment method identifier. """ - type: Literal["shipping", "pickup"] + type: str """ - Fulfillment method type. + Fulfillment method type. Well-known values: `shipping`, `pickup`. Businesses MAY use additional values. """ line_item_ids: list[str] """ @@ -49,11 +47,11 @@ class FulfillmentMethod(BaseModel): list[fulfillment_destination.FulfillmentDestination] | None ) = None """ - Available destinations. For shipping: addresses. For pickup: retail locations. + Available destinations for this method. In Business responses, each destination carries a `type` and `id`. """ selected_destination_id: str | None = None """ - ID of the selected destination. + ID of the selected destination. Accepts any stable, Business-scoped ID the Business recognizes for this method, including Location IDs not yet enumerated in `destinations`. """ groups: list[fulfillment_group.FulfillmentGroup] | None = None """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method_create_request.py index 602c48d..981c8cd 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method_create_request.py @@ -18,44 +18,26 @@ from __future__ import annotations -from typing import Literal - from pydantic import BaseModel, ConfigDict -from . import ( - fulfillment_destination_create_request, - fulfillment_group_create_request, -) +from . import fulfillment_group_create_request class FulfillmentMethodCreateRequest(BaseModel): """ - A fulfillment method (shipping or pickup) with destinations and groups. + A fulfillment method with destinations and groups. """ model_config = ConfigDict( extra="allow", ) - type: Literal["shipping", "pickup"] - """ - Fulfillment method type. - """ - line_item_ids: list[str] | None = None - """ - Line item IDs fulfilled via this method. - """ - destinations: ( - list[ - fulfillment_destination_create_request.FulfillmentDestinationCreateRequest - ] - | None - ) = None + type: str """ - Available destinations. For shipping: addresses. For pickup: retail locations. + Fulfillment method type. Well-known values: `shipping`, `pickup`. Businesses MAY use additional values. """ selected_destination_id: str | None = None """ - ID of the selected destination. + ID of the selected destination. Accepts any stable, Business-scoped ID the Business recognizes for this method, including Location IDs not yet enumerated in `destinations`. """ groups: ( list[fulfillment_group_create_request.FulfillmentGroupCreateRequest] diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method_update_request.py index 712477f..3f06a19 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method_update_request.py @@ -18,19 +18,14 @@ from __future__ import annotations -from typing import Literal - from pydantic import BaseModel, ConfigDict -from . import ( - fulfillment_destination_update_request, - fulfillment_group_update_request, -) +from . import fulfillment_group_update_request class FulfillmentMethodUpdateRequest(BaseModel): """ - A fulfillment method (shipping or pickup) with destinations and groups. + A fulfillment method with destinations and groups. """ model_config = ConfigDict( @@ -40,26 +35,17 @@ class FulfillmentMethodUpdateRequest(BaseModel): """ Unique fulfillment method identifier. """ - type: Literal["shipping", "pickup"] | None = None + type: str | None = None """ - Fulfillment method type. + Fulfillment method type. Well-known values: `shipping`, `pickup`. Businesses MAY use additional values. """ line_item_ids: list[str] """ Line item IDs fulfilled via this method. """ - destinations: ( - list[ - fulfillment_destination_update_request.FulfillmentDestinationUpdateRequest - ] - | None - ) = None - """ - Available destinations. For shipping: addresses. For pickup: retail locations. - """ selected_destination_id: str | None = None """ - ID of the selected destination. + ID of the selected destination. Accepts any stable, Business-scoped ID the Business recognizes for this method, including Location IDs not yet enumerated in `destinations`. """ groups: ( list[fulfillment_group_update_request.FulfillmentGroupUpdateRequest] diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option.py index 93b3bf8..b5f3ff1 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option.py @@ -18,31 +18,20 @@ from __future__ import annotations -from pydantic import AwareDatetime, BaseModel, ConfigDict +from pydantic import AwareDatetime, ConfigDict -from . import total +from ...common.types import total +from .fulfillment_option_base import FulfillmentOptionBase -class FulfillmentOption(BaseModel): +class FulfillmentOption(FulfillmentOptionBase): """ - A fulfillment option within a group (e.g., Standard Shipping $5, Express $15). + A fulfillment option within a group (e.g., Standard Shipping $5, Express $15). Extends the fulfillment option base with cost and timing. """ model_config = ConfigDict( extra="allow", ) - id: str - """ - Unique fulfillment option identifier. - """ - title: str - """ - Short label (e.g., 'Express Shipping', 'Curbside Pickup'). - """ - description: str | None = None - """ - Complete context for buyer decision (e.g., 'Arrives Dec 12-15 via FedEx'). - """ carrier: str | None = None """ Carrier name (for shipping). diff --git a/src/ucp_sdk/models/schemas/shopping/types/merchant_fulfillment_config.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_base.py similarity index 54% rename from src/ucp_sdk/models/schemas/shopping/types/merchant_fulfillment_config.py rename to src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_base.py index f4b1afd..b54b7de 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/merchant_fulfillment_config.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_base.py @@ -18,44 +18,28 @@ from __future__ import annotations -from typing import Literal - from pydantic import BaseModel, ConfigDict +from ...common.types import description as description_1 -class AllowsMultiDestination(BaseModel): - """ - Permits multiple destinations per method type. - """ - model_config = ConfigDict( - extra="forbid", - ) - shipping: bool | None = None - """ - Multiple shipping destinations allowed. - """ - pickup: bool | None = None +class FulfillmentOptionBase(BaseModel): """ - Multiple pickup locations allowed. - """ - - -class MerchantFulfillmentConfig(BaseModel): - """ - Merchant's fulfillment configuration. + Common base for a fulfillment option: an addressable, renderable choice (e.g. Standard, Express). Catalog uses this base directly; checkout composes it with cost and timing. """ model_config = ConfigDict( extra="allow", ) - allows_multi_destination: AllowsMultiDestination | None = None + id: str + """ + Unique identifier for this fulfillment option. + """ + title: str """ - Permits multiple destinations per method type. + Short label that distinguishes this option from its siblings (e.g. 'Standard', 'Express Shipping', 'Curbside Pickup'). """ - allows_method_combinations: ( - list[list[Literal["shipping", "pickup"]]] | None - ) = None + description: description_1.Description | None = None """ - Allowed method type combinations. + Supplementary context for the title (e.g. 'Arrives in 4 business days', 'Arrives Dec 12-15 via FedEx'). Directly renderable; MUST NOT repeat the title. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/retail_location_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_base_create_request.py similarity index 68% rename from src/ucp_sdk/models/schemas/shopping/types/retail_location_create_request.py rename to src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_base_create_request.py index 4d42caf..5431e66 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/retail_location_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_base_create_request.py @@ -20,24 +20,12 @@ from pydantic import BaseModel, ConfigDict -from . import postal_address_create_request - -class RetailLocationCreateRequest(BaseModel): +class FulfillmentOptionBaseCreateRequest(BaseModel): """ - A pickup location (retail store, locker, etc.). + Common base for a fulfillment option: an addressable, renderable choice (e.g. Standard, Express). Catalog uses this base directly; checkout composes it with cost and timing. """ model_config = ConfigDict( extra="allow", ) - name: str - """ - Location name (e.g., store name). - """ - address: postal_address_create_request.PostalAddressCreateRequest | None = ( - None - ) - """ - Physical address of the location. - """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_base_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_base_update_request.py new file mode 100644 index 0000000..b0112af --- /dev/null +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_base_update_request.py @@ -0,0 +1,31 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from pydantic import BaseModel, ConfigDict + + +class FulfillmentOptionBaseUpdateRequest(BaseModel): + """ + Common base for a fulfillment option: an addressable, renderable choice (e.g. Standard, Express). Catalog uses this base directly; checkout composes it with cost and timing. + """ + + model_config = ConfigDict( + extra="allow", + ) diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_create_request.py index d08ee75..4cbda60 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_create_request.py @@ -18,12 +18,16 @@ from __future__ import annotations -from pydantic import BaseModel, ConfigDict +from pydantic import ConfigDict +from .fulfillment_option_base_create_request import ( + FulfillmentOptionBaseCreateRequest, +) -class FulfillmentOptionCreateRequest(BaseModel): + +class FulfillmentOptionCreateRequest(FulfillmentOptionBaseCreateRequest): """ - A fulfillment option within a group (e.g., Standard Shipping $5, Express $15). + A fulfillment option within a group (e.g., Standard Shipping $5, Express $15). Extends the fulfillment option base with cost and timing. """ model_config = ConfigDict( diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_update_request.py index 363e7f3..d2928a7 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_update_request.py @@ -18,12 +18,16 @@ from __future__ import annotations -from pydantic import BaseModel, ConfigDict +from pydantic import ConfigDict +from .fulfillment_option_base_update_request import ( + FulfillmentOptionBaseUpdateRequest, +) -class FulfillmentOptionUpdateRequest(BaseModel): + +class FulfillmentOptionUpdateRequest(FulfillmentOptionBaseUpdateRequest): """ - A fulfillment option within a group (e.g., Standard Shipping $5, Express $15). + A fulfillment option within a group (e.g., Standard Shipping $5, Express $15). Extends the fulfillment option base with cost and timing. """ model_config = ConfigDict( diff --git a/src/ucp_sdk/models/schemas/shopping/types/instrument_group.py b/src/ucp_sdk/models/schemas/shopping/types/instrument_group.py new file mode 100644 index 0000000..55bb991 --- /dev/null +++ b/src/ucp_sdk/models/schemas/shopping/types/instrument_group.py @@ -0,0 +1,43 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from pydantic import BaseModel, ConfigDict, Field + + +class InstrumentGroup(BaseModel): + """ + A constraint within an allowed combination that defines which instrument types can fill this group and how many are permitted. + """ + + model_config = ConfigDict( + extra="allow", + ) + types: list[str] = Field(..., min_length=1) + """ + Instrument types accepted by this group (OR logic). Any listed type qualifies. + """ + min: int | None = Field(0, ge=0) + """ + Minimum number of instruments required from this group. Defaults to 0 (optional). + """ + max: int | None = Field(1, ge=1) + """ + Maximum number of instruments allowed from this group. Defaults to 1. MUST be greater than or equal to `min`. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/item.py b/src/ucp_sdk/models/schemas/shopping/types/item.py index cfcc71c..1d07c83 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/item.py +++ b/src/ucp_sdk/models/schemas/shopping/types/item.py @@ -20,7 +20,9 @@ from pydantic import AnyUrl, BaseModel, ConfigDict -from . import amount +from ...common.types import amount +from ...common.types import quantity_unit as quantity_unit_1 +from . import unit_price as unit_price_1 class Item(BaseModel): @@ -37,7 +39,15 @@ class Item(BaseModel): """ price: amount.Amount """ - Unit price in ISO 4217 minor units. + Unit price in ISO 4217 minor units. Price is the amount per one whole `quantity_unit.unit` (for example, per lb or per hour); when `quantity_unit` is absent, it is per `each`. + """ + quantity_unit: quantity_unit_1.QuantityUnit | None = None + """ + Sale basis this item's `quantity` is denominated in. On an authoritative Business response, absence encodes the default `each` machine identity (`C62`, 0); the Business MUST include this descriptor for every non-`each` response. On Platform requests, omission makes no assertion: the Business interprets `quantity` using the item's authoritative sale basis. If the Platform includes this descriptor, it asserts the unit-descriptor machine identity. The Business MUST compare that machine identity (`unit`, effective `scale`), ignore `display_text` and `increment`, and resolve a mismatch by conversion surfaced as a visible line revision with a warning, or by rejection with a recoverable business outcome; silent reinterpretation is forbidden. An explicit `C62` descriptor at effective scale 0 matches an authoritative basis represented by an absent descriptor. + """ + unit_price: unit_price_1.UnitPrice | None = None + """ + Pricing basis for this item. On an authoritative Business response, the Business MUST include `unit_price` on every line whose pricing basis differs from its sale basis (for example, priced per pound but sold per `each`); presence on a line marks the rate as transactional rather than display-only. When the pricing basis is the sale basis, `item.price` fully denominates the charge and this field MAY be omitted. """ image_url: AnyUrl | None = None """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/item_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/item_create_request.py index bbef8e8..df9f0cd 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/item_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/item_create_request.py @@ -20,6 +20,8 @@ from pydantic import BaseModel, ConfigDict +from ...common.types import quantity_unit_create_request + class ItemCreateRequest(BaseModel): model_config = ConfigDict( @@ -29,3 +31,9 @@ class ItemCreateRequest(BaseModel): """ The product identifier, often the SKU, required to resolve the product details associated with this line item. Should be recognized by both the Platform, and the Business. """ + quantity_unit: ( + quantity_unit_create_request.QuantityUnitCreateRequest | None + ) = None + """ + Sale basis this item's `quantity` is denominated in. On an authoritative Business response, absence encodes the default `each` machine identity (`C62`, 0); the Business MUST include this descriptor for every non-`each` response. On Platform requests, omission makes no assertion: the Business interprets `quantity` using the item's authoritative sale basis. If the Platform includes this descriptor, it asserts the unit-descriptor machine identity. The Business MUST compare that machine identity (`unit`, effective `scale`), ignore `display_text` and `increment`, and resolve a mismatch by conversion surfaced as a visible line revision with a warning, or by rejection with a recoverable business outcome; silent reinterpretation is forbidden. An explicit `C62` descriptor at effective scale 0 matches an authoritative basis represented by an absent descriptor. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/item_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/item_update_request.py index c957d16..96186f5 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/item_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/item_update_request.py @@ -20,6 +20,8 @@ from pydantic import BaseModel, ConfigDict +from ...common.types import quantity_unit_update_request + class ItemUpdateRequest(BaseModel): model_config = ConfigDict( @@ -29,3 +31,9 @@ class ItemUpdateRequest(BaseModel): """ The product identifier, often the SKU, required to resolve the product details associated with this line item. Should be recognized by both the Platform, and the Business. """ + quantity_unit: ( + quantity_unit_update_request.QuantityUnitUpdateRequest | None + ) = None + """ + Sale basis this item's `quantity` is denominated in. On an authoritative Business response, absence encodes the default `each` machine identity (`C62`, 0); the Business MUST include this descriptor for every non-`each` response. On Platform requests, omission makes no assertion: the Business interprets `quantity` using the item's authoritative sale basis. If the Platform includes this descriptor, it asserts the unit-descriptor machine identity. The Business MUST compare that machine identity (`unit`, effective `scale`), ignore `display_text` and `increment`, and resolve a mismatch by conversion surfaced as a visible line revision with a warning, or by rejection with a recoverable business outcome; silent reinterpretation is forbidden. An explicit `C62` descriptor at effective scale 0 matches an authoritative basis represented by an absent descriptor. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/line_item.py b/src/ucp_sdk/models/schemas/shopping/types/line_item.py index 9f2befe..cf31595 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/line_item.py +++ b/src/ucp_sdk/models/schemas/shopping/types/line_item.py @@ -20,8 +20,8 @@ from pydantic import BaseModel, ConfigDict, Field +from ...common.types import total from . import item as item_1 -from . import total class LineItem(BaseModel): @@ -34,9 +34,9 @@ class LineItem(BaseModel): ) id: str item: item_1.Item - quantity: int = Field(..., ge=1) + quantity: int = Field(..., ge=1, le=9007199254740991) """ - Quantity of the item being purchased. + Always an integer step count. On Platform requests, steps use the item's Business-authoritative sale basis; omitting `item.quantity_unit` makes no assertion and does not imply `each`. On Business responses, `item.quantity_unit` describes the basis; if absent, it encodes the `each` machine identity (`C62`, 0) and `quantity` counts whole items. """ totals: list[total.Total] """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/line_item_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/line_item_create_request.py index 754e4fe..c669bb3 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/line_item_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/line_item_create_request.py @@ -32,7 +32,7 @@ class LineItemCreateRequest(BaseModel): extra="allow", ) item: item_create_request.ItemCreateRequest - quantity: int = Field(..., ge=1) + quantity: int = Field(..., ge=1, le=9007199254740991) """ - Quantity of the item being purchased. + Always an integer step count. On Platform requests, steps use the item's Business-authoritative sale basis; omitting `item.quantity_unit` makes no assertion and does not imply `each`. On Business responses, `item.quantity_unit` describes the basis; if absent, it encodes the `each` machine identity (`C62`, 0) and `quantity` counts whole items. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/line_item_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/line_item_update_request.py index fc43593..a5c78e4 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/line_item_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/line_item_update_request.py @@ -33,9 +33,9 @@ class LineItemUpdateRequest(BaseModel): ) id: str | None = None item: item_update_request.ItemUpdateRequest - quantity: int = Field(..., ge=1) + quantity: int = Field(..., ge=1, le=9007199254740991) """ - Quantity of the item being purchased. + Always an integer step count. On Platform requests, steps use the item's Business-authoritative sale basis; omitting `item.quantity_unit` makes no assertion and does not imply `each`. On Business responses, `item.quantity_unit` describes the basis; if absent, it encodes the `each` machine identity (`C62`, 0) and `quantity` counts whole items. """ parent_id: str | None = None """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/location_destination.py b/src/ucp_sdk/models/schemas/shopping/types/location_destination.py new file mode 100644 index 0000000..9860bac --- /dev/null +++ b/src/ucp_sdk/models/schemas/shopping/types/location_destination.py @@ -0,0 +1,39 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from typing import Literal + +from pydantic import ConfigDict + +from ...common.types.location_summary import LocationSummary + + +class BusinessLocationDestination(LocationSummary): + """ + A business location fulfillment destination. Business-authored and response-only: the Platform selects a location via `selected_destination_id` rather than writing destinations. + """ + + model_config = ConfigDict( + extra="allow", + ) + type: Literal["business_location"] + """ + Destination type discriminator. Response-only. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/location_destination_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/location_destination_create_request.py new file mode 100644 index 0000000..90cb2a5 --- /dev/null +++ b/src/ucp_sdk/models/schemas/shopping/types/location_destination_create_request.py @@ -0,0 +1,35 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from pydantic import ConfigDict + +from ...common.types.location_summary_create_request import ( + LocationSummaryCreateRequest, +) + + +class BusinessLocationDestinationCreateRequest(LocationSummaryCreateRequest): + """ + A business location fulfillment destination. Business-authored and response-only: the Platform selects a location via `selected_destination_id` rather than writing destinations. + """ + + model_config = ConfigDict( + extra="allow", + ) diff --git a/src/ucp_sdk/models/schemas/shopping/types/location_destination_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/location_destination_update_request.py new file mode 100644 index 0000000..3154a71 --- /dev/null +++ b/src/ucp_sdk/models/schemas/shopping/types/location_destination_update_request.py @@ -0,0 +1,35 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from pydantic import ConfigDict + +from ...common.types.location_summary_update_request import ( + LocationSummaryUpdateRequest, +) + + +class BusinessLocationDestinationUpdateRequest(LocationSummaryUpdateRequest): + """ + A business location fulfillment destination. Business-authored and response-only: the Platform selects a location via `selected_destination_id` rather than writing destinations. + """ + + model_config = ConfigDict( + extra="allow", + ) diff --git a/src/ucp_sdk/models/schemas/shopping/types/network_token_credential.py b/src/ucp_sdk/models/schemas/shopping/types/network_token_credential.py new file mode 100644 index 0000000..522e07b --- /dev/null +++ b/src/ucp_sdk/models/schemas/shopping/types/network_token_credential.py @@ -0,0 +1,67 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from typing import Literal + +from pydantic import ConfigDict, Field + +from .payment_credential import PaymentCredential + + +class NetworkTokenCredential(PaymentCredential): + """ + A card-network token credential verified with a transaction cryptogram. The `number` field carries the network token or wallet-provisioned token rather than the underlying FPAN. + """ + + model_config = ConfigDict( + extra="allow", + ) + type: Literal["network_token"] + """ + The credential type identifier for network token credentials. + """ + number: str = Field(..., examples=["5204240000004242"]) + """ + Network token or wallet-provisioned token replacing the underlying FPAN. + """ + expiry_month: int | None = None + """ + The month of the token's expiration date (1-12). + """ + expiry_year: int | None = None + """ + The year of the token's expiration date. + """ + name: str | None = Field(None, examples=["Jane Doe"]) + """ + Cardholder name. + """ + cryptogram: str = Field(..., examples=["gXc5UCLnM6ckD7pjM1TdPA=="]) + """ + Transaction cryptogram or dynamic CVC (dCVV), in the long or short form expected by the card network or processor. + """ + eci_value: str | None = Field(None, examples=["07"]) + """ + Electronic Commerce Indicator / Security Level Indicator associated with the transaction. + """ + token_requestor_id: str | None = Field(None, examples=["12345678901"]) + """ + Payment network token requestor identifier, when required by the processor or network-token program. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/order_line_item.py b/src/ucp_sdk/models/schemas/shopping/types/order_line_item.py index cd80f04..131c550 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/order_line_item.py +++ b/src/ucp_sdk/models/schemas/shopping/types/order_line_item.py @@ -22,29 +22,29 @@ from pydantic import BaseModel, ConfigDict, Field +from ...common.types import total as total_1 from . import item as item_1 -from . import total as total_1 class Quantity(BaseModel): """ - Quantity tracking for the line item. + Tracks the line item's original, current active, and fulfilled quantities. All three values use the same inherited `item.quantity_unit`. When `item.quantity_unit` is absent on an authoritative order response, each step is one whole item (`each`) under the shared default. """ model_config = ConfigDict( extra="allow", ) - original: int | None = Field(None, ge=0) + original: int | None = Field(None, ge=0, le=9007199254740991) """ - Quantity from the original checkout. + Quantity from the original checkout, expressed as an integer step count. """ - total: int = Field(..., ge=0) + total: int = Field(..., ge=0, le=9007199254740991) """ - Current total active quantity. May differ from original due to post-order modifications (e.g., returns or cancellations). + Current active quantity after returns, cancellations, or other order changes, expressed as an integer step count. """ - fulfilled: int = Field(..., ge=0) + fulfilled: int = Field(..., ge=0, le=9007199254740991) """ - Quantity fulfilled so far. + Quantity fulfilled so far, expressed as an integer step count. """ @@ -58,11 +58,11 @@ class OrderLineItem(BaseModel): """ item: item_1.Item """ - Product data (id, title, price, image_url). + Purchased item data, including identity, price, and sale basis. """ quantity: Quantity """ - Quantity tracking for the line item. + Tracks the line item's original, current active, and fulfilled quantities. All three values use the same inherited `item.quantity_unit`. When `item.quantity_unit` is absent on an authoritative order response, each step is one whole item (`each`) under the shared default. """ totals: list[total_1.Total] """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/order_line_item_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/order_line_item_create_request.py index 56693e0..6e0fe34 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/order_line_item_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/order_line_item_create_request.py @@ -22,28 +22,29 @@ from pydantic import BaseModel, ConfigDict, Field -from . import item_create_request, total_create_request +from ...common.types import total_create_request +from . import item_create_request class Quantity(BaseModel): """ - Quantity tracking for the line item. + Tracks the line item's original, current active, and fulfilled quantities. All three values use the same inherited `item.quantity_unit`. When `item.quantity_unit` is absent on an authoritative order response, each step is one whole item (`each`) under the shared default. """ model_config = ConfigDict( extra="allow", ) - original: int | None = Field(None, ge=0) + original: int | None = Field(None, ge=0, le=9007199254740991) """ - Quantity from the original checkout. + Quantity from the original checkout, expressed as an integer step count. """ - total: int = Field(..., ge=0) + total: int = Field(..., ge=0, le=9007199254740991) """ - Current total active quantity. May differ from original due to post-order modifications (e.g., returns or cancellations). + Current active quantity after returns, cancellations, or other order changes, expressed as an integer step count. """ - fulfilled: int = Field(..., ge=0) + fulfilled: int = Field(..., ge=0, le=9007199254740991) """ - Quantity fulfilled so far. + Quantity fulfilled so far, expressed as an integer step count. """ @@ -57,11 +58,11 @@ class OrderLineItemCreateRequest(BaseModel): """ item: item_create_request.ItemCreateRequest """ - Product data (id, title, price, image_url). + Purchased item data, including identity, price, and sale basis. """ quantity: Quantity """ - Quantity tracking for the line item. + Tracks the line item's original, current active, and fulfilled quantities. All three values use the same inherited `item.quantity_unit`. When `item.quantity_unit` is absent on an authoritative order response, each step is one whole item (`each`) under the shared default. """ totals: list[total_create_request.TotalCreateRequest] """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/order_line_item_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/order_line_item_update_request.py index 178d09c..7db84e2 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/order_line_item_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/order_line_item_update_request.py @@ -22,28 +22,29 @@ from pydantic import BaseModel, ConfigDict, Field -from . import item_update_request, total_update_request +from ...common.types import total_update_request +from . import item_update_request class Quantity(BaseModel): """ - Quantity tracking for the line item. + Tracks the line item's original, current active, and fulfilled quantities. All three values use the same inherited `item.quantity_unit`. When `item.quantity_unit` is absent on an authoritative order response, each step is one whole item (`each`) under the shared default. """ model_config = ConfigDict( extra="allow", ) - original: int | None = Field(None, ge=0) + original: int | None = Field(None, ge=0, le=9007199254740991) """ - Quantity from the original checkout. + Quantity from the original checkout, expressed as an integer step count. """ - total: int = Field(..., ge=0) + total: int = Field(..., ge=0, le=9007199254740991) """ - Current total active quantity. May differ from original due to post-order modifications (e.g., returns or cancellations). + Current active quantity after returns, cancellations, or other order changes, expressed as an integer step count. """ - fulfilled: int = Field(..., ge=0) + fulfilled: int = Field(..., ge=0, le=9007199254740991) """ - Quantity fulfilled so far. + Quantity fulfilled so far, expressed as an integer step count. """ @@ -57,11 +58,11 @@ class OrderLineItemUpdateRequest(BaseModel): """ item: item_update_request.ItemUpdateRequest """ - Product data (id, title, price, image_url). + Purchased item data, including identity, price, and sale basis. """ quantity: Quantity """ - Quantity tracking for the line item. + Tracks the line item's original, current active, and fulfilled quantities. All three values use the same inherited `item.quantity_unit`. When `item.quantity_unit` is absent on an authoritative order response, each step is one whole item (`each`) under the shared default. """ totals: list[total_update_request.TotalUpdateRequest] """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/pan_credential.py b/src/ucp_sdk/models/schemas/shopping/types/pan_credential.py new file mode 100644 index 0000000..a7ed37c --- /dev/null +++ b/src/ucp_sdk/models/schemas/shopping/types/pan_credential.py @@ -0,0 +1,59 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from typing import Literal + +from pydantic import ConfigDict, Field + +from .payment_credential import PaymentCredential + + +class PanCredential(PaymentCredential): + """ + A card credential carrying a funding primary account number (FPAN). Credential selection follows the shape of the value on the wire rather than its provenance: a network token surfaced in PAN form and verified with a `cvc` — as with credentials where a dynamic verification code proxies the cryptogram — is carried here, while a token verified with a discrete `cryptogram` uses Network Token Credential. This credential type MUST NOT be used for checkout, only with payment handlers that tokenize or encrypt credentials. CRITICAL: Both parties handling a PAN credential (sender and receiver) MUST be PCI DSS compliant. Transmission MUST use HTTPS/TLS with strong cipher suites. + """ + + model_config = ConfigDict( + extra="allow", + ) + type: Literal["pan"] + """ + The credential type identifier for PAN credentials. + """ + number: str = Field(..., examples=["4242424242424242"]) + """ + Funding primary account number (FPAN). + """ + expiry_month: int | None = None + """ + The month of the card's expiration date (1-12). + """ + expiry_year: int | None = None + """ + The year of the card's expiration date. + """ + name: str | None = Field(None, examples=["Jane Doe"]) + """ + Cardholder name. + """ + cvc: str | None = Field(None, examples=["223"], max_length=4) + """ + Card verification code. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/payment_identity.py b/src/ucp_sdk/models/schemas/shopping/types/payment_identity.py index b30f85d..14b1881 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/payment_identity.py +++ b/src/ucp_sdk/models/schemas/shopping/types/payment_identity.py @@ -23,7 +23,7 @@ class PaymentIdentity(BaseModel): """ - Identity of a participant for token binding. The access_token uniquely identifies the participant who tokens should be bound to. + Identity of a participant for token binding. The access_token uniquely identifies the participant whom tokens should be issued to. """ model_config = ConfigDict( diff --git a/src/ucp_sdk/models/schemas/shopping/types/payment_instrument.py b/src/ucp_sdk/models/schemas/shopping/types/payment_instrument.py index 4b7bf78..138c947 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/payment_instrument.py +++ b/src/ucp_sdk/models/schemas/shopping/types/payment_instrument.py @@ -22,7 +22,8 @@ from pydantic import BaseModel, ConfigDict -from . import payment_credential, postal_address +from ...common.types import postal_address +from . import payment_credential class PaymentInstrument(BaseModel): @@ -35,7 +36,7 @@ class PaymentInstrument(BaseModel): ) id: str """ - A unique identifier for this instrument instance, assigned by the platform. + A unique identifier for this instrument instance. Typically assigned by the platform for instruments it collects. For a business-owned saved instrument returned on an identity-linked response, this identifier is assigned by the business; the platform MUST treat it as an opaque, business-scoped reference, and the business resolves it server-side when the buyer selects it. """ handler_id: str """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/payment_instrument_complete_request.py b/src/ucp_sdk/models/schemas/shopping/types/payment_instrument_complete_request.py index 2aac44e..7acd81f 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/payment_instrument_complete_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/payment_instrument_complete_request.py @@ -22,10 +22,8 @@ from pydantic import BaseModel, ConfigDict -from . import ( - payment_credential_complete_request, - postal_address_complete_request, -) +from ...common.types import postal_address_complete_request +from . import payment_credential_complete_request class PaymentInstrumentCompleteRequest(BaseModel): @@ -38,7 +36,7 @@ class PaymentInstrumentCompleteRequest(BaseModel): ) id: str """ - A unique identifier for this instrument instance, assigned by the platform. + A unique identifier for this instrument instance. Typically assigned by the platform for instruments it collects. For a business-owned saved instrument returned on an identity-linked response, this identifier is assigned by the business; the platform MUST treat it as an opaque, business-scoped reference, and the business resolves it server-side when the buyer selects it. """ handler_id: str """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/payment_instrument_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/payment_instrument_create_request.py index 4d7117e..f13e02f 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/payment_instrument_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/payment_instrument_create_request.py @@ -22,7 +22,8 @@ from pydantic import BaseModel, ConfigDict -from . import payment_credential_create_request, postal_address_create_request +from ...common.types import postal_address_create_request +from . import payment_credential_create_request class PaymentInstrumentCreateRequest(BaseModel): @@ -35,7 +36,7 @@ class PaymentInstrumentCreateRequest(BaseModel): ) id: str """ - A unique identifier for this instrument instance, assigned by the platform. + A unique identifier for this instrument instance. Typically assigned by the platform for instruments it collects. For a business-owned saved instrument returned on an identity-linked response, this identifier is assigned by the business; the platform MUST treat it as an opaque, business-scoped reference, and the business resolves it server-side when the buyer selects it. """ handler_id: str """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/payment_instrument_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/payment_instrument_update_request.py index 0a72443..2c30caf 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/payment_instrument_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/payment_instrument_update_request.py @@ -22,7 +22,8 @@ from pydantic import BaseModel, ConfigDict -from . import payment_credential_update_request, postal_address_update_request +from ...common.types import postal_address_update_request +from . import payment_credential_update_request class PaymentInstrumentUpdateRequest(BaseModel): @@ -35,7 +36,7 @@ class PaymentInstrumentUpdateRequest(BaseModel): ) id: str """ - A unique identifier for this instrument instance, assigned by the platform. + A unique identifier for this instrument instance. Typically assigned by the platform for instruments it collects. For a business-owned saved instrument returned on an identity-linked response, this identifier is assigned by the business; the platform MUST treat it as an opaque, business-scoped reference, and the business resolves it server-side when the buyer selects it. """ handler_id: str """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/payment_schedule.py b/src/ucp_sdk/models/schemas/shopping/types/payment_schedule.py new file mode 100644 index 0000000..51e8cb9 --- /dev/null +++ b/src/ucp_sdk/models/schemas/shopping/types/payment_schedule.py @@ -0,0 +1,54 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from pydantic import AwareDatetime, BaseModel, ConfigDict + +from ...common.types import amount as amount_1 +from ...common.types import description as description_1 + + +class PaymentSchedule(BaseModel): + """ + A single payment that settles part or all of the checkout under a payment term. Timing is stated in buyer-facing text; `type` and `due_at` are supplementary machine-readable signals derived from it. + """ + + model_config = ConfigDict( + extra="allow", + ) + id: str + """ + Identifier for this payment schedule, unique within its payment term. Businesses SHOULD keep it stable across responses while the schedule remains the same payment. + """ + type: str + """ + Timing class, drawn from an open vocabulary. `immediate` is the only value with defined meaning: the payment is due when the checkout is completed. Any other value means the payment is not due at completion, and `description` states when it is due. Whether a due payment is authorized, captured, or settled at that moment is payment-handler behavior and outside this extension. Businesses MAY use additional values (e.g. `deferred`, `on_shipment`); Platforms MUST treat unrecognized values as not due at completion. + """ + description: description_1.Description + """ + Complete buyer-facing statement of when and how this payment is due. Businesses MUST make this field sufficient on its own: a Platform that recognizes no `type` value and reads no other field MUST be able to present this schedule correctly. Platforms MAY use `type` and `due_at` for enhanced presentation, but MUST NOT present derived timing that contradicts this field. + """ + due_at: AwareDatetime | None = None + """ + Absolute RFC 3339 date-time when this payment is due, when the Business can determine one at checkout. Supplementary to `description`, never a replacement for it. Omitted when the due date depends on a future event (e.g. 'due on delivery'); the timing is then stated in `description` alone. + """ + amount: amount_1.Amount + """ + The amount charged when this payment is taken, inclusive of tax and every other charge, in the Checkout currency's minor units (ISO 4217). A schedule states an amount rather than a totals breakdown: the purchase is priced once at the Checkout, and a schedule moves part or all of that price. Where the selected term changes what the purchase costs, that difference appears in `checkout.totals`, not here. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/payment_term.py b/src/ucp_sdk/models/schemas/shopping/types/payment_term.py new file mode 100644 index 0000000..0f66739 --- /dev/null +++ b/src/ucp_sdk/models/schemas/shopping/types/payment_term.py @@ -0,0 +1,50 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from pydantic import BaseModel, ConfigDict, Field + +from ...common.types import description as description_1 +from . import payment_schedule + + +class PaymentTerm(BaseModel): + """ + A way of paying for the checkout: one or more payment schedules that together cover its total. + """ + + model_config = ConfigDict( + extra="allow", + ) + id: str + """ + Unique identifier for this payment term within the checkout. Referenced by `payment.selected_term_id`. + """ + title: str + """ + Short label that distinguishes this term from its siblings (e.g. 'Pay now', 'Pay in 4', 'Deposit + balance at check-in'). + """ + description: description_1.Description | None = None + """ + Supplementary context for the title (e.g. 'Save 5% by paying today'). Directly renderable; MUST NOT repeat the title. + """ + schedules: list[payment_schedule.PaymentSchedule] = Field(..., min_length=1) + """ + Payment schedules that settle this checkout under this term, in the order they come due. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/product.py b/src/ucp_sdk/models/schemas/shopping/types/product.py index 6fa39d0..57b9363 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/product.py +++ b/src/ucp_sdk/models/schemas/shopping/types/product.py @@ -22,11 +22,10 @@ from pydantic import AnyUrl, BaseModel, ConfigDict, Field -from . import category -from . import description as description_1 -from . import media as media_1 -from . import price_range as price_range_1 -from . import product_option +from ...common.types import description as description_1 +from ...common.types import media as media_1 +from ...common.types import price_range as price_range_1 +from . import category, product_option from . import rating as rating_1 from . import variant diff --git a/src/ucp_sdk/models/schemas/shopping/types/search_filters.py b/src/ucp_sdk/models/schemas/shopping/types/search_filters.py index 6b35cd2..c57be17 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/search_filters.py +++ b/src/ucp_sdk/models/schemas/shopping/types/search_filters.py @@ -20,7 +20,7 @@ from pydantic import BaseModel, ConfigDict -from . import price_filter +from ...common.types import price_filter class SearchFilters(BaseModel): diff --git a/src/ucp_sdk/models/schemas/shopping/types/shipping_destination.py b/src/ucp_sdk/models/schemas/shopping/types/shipping_destination.py index f8b929d..f5abc26 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/shipping_destination.py +++ b/src/ucp_sdk/models/schemas/shopping/types/shipping_destination.py @@ -18,9 +18,11 @@ from __future__ import annotations +from typing import Literal + from pydantic import ConfigDict -from .postal_address import PostalAddress +from ...common.types.postal_address import PostalAddress class ShippingDestination(PostalAddress): @@ -35,3 +37,7 @@ class ShippingDestination(PostalAddress): """ ID specific to this shipping destination. """ + type: Literal["shipping_address"] + """ + Destination type discriminator. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/shipping_destination_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/shipping_destination_create_request.py index b454152..b654698 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/shipping_destination_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/shipping_destination_create_request.py @@ -18,9 +18,13 @@ from __future__ import annotations +from typing import Literal + from pydantic import ConfigDict -from .postal_address_create_request import PostalAddressCreateRequest +from ...common.types.postal_address_create_request import ( + PostalAddressCreateRequest, +) class ShippingDestinationCreateRequest(PostalAddressCreateRequest): @@ -35,3 +39,7 @@ class ShippingDestinationCreateRequest(PostalAddressCreateRequest): """ ID specific to this shipping destination. """ + type: Literal["shipping_address"] | None = None + """ + Destination type discriminator. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/shipping_destination_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/shipping_destination_update_request.py index 3ab1733..c3b5904 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/shipping_destination_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/shipping_destination_update_request.py @@ -18,9 +18,13 @@ from __future__ import annotations +from typing import Literal + from pydantic import ConfigDict -from .postal_address_update_request import PostalAddressUpdateRequest +from ...common.types.postal_address_update_request import ( + PostalAddressUpdateRequest, +) class ShippingDestinationUpdateRequest(PostalAddressUpdateRequest): @@ -35,3 +39,7 @@ class ShippingDestinationUpdateRequest(PostalAddressUpdateRequest): """ ID specific to this shipping destination. """ + type: Literal["shipping_address"] | None = None + """ + Destination type discriminator. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/unit_price.py b/src/ucp_sdk/models/schemas/shopping/types/unit_price.py new file mode 100644 index 0000000..9760096 --- /dev/null +++ b/src/ucp_sdk/models/schemas/shopping/types/unit_price.py @@ -0,0 +1,74 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from typing import Any + +from pydantic import BaseModel, ConfigDict, Field + +from ...common.types import amount as amount_1 +from ...common.types.measure import Measure as Measure_1 + + +class Measure(Measure_1): + """ + Product quantity in packaging/content (for example, a 750 mL bottle), distinct from `quantity_unit`, which defines the sale basis. Its integer `value` MUST be at least 1. + """ + + model_config = ConfigDict( + extra="allow", + ) + value: Any | None = Field(None, ge=1) + + +class Reference(Measure_1): + """ + Denominator for unit price display (for example, per 100 mL or per 1 kg). Its integer `value` MUST be at least 1. + """ + + model_config = ConfigDict( + extra="allow", + ) + value: Any | None = Field(None, ge=1) + + +class UnitPrice(BaseModel): + """ + Price per standard unit of measurement. MAY be omitted when unit pricing does not apply. `unit_price.currency` MUST equal `price.currency`; the comparator MUST NOT perform currency conversion. `measure.unit` and `reference.unit` MUST be identical; cross-unit conversion is not permitted. Their scales MAY differ; each value represents `value × 10^-scale`. + """ + + model_config = ConfigDict( + extra="allow", + ) + amount: amount_1.Amount + """ + Unit price in ISO 4217 minor units. After satisfying the same-unit invariant, the Business MUST compute the comparator as `(price.amount / (measure.value × 10^-measure.scale)) × (reference.value × 10^-reference.scale)` and round it once to ISO 4217 minor units according to its pricing rules. The returned `unit_price.amount` is authoritative; the Platform MUST NOT recompute or substitute its own result. + """ + currency: str = Field(..., pattern="^[A-Z]{3}$") + """ + ISO 4217 currency code. + """ + measure: Measure + """ + Product quantity in packaging/content (for example, a 750 mL bottle), distinct from `quantity_unit`, which defines the sale basis. Its integer `value` MUST be at least 1. + """ + reference: Reference + """ + Denominator for unit price display (for example, per 100 mL or per 1 kg). Its integer `value` MUST be at least 1. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/variant.py b/src/ucp_sdk/models/schemas/shopping/types/variant.py index e45f245..4e93a4c 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/variant.py +++ b/src/ucp_sdk/models/schemas/shopping/types/variant.py @@ -20,16 +20,18 @@ from typing import Any -from pydantic import AnyUrl, BaseModel, ConfigDict, Field - -from . import amount as amount_1 +from pydantic import AnyUrl, BaseModel, ConfigDict + +from ...common.types import description as description_1 +from ...common.types import link +from ...common.types import media as media_1 +from ...common.types import price as price_1 +from ...common.types import quantity_unit as quantity_unit_1 +from . import availability as availability_1 from . import category -from . import description as description_1 -from . import link -from . import media as media_1 -from . import price as price_1 from . import rating as rating_1 from . import selected_option +from . import unit_price as unit_price_1 class Barcode(BaseModel): @@ -46,86 +48,6 @@ class Barcode(BaseModel): """ -class Measure(BaseModel): - """ - Product quantity in packaging (e.g., 750ml bottle). - """ - - model_config = ConfigDict( - extra="allow", - ) - value: float - """ - Package quantity. - """ - unit: str - """ - Unit of measurement. - """ - - -class Reference(BaseModel): - """ - Denominator for unit price display (e.g., per 100ml, per 1kg). - """ - - model_config = ConfigDict( - extra="allow", - ) - value: int - """ - Reference quantity. - """ - unit: str - """ - Unit of measurement. - """ - - -class UnitPrice(BaseModel): - """ - Price per standard unit of measurement. MAY be omitted when unit pricing does not apply. - """ - - model_config = ConfigDict( - extra="allow", - ) - amount: amount_1.Amount - """ - Unit price in ISO 4217 minor units. Business MUST return precomputed unit price value: (variant.price / measure.value) * reference.value. - """ - currency: str = Field(..., pattern="^[A-Z]{3}$") - """ - ISO 4217 currency code. - """ - measure: Measure - """ - Product quantity in packaging (e.g., 750ml bottle). - """ - reference: Reference - """ - Denominator for unit price display (e.g., per 100ml, per 1kg). - """ - - -class Availability(BaseModel): - """ - Variant availability for purchase. - """ - - model_config = ConfigDict( - extra="allow", - ) - available: bool | None = None - """ - Whether this variant can be purchased. See status for fulfillment details. - """ - status: str | None = None - """ - Qualifies available with fulfillment state. Well-known values: `in_stock`, `backorder`, `preorder`, `out_of_stock`, `discontinued`. - """ - - class Seller(BaseModel): """ Optional seller context for this variant. @@ -186,17 +108,21 @@ class Variant(BaseModel): """ price: price_1.Price """ - Current selling price. + Current selling price. Price is the amount per one whole `quantity_unit.unit` (for example, per lb or per hour); when `quantity_unit` is absent, it is per `each`. Line total is `price × quantity × 10^-scale`, computed and rounded once by the Business; `totals` remain authoritative. + """ + quantity_unit: quantity_unit_1.QuantityUnit | None = None + """ + Sale basis this variant's `quantity` is denominated in. The default sale basis is `each`, whose machine identity is (`C62`, 0); `C62` is the UN/CEFACT Rec20 code for one/each. An absent catalog descriptor encodes that default. An `increment` advertises the ordering granularity in steps (for example, `scale` 2 with `increment` 25 sells in 0.25-unit multiples). """ list_price: price_1.Price | None = None """ List price before discounts (for strikethrough display). """ - unit_price: UnitPrice | None = None + unit_price: unit_price_1.UnitPrice | None = None """ - Price per standard unit of measurement. MAY be omitted when unit pricing does not apply. + Price per standard unit of measurement, for shelf-style comparison display. MAY be omitted when unit pricing does not apply. """ - availability: Availability | None = None + availability: availability_1.Availability | None = None """ Variant availability for purchase. """ diff --git a/src/ucp_sdk/models/schemas/transports/__init__.py b/src/ucp_sdk/models/schemas/transports/__init__.py index 1252d6b..421dc21 100644 --- a/src/ucp_sdk/models/schemas/transports/__init__.py +++ b/src/ucp_sdk/models/schemas/transports/__init__.py @@ -15,3 +15,4 @@ # generated by datamodel-codegen # pylint: disable=all # pyformat: disable + diff --git a/src/ucp_sdk/models/schemas/transports/a2a_message.py b/src/ucp_sdk/models/schemas/transports/a2a_message.py new file mode 100644 index 0000000..618f658 --- /dev/null +++ b/src/ucp_sdk/models/schemas/transports/a2a_message.py @@ -0,0 +1,133 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from typing import Annotated, Any, Literal + +from pydantic import AnyUrl, BaseModel, ConfigDict, Field +from typing_extensions import TypeAliasType + +from .jsonrpc import Request, SuccessResponse + + +class Extension(BaseModel): + """ + A2A Agent Card extension advertisement for UCP. + """ + + model_config = ConfigDict( + extra="allow", + ) + uri: AnyUrl + """ + Extension URI. UCP uses its versioned reference URI. + """ + description: str | None = None + params: dict[str, Any] | None = None + """ + Extension parameters such as advertised UCP capabilities. + """ + + +class AgentCard(BaseModel): + """ + A2A Agent Card fragment advertising UCP support through extensions. + """ + + model_config = ConfigDict( + extra="allow", + ) + extensions: list[Extension] = Field(..., min_length=1) + + +class Part(BaseModel): + """ + A2A message part. UCP examples use text parts for natural language and data parts for structured UCP payloads. + """ + + model_config = ConfigDict( + extra="allow", + ) + type: str | None = None + kind: str | None = None + text: str | None = None + data: dict[str, Any] | None = None + """ + Structured data payload. UCP reserves a2a.ucp.* keys for UCP payloads. + """ + + +class Message(BaseModel): + """ + A2A Message carrying natural-language or structured UCP data parts. + """ + + model_config = ConfigDict( + extra="allow", + ) + role: Literal["user", "agent"] + """ + Message sender role. + """ + parts: list[Part] = Field(..., min_length=1) + messageId: str + kind: Literal["message"] + contextId: str + + +class Params(BaseModel): + model_config = ConfigDict( + extra="allow", + ) + message: Message + + +class MessageRequest(Request): + """ + A2A message/send JSON-RPC request whose params carry a UCP-bearing Message from the platform to the business agent. + """ + + model_config = ConfigDict( + extra="allow", + ) + method: Literal["message/send"] | None = None + params: Params + + +class MessageResponse(SuccessResponse): + """ + JSON-RPC success response whose result is an A2A Message from the business agent. + """ + + model_config = ConfigDict( + extra="allow", + ) + result: Message | None = None + + +A2AUcpMessageEnvelope = TypeAliasType( + "A2AUcpMessageEnvelope", + Annotated[ + AgentCard | MessageRequest | MessageResponse, + Field(..., title="A2A UCP Message Envelope"), + ], +) +""" +Minimal A2A envelope shapes used by UCP's A2A checkout binding. This schema validates UCP's transport mapping points — Agent Card extension advertisement, inbound A2A Message requests, and JSON-RPC responses carrying A2A Message results — without attempting to re-specify the full A2A protocol. +""" diff --git a/src/ucp_sdk/models/schemas/transports/embedded_message.py b/src/ucp_sdk/models/schemas/transports/embedded_message.py new file mode 100644 index 0000000..7ffc673 --- /dev/null +++ b/src/ucp_sdk/models/schemas/transports/embedded_message.py @@ -0,0 +1,109 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from typing import Annotated, Any + +from pydantic import ConfigDict, Field, model_validator +from typing_extensions import TypeAliasType + +from . import jsonrpc +from .jsonrpc import Request as Request_1 +from .jsonrpc import SuccessResponse + +Method = TypeAliasType( + "Method", + Annotated[ + str, + Field( + ..., + pattern="^(ec|ep\\.cart)\\.[a-z][a-z0-9_]*(?:\\.[a-z][a-z0-9_]*)*$", + ), + ], +) +""" +Embedded Protocol method name. Checkout methods use ec.* and cart methods use ep.cart.*. +""" + + +class Request(Request_1): + """ + Embedded Protocol request or notification envelope. Messages with id expect a response; messages without id are notifications. + """ + + model_config = ConfigDict( + extra="allow", + ) + method: Method | None = None + params: dict[str, Any] + """ + Capability-specific EP parameters. + """ + + +class Response(SuccessResponse): + """ + Embedded Protocol success response envelope. UCP application-level success and error outcomes are both carried in result.ucp.status. + """ + + model_config = ConfigDict( + extra="allow", + ) + result: dict[str, Any] | None = None + """ + Capability-specific EP result. Application-level status is defined by capability schemas; see Embedded Protocol response handling. + """ + + @model_validator(mode="after") + def _enforce_conditional_required(self): + """JSON Schema if/then: enforce conditionally required fields.""" + rules = [ + { + "discriminator": "has_next_page", + "values": [True], + "required": ["cursor"], + } + ] + for rule in rules: + if getattr(self, rule["discriminator"], None) not in rule["values"]: + continue + for field in rule["required"]: + if field not in self.model_fields_set: + raise ValueError( + f"Field {field!r} is required by a schema condition" + ) + return self + + +ErrorResponse = TypeAliasType("ErrorResponse", jsonrpc.ErrorResponse) +""" +JSON-RPC transport-level error response for EP messages. Application-level failures use the response result with result.ucp.status=error instead. +""" + + +EmbeddedProtocolMessageEnvelope = TypeAliasType( + "EmbeddedProtocolMessageEnvelope", + Annotated[ + Request | Response | ErrorResponse, + Field(..., title="Embedded Protocol Message Envelope"), + ], +) +""" +JSON-RPC envelope for UCP Embedded Protocol (EP) messages exchanged between a host and an embedded context. This schema constrains the shared transport envelope and method namespace while leaving capability-specific params and result payloads to their capability schemas. +""" diff --git a/src/ucp_sdk/models/schemas/transports/jsonrpc.py b/src/ucp_sdk/models/schemas/transports/jsonrpc.py new file mode 100644 index 0000000..f8ffdd3 --- /dev/null +++ b/src/ucp_sdk/models/schemas/transports/jsonrpc.py @@ -0,0 +1,121 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from typing import Annotated, Any, Literal + +from pydantic import BaseModel, ConfigDict, Field +from typing_extensions import TypeAliasType + +Id = TypeAliasType("Id", str | float | None) +""" +JSON-RPC request identifier. Notifications omit id; responses echo the request id, or use null when the request id could not be determined. +""" + + +class Error(BaseModel): + """ + JSON-RPC transport-level error object. UCP business outcomes use result payloads with UCP messages instead of this object. + """ + + model_config = ConfigDict( + extra="allow", + ) + code: int + """ + JSON-RPC error code. Standard codes are negative integers; UCP bindings reserve business errors for UCP messages. + """ + message: str + """ + Short transport-level error description. + """ + data: Any | None = None + """ + Optional machine-readable transport error details. + """ + + +class Request(BaseModel): + """ + JSON-RPC request or notification envelope. Presence of id makes the message a request; absence of id makes it a notification. + """ + + model_config = ConfigDict( + extra="allow", + ) + jsonrpc: Literal["2.0"] + """ + JSON-RPC protocol version. + """ + id: Id | None = None + method: str = Field(..., min_length=1) + """ + Transport method name. Binding-specific schemas constrain the method namespace. + """ + params: dict[str, Any] | list[Any] | None = None + """ + Method parameters. Binding-specific schemas define the object shape. + """ + + +class SuccessResponse(BaseModel): + """ + JSON-RPC success response envelope. + """ + + model_config = ConfigDict( + extra="allow", + ) + jsonrpc: Literal["2.0"] + """ + JSON-RPC protocol version. + """ + id: Id + result: Any + """ + Successful transport result. UCP bindings define the nested result payload. + """ + + +class ErrorResponse(BaseModel): + """ + JSON-RPC transport error response envelope. This is for protocol-level failures, not UCP application-level messages. + """ + + model_config = ConfigDict( + extra="forbid", + ) + jsonrpc: Literal["2.0"] + """ + JSON-RPC protocol version. + """ + id: Id + error: Error + + +JsonRpc20Envelope = TypeAliasType( + "JsonRpc20Envelope", + Annotated[ + Request | SuccessResponse | ErrorResponse, + Field(..., title="JSON-RPC 2.0 Envelope"), + ], +) +""" +Common JSON-RPC 2.0 transport envelope used by UCP JSON-RPC-based bindings. This schema intentionally validates only the protocol envelope; binding-specific params and result payloads are validated by transport-specific schemas or extracted UCP payload schemas. +""" diff --git a/src/ucp_sdk/models/schemas/transports/mcp_tool_call.py b/src/ucp_sdk/models/schemas/transports/mcp_tool_call.py new file mode 100644 index 0000000..6418787 --- /dev/null +++ b/src/ucp_sdk/models/schemas/transports/mcp_tool_call.py @@ -0,0 +1,157 @@ +# Copyright 2026 UCP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# generated by datamodel-codegen +# pylint: disable=all +# pyformat: disable + +from __future__ import annotations + +from typing import Annotated, Any, Literal + +from pydantic import BaseModel, ConfigDict, Field, model_validator +from typing_extensions import TypeAliasType + +from . import jsonrpc +from .jsonrpc import Request as Request_1 +from .jsonrpc import SuccessResponse + + +class UcpAgent(BaseModel): + """ + UCP-Agent metadata carried inside MCP tool arguments. + """ + + model_config = ConfigDict( + extra="allow", + ) + profile: str + """ + Platform profile URI advertised to the business. + """ + + +class Meta(BaseModel): + """ + UCP request metadata passed through MCP params.arguments.meta. + """ + + model_config = ConfigDict( + extra="allow", + ) + ucp_agent: UcpAgent | None = Field(None, alias="ucp-agent") + idempotency_key: str | None = Field(None, alias="idempotency-key") + """ + Optional idempotency key for retry-safe mutating operations. + """ + + +class Arguments(BaseModel): + """ + MCP tool arguments. UCP reserves meta for transport metadata; operation payload fields such as checkout, cart, order id, or catalog inputs are operation-specific. + """ + + model_config = ConfigDict( + extra="allow", + ) + meta: Meta | None = None + + +class Params(BaseModel): + model_config = ConfigDict( + extra="allow", + ) + name: str = Field(..., min_length=1) + """ + MCP tool name matching the UCP operation binding, such as create_checkout or get_cart. + """ + arguments: Arguments + + +class Request(Request_1): + """ + MCP tools/call request envelope for invoking a UCP operation. + """ + + model_config = ConfigDict( + extra="allow", + ) + method: Literal["tools/call"] | None = None + params: Params + + +class ContentPart(BaseModel): + """ + MCP content part returned for clients that do not consume structuredContent. + """ + + model_config = ConfigDict( + extra="allow", + ) + type: str + text: str | None = None + + +class Result(BaseModel): + model_config = ConfigDict( + extra="allow", + ) + structuredContent: dict[str, Any] + """ + The UCP response payload for the operation. + """ + content: list[ContentPart] | None = None + + +class Response(SuccessResponse): + """ + MCP tools/call response envelope. UCP payloads are carried in result.structuredContent; content is compatibility output. + """ + + model_config = ConfigDict( + extra="allow", + ) + result: Result | None = None + + @model_validator(mode="after") + def _enforce_conditional_required(self): + """JSON Schema if/then: enforce conditionally required fields.""" + rules = [ + { + "discriminator": "has_next_page", + "values": [True], + "required": ["cursor"], + } + ] + for rule in rules: + if getattr(self, rule["discriminator"], None) not in rule["values"]: + continue + for field in rule["required"]: + if field not in self.model_fields_set: + raise ValueError( + f"Field {field!r} is required by a schema condition" + ) + return self + + +McpToolCallEnvelope = TypeAliasType( + "McpToolCallEnvelope", + Annotated[ + Request | Response | jsonrpc.ErrorResponse, + Field(..., title="MCP Tool Call Envelope"), + ], +) +""" +UCP's MCP transport envelope for JSON-RPC tools/call messages. The schema validates the MCP mapping layer: operation name in params.name, UCP metadata and domain arguments in params.arguments, and UCP output in result.structuredContent. +""" diff --git a/src/ucp_sdk/models/schemas/ucp.py b/src/ucp_sdk/models/schemas/ucp.py index 373f7a9..15e3acf 100644 --- a/src/ucp_sdk/models/schemas/ucp.py +++ b/src/ucp_sdk/models/schemas/ucp.py @@ -24,13 +24,14 @@ from typing_extensions import TypeAliasType from . import capability, payment_handler, service -from .shopping.types import reverse_domain_name +from .common.types import request_constraints as request_constraints_1 +from .common.types import reverse_domain_name Version = TypeAliasType( "Version", Annotated[str, Field(..., pattern="^\\d{4}-\\d{2}-\\d{2}$")] ) """ -UCP version in YYYY-MM-DD format. +Version identifier in YYYY-MM-DD format. """ @@ -62,7 +63,7 @@ class Requires(BaseModel): ) protocol: VersionConstraint | None = None """ - Required protocol version. + Required range for the selected `ucp.version`. """ capabilities: ( dict[reverse_domain_name.ReverseDomainName, VersionConstraint] | None @@ -72,6 +73,12 @@ class Requires(BaseModel): """ +MapOrder = TypeAliasType("MapOrder", dict[str, list[str]]) +""" +Preferred key order for map-valued fields in the scope annotated by the containing `ucp` member. Each property names a target map, and its array lists target keys in preferred order. Lists may be partial and are not allowlists. +""" + + class Entity(BaseModel): """ Shared foundation for all UCP entities. @@ -102,6 +109,18 @@ class Entity(BaseModel): """ +class Members(BaseModel): + """ + Members defined inside the reserved `ucp` protocol object. The object is open for forward compatibility: consumers MUST ignore unrecognized members. Only UCP core defines members, and every defined member MUST be safe to ignore. + """ + + model_config = ConfigDict( + extra="allow", + ) + map_order: MapOrder | None = None + request_constraints: request_constraints_1.RequestConstraints | None = None + + class Base(BaseModel): """ Base UCP metadata with shared properties for all schema types. @@ -111,6 +130,10 @@ class Base(BaseModel): extra="allow", ) version: Version + map_order: MapOrder | None = None + """ + Preferred key-traversal order for sibling registry fields inside the root `ucp` envelope (`services`, `capabilities`, and `payment_handlers`). + """ status: Literal["success", "error"] | None = "success" """ Application-level status of the UCP operation. @@ -174,7 +197,7 @@ class PlatformSchema(Base): extra="allow", ) services: dict[ - reverse_domain_name.ReverseDomainName, list[service.PlatformSchema5] + reverse_domain_name.ReverseDomainName, list[service.PlatformSchema6] ] """ Service registry keyed by reverse-domain name. @@ -211,7 +234,7 @@ class BusinessSchema(Base): Previous protocol versions this business supports, mapped to profile URIs. Businesses that support older protocol versions SHOULD advertise each version and link to its profile. Each URI points to a complete, self-contained profile for that version. When omitted, only `version` is supported. """ services: dict[ - reverse_domain_name.ReverseDomainName, list[service.BusinessSchema2] + reverse_domain_name.ReverseDomainName, list[service.BusinessSchema3] ] """ Service registry keyed by reverse-domain name. diff --git a/src/ucp_sdk/models/schemas/ucp_create_request.py b/src/ucp_sdk/models/schemas/ucp_create_request.py index bba6e04..3336fd6 100644 --- a/src/ucp_sdk/models/schemas/ucp_create_request.py +++ b/src/ucp_sdk/models/schemas/ucp_create_request.py @@ -24,13 +24,14 @@ from typing_extensions import TypeAliasType from . import capability, payment_handler, service -from .shopping.types import reverse_domain_name_create_request +from .common.types import request_constraints as request_constraints_1 +from .common.types import reverse_domain_name_create_request Version = TypeAliasType( "Version", Annotated[str, Field(..., pattern="^\\d{4}-\\d{2}-\\d{2}$")] ) """ -UCP version in YYYY-MM-DD format. +Version identifier in YYYY-MM-DD format. """ @@ -62,7 +63,7 @@ class Requires(BaseModel): ) protocol: VersionConstraint | None = None """ - Required protocol version. + Required range for the selected `ucp.version`. """ capabilities: ( dict[ @@ -76,6 +77,12 @@ class Requires(BaseModel): """ +MapOrder = TypeAliasType("MapOrder", dict[str, list[str]]) +""" +Preferred key order for map-valued fields in the scope annotated by the containing `ucp` member. Each property names a target map, and its array lists target keys in preferred order. Lists may be partial and are not allowlists. +""" + + class Entity(BaseModel): """ Shared foundation for all UCP entities. @@ -106,6 +113,18 @@ class Entity(BaseModel): """ +class Members(BaseModel): + """ + Members defined inside the reserved `ucp` protocol object. The object is open for forward compatibility: consumers MUST ignore unrecognized members. Only UCP core defines members, and every defined member MUST be safe to ignore. + """ + + model_config = ConfigDict( + extra="allow", + ) + map_order: MapOrder | None = None + request_constraints: request_constraints_1.RequestConstraints | None = None + + class Base(BaseModel): """ Base UCP metadata with shared properties for all schema types. @@ -115,6 +134,10 @@ class Base(BaseModel): extra="allow", ) version: Version + map_order: MapOrder | None = None + """ + Preferred key-traversal order for sibling registry fields inside the root `ucp` envelope (`services`, `capabilities`, and `payment_handlers`). + """ status: Literal["success", "error"] | None = "success" """ Application-level status of the UCP operation. @@ -189,7 +212,7 @@ class PlatformSchema(Base): ) services: dict[ reverse_domain_name_create_request.ReverseDomainNameCreateRequest, - list[service.PlatformSchema5], + list[service.PlatformSchema6], ] """ Service registry keyed by reverse-domain name. @@ -227,7 +250,7 @@ class BusinessSchema(Base): """ services: dict[ reverse_domain_name_create_request.ReverseDomainNameCreateRequest, - list[service.BusinessSchema2], + list[service.BusinessSchema3], ] """ Service registry keyed by reverse-domain name. diff --git a/src/ucp_sdk/models/schemas/ucp_update_request.py b/src/ucp_sdk/models/schemas/ucp_update_request.py index 698fc4e..6653e6f 100644 --- a/src/ucp_sdk/models/schemas/ucp_update_request.py +++ b/src/ucp_sdk/models/schemas/ucp_update_request.py @@ -24,13 +24,14 @@ from typing_extensions import TypeAliasType from . import capability, payment_handler, service -from .shopping.types import reverse_domain_name_update_request +from .common.types import request_constraints as request_constraints_1 +from .common.types import reverse_domain_name_update_request Version = TypeAliasType( "Version", Annotated[str, Field(..., pattern="^\\d{4}-\\d{2}-\\d{2}$")] ) """ -UCP version in YYYY-MM-DD format. +Version identifier in YYYY-MM-DD format. """ @@ -62,7 +63,7 @@ class Requires(BaseModel): ) protocol: VersionConstraint | None = None """ - Required protocol version. + Required range for the selected `ucp.version`. """ capabilities: ( dict[ @@ -76,6 +77,12 @@ class Requires(BaseModel): """ +MapOrder = TypeAliasType("MapOrder", dict[str, list[str]]) +""" +Preferred key order for map-valued fields in the scope annotated by the containing `ucp` member. Each property names a target map, and its array lists target keys in preferred order. Lists may be partial and are not allowlists. +""" + + class Entity(BaseModel): """ Shared foundation for all UCP entities. @@ -106,6 +113,18 @@ class Entity(BaseModel): """ +class Members(BaseModel): + """ + Members defined inside the reserved `ucp` protocol object. The object is open for forward compatibility: consumers MUST ignore unrecognized members. Only UCP core defines members, and every defined member MUST be safe to ignore. + """ + + model_config = ConfigDict( + extra="allow", + ) + map_order: MapOrder | None = None + request_constraints: request_constraints_1.RequestConstraints | None = None + + class Base(BaseModel): """ Base UCP metadata with shared properties for all schema types. @@ -115,6 +134,10 @@ class Base(BaseModel): extra="allow", ) version: Version + map_order: MapOrder | None = None + """ + Preferred key-traversal order for sibling registry fields inside the root `ucp` envelope (`services`, `capabilities`, and `payment_handlers`). + """ status: Literal["success", "error"] | None = "success" """ Application-level status of the UCP operation. @@ -189,7 +212,7 @@ class PlatformSchema(Base): ) services: dict[ reverse_domain_name_update_request.ReverseDomainNameUpdateRequest, - list[service.PlatformSchema5], + list[service.PlatformSchema6], ] """ Service registry keyed by reverse-domain name. @@ -227,7 +250,7 @@ class BusinessSchema(Base): """ services: dict[ reverse_domain_name_update_request.ReverseDomainNameUpdateRequest, - list[service.BusinessSchema2], + list[service.BusinessSchema3], ] """ Service registry keyed by reverse-domain name. From 7e6a34f43d2ba6824e9c3c94d10d91c7aaf93b66 Mon Sep 17 00:00:00 2001 From: Ryan Conigliaro Date: Mon, 24 Aug 2026 21:30:00 -0400 Subject: [PATCH 2/6] adding test case --- tests/test_codegen_pipeline.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/test_codegen_pipeline.py b/tests/test_codegen_pipeline.py index e708e3e..da00eb7 100644 --- a/tests/test_codegen_pipeline.py +++ b/tests/test_codegen_pipeline.py @@ -55,6 +55,27 @@ class SchemaNormalizationTest(unittest.TestCase): """Tests schema flattening and reference normalization.""" + def test_iter_nodes_expands_properties_without_yielding_container( + self, + ) -> None: + """iter_nodes yields "properties" map values directly rather than the "properties" map as a container. Avoids traversal of property names that match json schema keywords.""" + schema = { + "type": "object", + "properties": { + "user": {"type": "string", "$ref": "user.json"}, + "allOf": {"type": "object"}, + }, + } + nodes = list(preprocess_schemas.iter_nodes(schema)) + + # The root object is yielded + self.assertIn(schema, nodes) + # The property subschemas are yielded + self.assertIn(schema["properties"]["user"], nodes) + self.assertIn(schema["properties"]["allOf"], nodes) + # The container map {"user": ..., "allOf": ...} itself is NOT yielded + self.assertNotIn(schema["properties"], nodes) + def test_resolve_local_ref_supports_objects_and_arrays(self) -> None: """Local JSON pointers resolve object keys and array indexes.""" schema = {"$defs": {"choices": [{"const": "first"}]}} From c1d1c898fbfad4c3fdab5db1f9c7ed6cbd26cbbd Mon Sep 17 00:00:00 2001 From: Ryan Conigliaro Date: Tue, 25 Aug 2026 14:56:57 -0400 Subject: [PATCH 3/6] running generate mocdles with latest version isntead of draft --- src/ucp_sdk/models/schemas/capability.py | 74 ++++- .../models/schemas/common/identity_linking.py | 18 +- src/ucp_sdk/models/schemas/common/loyalty.py | 297 ------------------ .../models/schemas/common/types/__init__.py | 18 -- .../models/schemas/common/types/actions.py | 56 ---- .../models/schemas/common/types/binding.py | 41 --- .../common/types/constraint_expression.py | 101 ------ .../models/schemas/common/types/locality.py | 43 --- .../common/types/locality_create_request.py | 43 --- .../common/types/locality_update_request.py | 43 --- .../models/schemas/common/types/measure.py | 37 --- .../common/types/measure_create_request.py | 37 --- .../common/types/measure_update_request.py | 37 --- .../models/schemas/common/types/policy.py | 50 --- .../schemas/common/types/quantity_unit.py | 37 --- .../types/quantity_unit_create_request.py | 37 --- .../types/quantity_unit_update_request.py | 37 --- .../common/types/request_constraints.py | 72 ----- .../models/schemas/common/types/unit.py | 43 --- .../common/types/unit_create_request.py | 43 --- .../common/types/unit_update_request.py | 43 --- src/ucp_sdk/models/schemas/profile.py | 127 -------- src/ucp_sdk/models/schemas/service.py | 26 +- .../models/schemas/shopping/buyer_consent.py | 86 +---- src/ucp_sdk/models/schemas/shopping/cart.py | 18 +- .../schemas/shopping/cart_create_request.py | 3 +- .../schemas/shopping/cart_update_request.py | 7 +- .../models/schemas/shopping/catalog_lookup.py | 63 ++-- .../models/schemas/shopping/catalog_search.py | 18 +- .../models/schemas/shopping/checkout.py | 20 +- .../shopping/checkout_complete_request.py | 3 +- .../shopping/checkout_create_request.py | 3 +- .../shopping/checkout_update_request.py | 3 +- .../models/schemas/shopping/discount.py | 4 +- .../models/schemas/shopping/fulfillment.py | 202 +----------- src/ucp_sdk/models/schemas/shopping/order.py | 9 +- .../schemas/shopping/order_create_request.py | 3 +- .../schemas/shopping/order_update_request.py | 3 +- .../shopping/payment_authentication.py | 101 ------ .../models/schemas/shopping/payment_terms.py | 99 ------ .../models/schemas/shopping/permalink.py | 52 --- .../models/schemas/shopping/split_payments.py | 80 ----- .../types/account_info.py} | 8 +- .../schemas/shopping/types/adjustment.py | 13 +- .../types/adjustment_create_request.py | 12 +- .../types/adjustment_update_request.py | 12 +- .../{common => shopping}/types/amount.py | 3 +- .../types/available_payment_instrument.py | 8 +- .../types/{availability.py => binding.py} | 14 +- .../types/business_fulfillment_config.py | 28 +- .../types/business_split_payments_config.py | 48 --- .../schemas/shopping/types/card_credential.py | 4 +- .../shopping/types/card_payment_instrument.py | 45 ++- .../{common => shopping}/types/context.py | 33 +- .../types/context_create_request.py | 33 +- .../types/context_update_request.py | 33 +- .../{common => shopping}/types/description.py | 0 .../{common => shopping}/types/error_code.py | 2 +- .../types/error_code_create_request.py | 2 +- .../types/error_code_update_request.py | 2 +- .../types/error_response.py | 0 .../schemas/shopping/types/expectation.py | 12 +- .../types/expectation_create_request.py | 12 +- .../types/expectation_update_request.py | 12 +- .../types/fulfillment_available_method.py | 6 +- .../shopping/types/fulfillment_destination.py | 31 +- .../fulfillment_destination_create_request.py | 34 +- .../types/fulfillment_destination_filter.py | 37 --- .../fulfillment_destination_update_request.py | 34 +- .../shopping/types/fulfillment_event.py | 4 +- .../types/fulfillment_event_create_request.py | 4 +- .../types/fulfillment_event_update_request.py | 4 +- .../shopping/types/fulfillment_method.py | 12 +- .../fulfillment_method_create_request.py | 28 +- .../fulfillment_method_update_request.py | 24 +- .../shopping/types/fulfillment_option.py | 21 +- .../fulfillment_option_base_update_request.py | 31 -- .../fulfillment_option_create_request.py | 10 +- .../fulfillment_option_update_request.py | 10 +- .../{common => shopping}/types/info_code.py | 2 +- .../types/info_code_create_request.py | 2 +- .../types/info_code_update_request.py | 2 +- .../shopping/types/instrument_group.py | 43 --- .../models/schemas/shopping/types/item.py | 14 +- .../shopping/types/item_create_request.py | 8 - .../shopping/types/item_update_request.py | 8 - .../schemas/shopping/types/line_item.py | 6 +- .../types/line_item_create_request.py | 4 +- .../types/line_item_update_request.py | 4 +- .../{common => shopping}/types/link.py | 0 .../shopping/types/location_destination.py | 39 --- .../location_destination_create_request.py | 35 --- .../location_destination_update_request.py | 35 --- .../{common => shopping}/types/media.py | 2 +- ...base.py => merchant_fulfillment_config.py} | 38 ++- .../{common => shopping}/types/message.py | 0 .../types/message_create_request.py | 0 .../types/message_error.py | 4 +- .../types/message_error_create_request.py | 4 +- .../types/message_error_update_request.py | 4 +- .../types/message_info.py | 2 +- .../types/message_info_create_request.py | 2 +- .../types/message_info_update_request.py | 2 +- .../types/message_update_request.py | 0 .../types/message_warning.py | 2 +- .../types/message_warning_create_request.py | 2 +- .../types/message_warning_update_request.py | 2 +- .../types/network_token_credential.py | 67 ---- .../schemas/shopping/types/order_line_item.py | 20 +- .../types/order_line_item_create_request.py | 21 +- .../types/order_line_item_update_request.py | 21 +- .../{common => shopping}/types/pagination.py | 0 .../schemas/shopping/types/pan_credential.py | 59 ---- .../shopping/types/payment_identity.py | 2 +- .../shopping/types/payment_instrument.py | 5 +- .../payment_instrument_complete_request.py | 8 +- .../payment_instrument_create_request.py | 5 +- .../payment_instrument_update_request.py | 5 +- .../shopping/types/payment_schedule.py | 54 ---- .../schemas/shopping/types/payment_term.py | 50 --- .../types/postal_address.py | 0 .../types/postal_address_complete_request.py | 0 .../types/postal_address_create_request.py | 0 .../types/postal_address_update_request.py | 0 .../{common => shopping}/types/price.py | 0 .../types/price_filter.py | 0 .../{common => shopping}/types/price_range.py | 2 +- .../models/schemas/shopping/types/product.py | 9 +- .../types/retail_location.py} | 8 +- .../types/retail_location_create_request.py} | 16 +- ...t.py => retail_location_update_request.py} | 16 +- .../types/reverse_domain_name.py | 13 +- .../reverse_domain_name_create_request.py | 13 +- .../reverse_domain_name_update_request.py | 13 +- .../schemas/shopping/types/search_filters.py | 2 +- .../shopping/types/shipping_destination.py | 8 +- .../shipping_destination_create_request.py | 10 +- .../shipping_destination_update_request.py | 10 +- .../{common => shopping}/types/signals.py | 2 +- .../types/signals_complete_request.py | 2 +- .../types/signals_create_request.py | 2 +- .../types/signals_update_request.py | 2 +- .../types/signed_amount.py | 11 +- .../types/signed_amount_create_request.py | 10 +- .../types/signed_amount_update_request.py | 10 +- .../{common => shopping}/types/total.py | 0 .../types/total_create_request.py | 0 .../types/total_update_request.py | 0 .../{common => shopping}/types/totals.py | 0 .../types/totals_create_request.py | 0 .../types/totals_update_request.py | 0 .../schemas/shopping/types/unit_price.py | 74 ----- .../models/schemas/shopping/types/variant.py | 108 ++++++- .../types/warning_code.py | 3 +- .../types/warning_code_create_request.py | 3 +- .../types/warning_code_update_request.py | 3 +- .../models/schemas/transports/a2a_message.py | 133 -------- .../schemas/transports/embedded_message.py | 109 ------- .../models/schemas/transports/jsonrpc.py | 121 ------- .../schemas/transports/mcp_tool_call.py | 157 --------- src/ucp_sdk/models/schemas/ucp.py | 33 +- .../models/schemas/ucp_create_request.py | 33 +- .../models/schemas/ucp_update_request.py | 33 +- tests/test_codegen_pipeline.py | 3 +- 164 files changed, 683 insertions(+), 3635 deletions(-) delete mode 100644 src/ucp_sdk/models/schemas/common/loyalty.py delete mode 100644 src/ucp_sdk/models/schemas/common/types/__init__.py delete mode 100644 src/ucp_sdk/models/schemas/common/types/actions.py delete mode 100644 src/ucp_sdk/models/schemas/common/types/binding.py delete mode 100644 src/ucp_sdk/models/schemas/common/types/constraint_expression.py delete mode 100644 src/ucp_sdk/models/schemas/common/types/locality.py delete mode 100644 src/ucp_sdk/models/schemas/common/types/locality_create_request.py delete mode 100644 src/ucp_sdk/models/schemas/common/types/locality_update_request.py delete mode 100644 src/ucp_sdk/models/schemas/common/types/measure.py delete mode 100644 src/ucp_sdk/models/schemas/common/types/measure_create_request.py delete mode 100644 src/ucp_sdk/models/schemas/common/types/measure_update_request.py delete mode 100644 src/ucp_sdk/models/schemas/common/types/policy.py delete mode 100644 src/ucp_sdk/models/schemas/common/types/quantity_unit.py delete mode 100644 src/ucp_sdk/models/schemas/common/types/quantity_unit_create_request.py delete mode 100644 src/ucp_sdk/models/schemas/common/types/quantity_unit_update_request.py delete mode 100644 src/ucp_sdk/models/schemas/common/types/request_constraints.py delete mode 100644 src/ucp_sdk/models/schemas/common/types/unit.py delete mode 100644 src/ucp_sdk/models/schemas/common/types/unit_create_request.py delete mode 100644 src/ucp_sdk/models/schemas/common/types/unit_update_request.py delete mode 100644 src/ucp_sdk/models/schemas/profile.py delete mode 100644 src/ucp_sdk/models/schemas/shopping/payment_authentication.py delete mode 100644 src/ucp_sdk/models/schemas/shopping/payment_terms.py delete mode 100644 src/ucp_sdk/models/schemas/shopping/permalink.py delete mode 100644 src/ucp_sdk/models/schemas/shopping/split_payments.py rename src/ucp_sdk/models/schemas/{common/types/location_summary_update_request.py => shopping/types/account_info.py} (74%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/amount.py (91%) rename src/ucp_sdk/models/schemas/shopping/types/{availability.py => binding.py} (61%) delete mode 100644 src/ucp_sdk/models/schemas/shopping/types/business_split_payments_config.py rename src/ucp_sdk/models/schemas/{common => shopping}/types/context.py (72%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/context_create_request.py (68%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/context_update_request.py (68%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/description.py (100%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/error_code.py (92%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/error_code_create_request.py (92%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/error_code_update_request.py (92%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/error_response.py (100%) delete mode 100644 src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination_filter.py delete mode 100644 src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_base_update_request.py rename src/ucp_sdk/models/schemas/{common => shopping}/types/info_code.py (90%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/info_code_create_request.py (90%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/info_code_update_request.py (90%) delete mode 100644 src/ucp_sdk/models/schemas/shopping/types/instrument_group.py rename src/ucp_sdk/models/schemas/{common => shopping}/types/link.py (100%) delete mode 100644 src/ucp_sdk/models/schemas/shopping/types/location_destination.py delete mode 100644 src/ucp_sdk/models/schemas/shopping/types/location_destination_create_request.py delete mode 100644 src/ucp_sdk/models/schemas/shopping/types/location_destination_update_request.py rename src/ucp_sdk/models/schemas/{common => shopping}/types/media.py (96%) rename src/ucp_sdk/models/schemas/shopping/types/{fulfillment_option_base.py => merchant_fulfillment_config.py} (54%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/message.py (100%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/message_create_request.py (100%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/message_error.py (71%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/message_error_create_request.py (72%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/message_error_update_request.py (72%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/message_info.py (93%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/message_info_create_request.py (93%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/message_info_update_request.py (93%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/message_update_request.py (100%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/message_warning.py (95%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/message_warning_create_request.py (95%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/message_warning_update_request.py (95%) delete mode 100644 src/ucp_sdk/models/schemas/shopping/types/network_token_credential.py rename src/ucp_sdk/models/schemas/{common => shopping}/types/pagination.py (100%) delete mode 100644 src/ucp_sdk/models/schemas/shopping/types/pan_credential.py delete mode 100644 src/ucp_sdk/models/schemas/shopping/types/payment_schedule.py delete mode 100644 src/ucp_sdk/models/schemas/shopping/types/payment_term.py rename src/ucp_sdk/models/schemas/{common => shopping}/types/postal_address.py (100%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/postal_address_complete_request.py (100%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/postal_address_create_request.py (100%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/postal_address_update_request.py (100%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/price.py (100%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/price_filter.py (100%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/price_range.py (92%) rename src/ucp_sdk/models/schemas/{common/types/location_summary.py => shopping/types/retail_location.py} (85%) rename src/ucp_sdk/models/schemas/{common/types/location_summary_create_request.py => shopping/types/retail_location_create_request.py} (70%) rename src/ucp_sdk/models/schemas/shopping/types/{fulfillment_option_base_create_request.py => retail_location_update_request.py} (68%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/reverse_domain_name.py (57%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/reverse_domain_name_create_request.py (58%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/reverse_domain_name_update_request.py (58%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/signals.py (95%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/signals_complete_request.py (95%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/signals_create_request.py (95%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/signals_update_request.py (95%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/signed_amount.py (84%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/signed_amount_create_request.py (85%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/signed_amount_update_request.py (85%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/total.py (100%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/total_create_request.py (100%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/total_update_request.py (100%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/totals.py (100%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/totals_create_request.py (100%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/totals_update_request.py (100%) delete mode 100644 src/ucp_sdk/models/schemas/shopping/types/unit_price.py rename src/ucp_sdk/models/schemas/{common => shopping}/types/warning_code.py (88%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/warning_code_create_request.py (88%) rename src/ucp_sdk/models/schemas/{common => shopping}/types/warning_code_update_request.py (88%) delete mode 100644 src/ucp_sdk/models/schemas/transports/a2a_message.py delete mode 100644 src/ucp_sdk/models/schemas/transports/embedded_message.py delete mode 100644 src/ucp_sdk/models/schemas/transports/jsonrpc.py delete mode 100644 src/ucp_sdk/models/schemas/transports/mcp_tool_call.py diff --git a/src/ucp_sdk/models/schemas/capability.py b/src/ucp_sdk/models/schemas/capability.py index 3538563..1a53ae0 100644 --- a/src/ucp_sdk/models/schemas/capability.py +++ b/src/ucp_sdk/models/schemas/capability.py @@ -23,8 +23,6 @@ from pydantic import AnyUrl, BaseModel, ConfigDict, Field from typing_extensions import TypeAliasType -from .common.types import reverse_domain_name - UcpCapability = TypeAliasType( "UcpCapability", Annotated[Any, Field(..., title="UCP Capability")] ) @@ -36,7 +34,7 @@ Extends = TypeAliasType( "Extends", Annotated[ - list[reverse_domain_name.ReverseDomainName], Field(..., min_length=1) + str, Field(..., pattern="^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$") ], ) """ @@ -44,6 +42,22 @@ """ +Extends1Item = TypeAliasType( + "Extends1Item", + Annotated[ + str, Field(..., pattern="^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$") + ], +) + + +Extends1 = TypeAliasType( + "Extends1", Annotated[list[Extends1Item], Field(..., min_length=1)] +) +""" +Parent capability(s) this extends. Present for extensions, absent for root capabilities. Use array for multi-parent extensions. +""" + + class Base(BaseModel): model_config = ConfigDict( extra="allow", @@ -68,12 +82,26 @@ class Base(BaseModel): """ Entity-specific configuration. Structure defined by each entity's schema. """ - extends: reverse_domain_name.ReverseDomainName | Extends | None = None + extends: Extends | Extends1 | None = None """ Parent capability(s) this extends. Present for extensions, absent for root capabilities. Use array for multi-parent extensions. """ +Extends2 = TypeAliasType("Extends2", Extends) + + +Extends3Item = TypeAliasType("Extends3Item", Extends1Item) + + +Extends3 = TypeAliasType( + "Extends3", Annotated[list[Extends3Item], Field(..., min_length=1)] +) +""" +Parent capability(s) this extends. Present for extensions, absent for root capabilities. Use array for multi-parent extensions. +""" + + class PlatformSchema(BaseModel): """ Full capability declaration for platform-level discovery. Includes spec/schema URLs for agent fetching. @@ -102,15 +130,29 @@ class PlatformSchema(BaseModel): """ Entity-specific configuration. Structure defined by each entity's schema. """ - extends: reverse_domain_name.ReverseDomainName | Extends | None = None + extends: Extends2 | Extends3 | None = None """ Parent capability(s) this extends. Present for extensions, absent for root capabilities. Use array for multi-parent extensions. """ +Extends4 = TypeAliasType("Extends4", Extends) + + +Extends5Item = TypeAliasType("Extends5Item", Extends1Item) + + +Extends5 = TypeAliasType( + "Extends5", Annotated[list[Extends5Item], Field(..., min_length=1)] +) +""" +Parent capability(s) this extends. Present for extensions, absent for root capabilities. Use array for multi-parent extensions. +""" + + class BusinessSchema(BaseModel): """ - Capability declaration for business/merchant discovery. Requires the `schema` URL so platforms can fetch and compose it during negotiation; may also include business-specific config overrides. + Capability configuration for business/merchant level. May include business-specific config overrides. """ model_config = ConfigDict( @@ -124,7 +166,7 @@ class BusinessSchema(BaseModel): """ URL to human-readable specification document. """ - schema_: AnyUrl = Field(..., alias="schema") + schema_: AnyUrl | None = Field(None, alias="schema") """ URL to JSON Schema defining this entity's structure and payloads. """ @@ -136,12 +178,26 @@ class BusinessSchema(BaseModel): """ Entity-specific configuration. Structure defined by each entity's schema. """ - extends: reverse_domain_name.ReverseDomainName | Extends | None = None + extends: Extends4 | Extends5 | None = None """ Parent capability(s) this extends. Present for extensions, absent for root capabilities. Use array for multi-parent extensions. """ +Extends6 = TypeAliasType("Extends6", Extends) + + +Extends7Item = TypeAliasType("Extends7Item", Extends1Item) + + +Extends7 = TypeAliasType( + "Extends7", Annotated[list[Extends7Item], Field(..., min_length=1)] +) +""" +Parent capability(s) this extends. Present for extensions, absent for root capabilities. Use array for multi-parent extensions. +""" + + class ResponseSchema(BaseModel): """ Capability reference in responses. Only name/version required to confirm active capabilities. @@ -170,7 +226,7 @@ class ResponseSchema(BaseModel): """ Entity-specific configuration. Structure defined by each entity's schema. """ - extends: reverse_domain_name.ReverseDomainName | Extends | None = None + extends: Extends6 | Extends7 | None = None """ Parent capability(s) this extends. Present for extensions, absent for root capabilities. Use array for multi-parent extensions. """ diff --git a/src/ucp_sdk/models/schemas/common/identity_linking.py b/src/ucp_sdk/models/schemas/common/identity_linking.py index aebf51c..5b32ea4 100644 --- a/src/ucp_sdk/models/schemas/common/identity_linking.py +++ b/src/ucp_sdk/models/schemas/common/identity_linking.py @@ -23,7 +23,7 @@ from pydantic import BaseModel, ConfigDict, Field from typing_extensions import TypeAliasType -from .types import description as description_1 +from ..shopping.types import description as description_1 IdentityLinking = TypeAliasType( "IdentityLinking", Annotated[Any, Field(..., title="Identity Linking")] @@ -53,7 +53,7 @@ class ScopePolicy(BaseModel): str, Field( ..., - pattern="^[a-z](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9_])?)+:[a-z][a-z0-9_]*$", + pattern="^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+:[a-z][a-z0-9_]*$", ), ], ) @@ -62,18 +62,4 @@ class ScopePolicy(BaseModel): """ -class Provider(BaseModel): - """ - A trusted identity provider for delegated authentication, keyed by the 'type' discriminator. 'oauth2' denotes an OAuth 2.0 / OIDC authorization server. Future versions MAY define additional types (e.g. wallet attestation) as non-breaking extensions; platforms MUST treat entries whose 'type' they do not support as filtered out (see Provider Selection). - """ - - model_config = ConfigDict( - extra="allow", - ) - type: str - """ - Provider mechanism discriminator. 'oauth2' for OAuth 2.0 / OIDC authorization servers. Additional values MAY be defined by future versions; the value is an open string, not a closed enum, so unrecognized types remain valid and are filtered at runtime. - """ - - IdentityLinking1 = TypeAliasType("IdentityLinking1", Any) diff --git a/src/ucp_sdk/models/schemas/common/loyalty.py b/src/ucp_sdk/models/schemas/common/loyalty.py deleted file mode 100644 index 009222d..0000000 --- a/src/ucp_sdk/models/schemas/common/loyalty.py +++ /dev/null @@ -1,297 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from typing import Annotated, Any - -from pydantic import BaseModel, ConfigDict, Field -from typing_extensions import TypeAliasType - -from ..shopping.cart import Cart as Cart_1 -from ..shopping.catalog_lookup import GetProductResponse, LookupResponse -from ..shopping.catalog_search import SearchResponse -from ..shopping.checkout import Checkout as Checkout_1 -from .types import reverse_domain_name - -LoyaltyExtension = TypeAliasType( - "LoyaltyExtension", Annotated[Any, Field(..., title="Loyalty Extension")] -) -""" -Extends various Capabilities with loyalty support using memberships info. -""" - - -RewardAmount = TypeAliasType("RewardAmount", Annotated[int, Field(..., ge=0)]) -""" -Non-negative integer amount denominated in the minor unit of the associated reward currency. The associated reward currency's `decimal_places` defines the minor-to-major ratio and defaults to 0 when omitted. -""" - - -class EarningBreakdown(BaseModel): - """ - Breakdown rule of the reward earnings - """ - - model_config = ConfigDict( - extra="allow", - ) - id: str - """ - Unique rewards breakdown rule identifier. - """ - amount: RewardAmount - """ - Rewards earned from this rule. - """ - description: str - """ - A display-ready, human-readable rationale for the specific rewards (e.g. 2x on footwear). - """ - benefit_id: str | None = None - """ - Optional `id` of the membership_tier_benefit that produced this rewards rule. Resolves against `membership_tier_benefit.id` within the same parent loyalty membership. - """ - - -class EarningForecast(BaseModel): - """ - Preview of rewards to be earned from the current transaction. - """ - - model_config = ConfigDict( - extra="allow", - ) - amount: RewardAmount - """ - Total rewards to be earned if the transaction completes. - """ - breakdown: list[EarningBreakdown] | None = None - """ - List of breakdown of earning contributing to the total. - """ - - -class RewardCurrency(BaseModel): - """ - The currency of the loyalty reward. - """ - - model_config = ConfigDict( - extra="allow", - ) - name: str - """ - Human-readable name of the currency (e.g. 'LoyaltyStars'). - """ - code: str - """ - Business-specific representation of the currency (e.g. 'LST'). - """ - decimal_places: int | None = Field(0, ge=0) - """ - The position of a digit to the right of a decimal point. Applies to all amount related fields for rewards. - """ - - -class Currency(BaseModel): - """ - A unit of value that customers can accumulate through various commercial activities. - """ - - model_config = ConfigDict( - extra="allow", - ) - name: str - """ - Human-readable name of the currency (e.g. 'LoyaltyStars'). - """ - code: str - """ - Business-specific representation of the currency (e.g. 'LST'). - """ - decimal_places: int | None = Field(0, ge=0) - """ - The position of a digit to the right of a decimal point. Applies to all amount related fields for rewards. - """ - - -class MembershipReward(BaseModel): - """ - Quantifiable reward type and optional earning forecast for the current transaction. - """ - - model_config = ConfigDict( - extra="allow", - ) - currency: Currency - """ - A unit of value that customers can accumulate through various commercial activities. - """ - earning_forecast: EarningForecast | None = None - """ - Preview of rewards to be earned from the current transaction. - """ - - -class MembershipTierBenefit(BaseModel): - """ - Benefits associated with a membership tier. - """ - - model_config = ConfigDict( - extra="allow", - ) - id: str - """ - Unique identifier for the tier benefit. - """ - description: str - """ - A display-ready, human-readable explanation of this benefit (e.g. 'Early access to sales'). - """ - - -class MembershipTier(BaseModel): - """ - Specific achievement rank or status milestone that unlocks escalating value as a member progresses through activity or spend. - """ - - model_config = ConfigDict( - extra="allow", - ) - id: str - """ - Unique identifier for the membership tier. - """ - name: str - """ - The human-readable name of the tier (e.g., 'Platinum'). - """ - benefits: list[MembershipTierBenefit] | None = None - """ - List of benefits associated with this tier. - """ - - -class LoyaltyMembership(BaseModel): - """ - Loyalty membership the business has accepted for the eligibility claim represented by the parent map key. Programs that can be joined independently MUST be modeled as separate sibling entries under the loyalty map, distinguished by reverse-domain naming (e.g., 'com.example.rewards' and 'com.example.rewards.card'). - """ - - model_config = ConfigDict( - extra="allow", - ) - id: str - """ - Unique loyalty membership identifier. - """ - name: str - """ - Business specific name of the loyalty membership/program. - """ - display_id: str | None = None - """ - A masked or partial version of the membership id for user recognition (e.g., '****5678'). MUST NOT be set if the membership has not been verified. - """ - tiers: list[MembershipTier] | None = None - """ - Active or display-safe tier context for this membership. Most programs are single-status (one entry); programs with parallel status dimensions (e.g., current and lifetime) populate one entry per active tier. Omitted when no tier context has been resolved. - """ - rewards: list[MembershipReward] | None = None - """ - Reward types and earning forecasts associated with this membership. Each object encapsulates one type of reward. - """ - provisional: bool - """ - True if this membership requires additional verification. - """ - - -Loyalty = TypeAliasType( - "Loyalty", dict[reverse_domain_name.ReverseDomainName, LoyaltyMembership] -) -""" -Key-value map whose keys represent buyer/platform asserted eligibility claims and whose values represent associated membership information. All loyalty keys MUST use reverse-domain naming to ensure provenance and prevent collisions when multiple extensions contribute to the shared namespace. -""" - - -class Search(SearchResponse): - """ - Catalog Search response extended with Loyalty capability. - """ - - model_config = ConfigDict( - extra="allow", - ) - loyalty: Loyalty | None = None - - -class Lookup1(LookupResponse): - """ - Catalog Lookup response extended with Loyalty capability. - """ - - model_config = ConfigDict( - extra="allow", - ) - loyalty: Loyalty | None = None - - -class Lookup2(GetProductResponse): - """ - Catalog Lookup response extended with Loyalty capability. - """ - - model_config = ConfigDict( - extra="allow", - ) - loyalty: Loyalty | None = None - - -Lookup = TypeAliasType( - "Lookup", - Annotated[ - Lookup1 | Lookup2, Field(..., title="Catalog Lookup with Loyalty") - ], -) -""" -Catalog Lookup response extended with Loyalty capability. -""" - - -class Cart(Cart_1): - """ - Cart extended with Loyalty capability. - """ - - model_config = ConfigDict( - extra="allow", - ) - loyalty: Loyalty | None = None - - -class Checkout(Checkout_1): - """ - Checkout extended with Loyalty capability. - """ - - model_config = ConfigDict( - extra="allow", - ) - loyalty: Loyalty | None = None diff --git a/src/ucp_sdk/models/schemas/common/types/__init__.py b/src/ucp_sdk/models/schemas/common/types/__init__.py deleted file mode 100644 index 421dc21..0000000 --- a/src/ucp_sdk/models/schemas/common/types/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - diff --git a/src/ucp_sdk/models/schemas/common/types/actions.py b/src/ucp_sdk/models/schemas/common/types/actions.py deleted file mode 100644 index d67b151..0000000 --- a/src/ucp_sdk/models/schemas/common/types/actions.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from typing import Annotated, Any - -from pydantic import BaseModel, ConfigDict, Field -from typing_extensions import TypeAliasType - -from . import reverse_domain_name - - -class Instance(BaseModel): - """ - Common fields for one outstanding Action instance are id and optional config. The extension declaring the Action type defines type-specific processing data under config. Additional properties are permitted for forward compatibility. - """ - - model_config = ConfigDict( - extra="allow", - ) - id: str = Field(..., min_length=1) - """ - Identifier for this Action instance. - """ - config: dict[str, Any] | None = None - """ - Configuration defined by the extension that declares this Action type. - """ - - -Actions = TypeAliasType( - "Actions", - Annotated[ - dict[reverse_domain_name.ReverseDomainName, list[Instance]], - Field(..., title="Actions"), - ], -) -""" -Outstanding extension-defined Action instances, keyed by reverse-domain Action type, not extension name. -""" diff --git a/src/ucp_sdk/models/schemas/common/types/binding.py b/src/ucp_sdk/models/schemas/common/types/binding.py deleted file mode 100644 index 021401e..0000000 --- a/src/ucp_sdk/models/schemas/common/types/binding.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from pydantic import BaseModel, ConfigDict, Field - -from . import reverse_domain_name - - -class Binding(BaseModel): - """ - Binds a credential or token to a specific capability resource. Prevents reuse across different resources. - """ - - model_config = ConfigDict( - extra="allow", - ) - type: reverse_domain_name.ReverseDomainName - """ - The capability that owns the bound resource, for example dev.ucp.shopping.checkout. MUST be a capability name declared in the UCP namespace. - """ - id: str = Field(..., min_length=1) - """ - Opaque identifier of the bound resource within the owning capability, for example a checkout identifier. - """ diff --git a/src/ucp_sdk/models/schemas/common/types/constraint_expression.py b/src/ucp_sdk/models/schemas/common/types/constraint_expression.py deleted file mode 100644 index 236ae50..0000000 --- a/src/ucp_sdk/models/schemas/common/types/constraint_expression.py +++ /dev/null @@ -1,101 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from typing import Any - -from pydantic import BaseModel, ConfigDict, Field, field_validator -from typing_extensions import TypeAliasType - - -class ValueConstraint1(BaseModel): - """ - A Value Constraint containing `enum`, `const`, or both. - """ - - model_config = ConfigDict( - extra="allow", - ) - enum: list[Any] = Field(..., min_length=1) - """ - A non-empty array of unique JSON values. - """ - const: Any | None = None - - -class ValueConstraint2(BaseModel): - """ - A Value Constraint containing `enum`, `const`, or both. - """ - - model_config = ConfigDict( - extra="allow", - ) - enum: list[Any] | None = Field(None, min_length=1) - """ - A non-empty array of unique JSON values. - """ - const: Any - - -ValueConstraint = TypeAliasType( - "ValueConstraint", ValueConstraint1 | ValueConstraint2 -) -""" -A Value Constraint containing `enum`, `const`, or both. -""" - - -class ConstraintExpression(BaseModel): - """ - A closed JSON Schema Draft 2020-12 constraint expression with Object and Value Constraint positions. - """ - - model_config = ConfigDict( - extra="forbid", - ) - required: list[str] | None = Field(None, min_length=1) - """ - Property names required by the constrained object. Must be non-empty: an empty array applies no constraint. - """ - properties: dict[str, ConstraintExpression | ValueConstraint] | None = None - """ - Constraints keyed by property name. Must be non-empty: an empty object applies no constraint. - """ - anyOf: list[ConstraintExpression] | None = None - """ - Alternative Object Constraints. The constrained object must satisfy at least one. A branch must be non-empty: an empty branch is satisfied by every object and neutralizes the alternation. - """ - - @field_validator("required", mode="after") - def _enforce_unique_items_required(cls, value): # noqa: N805 - """JSON Schema uniqueItems: reject duplicate entries.""" - if value is None: - return value - seen = [] - for item in value: - if item in seen: - raise ValueError( - "Items must be unique (schema uniqueItems=true)" - ) - seen.append(item) - return value - - -ConstraintExpression.model_rebuild() diff --git a/src/ucp_sdk/models/schemas/common/types/locality.py b/src/ucp_sdk/models/schemas/common/types/locality.py deleted file mode 100644 index 35ff9b8..0000000 --- a/src/ucp_sdk/models/schemas/common/types/locality.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from pydantic import BaseModel, ConfigDict - - -class Locality(BaseModel): - """ - A coarse geographic location — country, region, and postal code. A lightweight alternative to a full postal address. - """ - - model_config = ConfigDict( - extra="allow", - ) - address_country: str | None = None - """ - The country, as a 2-letter ISO 3166-1 alpha-2 code (e.g. "US"). A 3-letter alpha-3 code or full country name MAY also be used. - """ - address_region: str | None = None - """ - The first-level administrative region within the country (e.g. a state or province such as California). - """ - postal_code: str | None = None - """ - The postal code (e.g. "94043"). - """ diff --git a/src/ucp_sdk/models/schemas/common/types/locality_create_request.py b/src/ucp_sdk/models/schemas/common/types/locality_create_request.py deleted file mode 100644 index 2b6c4c6..0000000 --- a/src/ucp_sdk/models/schemas/common/types/locality_create_request.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from pydantic import BaseModel, ConfigDict - - -class LocalityCreateRequest(BaseModel): - """ - A coarse geographic location — country, region, and postal code. A lightweight alternative to a full postal address. - """ - - model_config = ConfigDict( - extra="allow", - ) - address_country: str | None = None - """ - The country, as a 2-letter ISO 3166-1 alpha-2 code (e.g. "US"). A 3-letter alpha-3 code or full country name MAY also be used. - """ - address_region: str | None = None - """ - The first-level administrative region within the country (e.g. a state or province such as California). - """ - postal_code: str | None = None - """ - The postal code (e.g. "94043"). - """ diff --git a/src/ucp_sdk/models/schemas/common/types/locality_update_request.py b/src/ucp_sdk/models/schemas/common/types/locality_update_request.py deleted file mode 100644 index 26c74ad..0000000 --- a/src/ucp_sdk/models/schemas/common/types/locality_update_request.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from pydantic import BaseModel, ConfigDict - - -class LocalityUpdateRequest(BaseModel): - """ - A coarse geographic location — country, region, and postal code. A lightweight alternative to a full postal address. - """ - - model_config = ConfigDict( - extra="allow", - ) - address_country: str | None = None - """ - The country, as a 2-letter ISO 3166-1 alpha-2 code (e.g. "US"). A 3-letter alpha-3 code or full country name MAY also be used. - """ - address_region: str | None = None - """ - The first-level administrative region within the country (e.g. a state or province such as California). - """ - postal_code: str | None = None - """ - The postal code (e.g. "94043"). - """ diff --git a/src/ucp_sdk/models/schemas/common/types/measure.py b/src/ucp_sdk/models/schemas/common/types/measure.py deleted file mode 100644 index f085f51..0000000 --- a/src/ucp_sdk/models/schemas/common/types/measure.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from pydantic import ConfigDict, Field - -from .unit import Unit - - -class Measure(Unit): - """ - A measure composed of an integer value and a unit descriptor. Its value is the integer count of `10^-scale` units of `unit`. - """ - - model_config = ConfigDict( - extra="allow", - ) - value: int = Field(..., ge=-9007199254740991, le=9007199254740991) - """ - Integer count of `10^-scale` units of `unit`. - """ diff --git a/src/ucp_sdk/models/schemas/common/types/measure_create_request.py b/src/ucp_sdk/models/schemas/common/types/measure_create_request.py deleted file mode 100644 index 006326d..0000000 --- a/src/ucp_sdk/models/schemas/common/types/measure_create_request.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from pydantic import ConfigDict, Field - -from .unit_create_request import UnitCreateRequest - - -class MeasureCreateRequest(UnitCreateRequest): - """ - A measure composed of an integer value and a unit descriptor. Its value is the integer count of `10^-scale` units of `unit`. - """ - - model_config = ConfigDict( - extra="allow", - ) - value: int = Field(..., ge=-9007199254740991, le=9007199254740991) - """ - Integer count of `10^-scale` units of `unit`. - """ diff --git a/src/ucp_sdk/models/schemas/common/types/measure_update_request.py b/src/ucp_sdk/models/schemas/common/types/measure_update_request.py deleted file mode 100644 index b2b08ea..0000000 --- a/src/ucp_sdk/models/schemas/common/types/measure_update_request.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from pydantic import ConfigDict, Field - -from .unit_update_request import UnitUpdateRequest - - -class MeasureUpdateRequest(UnitUpdateRequest): - """ - A measure composed of an integer value and a unit descriptor. Its value is the integer count of `10^-scale` units of `unit`. - """ - - model_config = ConfigDict( - extra="allow", - ) - value: int = Field(..., ge=-9007199254740991, le=9007199254740991) - """ - Integer count of `10^-scale` units of `unit`. - """ diff --git a/src/ucp_sdk/models/schemas/common/types/policy.py b/src/ucp_sdk/models/schemas/common/types/policy.py deleted file mode 100644 index 9db2ca7..0000000 --- a/src/ucp_sdk/models/schemas/common/types/policy.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from pydantic import AnyUrl, BaseModel, ConfigDict - -from . import description as description_1 -from . import reverse_domain_name - - -class Policy(BaseModel): - """ - A durable business rule about the items in a response — return/refund terms, warranty, and the like — at the time of purchase. Every policy carries a `type` (an open reverse-DNS vocabulary) and a `description` so a platform can present it without understanding its type-specific fields; type-specific fields (gated by `type`) add structured context for platforms that model that type. Policies are reference data; the obligation to display a term to the buyer is carried by a `messages[]` warning whose `code` equals the policy `type` — see the Policies section of the specification. - """ - - model_config = ConfigDict( - extra="allow", - ) - type: reverse_domain_name.ReverseDomainName - """ - Policy type discriminator. Open reverse-DNS vocabulary. Well-known values: `dev.ucp.shopping.policy.return` (return terms), `dev.ucp.shopping.policy.warranty` (warranty terms). Businesses MAY define custom types in their own domain (e.g., `com.example.policy.price_match`). Platforms MUST tolerate unknown values. - """ - description: description_1.Description - """ - Human-readable policy summary in one or more formats (plain, markdown, html). Required on every policy so a platform can present it without understanding any type-specific fields. This is not the buyer-facing disclosure — display is compelled by a `messages[]` warning (see the Policies section). - """ - applies_to: list[str] | None = None - """ - RFC 9535 JSONPath expressions identifying the nodes this policy applies to, relative to the embedding response root (e.g., `$.line_items[0]` in cart/checkout, `$.products[2]` in catalog). Each target covers the node it names and everything nested under it, so a target on a product also covers its variants. A singular query (RFC 9535 Section 2.3.5.1; name and index selectors only) names a single node; filters, wildcards, and slices match a set. When omitted, the policy applies to the entire response. When policies of the same `type` contest a node, the narrowest target wins and overrides the rest. See the Policies section for how specificity resolves. - """ - url: AnyUrl | None = None - """ - Optional link to the full policy document. - """ diff --git a/src/ucp_sdk/models/schemas/common/types/quantity_unit.py b/src/ucp_sdk/models/schemas/common/types/quantity_unit.py deleted file mode 100644 index 44d14dd..0000000 --- a/src/ucp_sdk/models/schemas/common/types/quantity_unit.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from pydantic import ConfigDict, Field - -from .unit import Unit - - -class QuantityUnit(Unit): - """ - Sale-basis descriptor for quantities: the shared unit descriptor plus the Business's ordering policy. Its unit-descriptor machine identity remains (`unit`, effective `scale`); `display_text` and `increment` are excluded from identity and mismatch comparison. - """ - - model_config = ConfigDict( - extra="allow", - ) - increment: int | None = Field(1, ge=1) - """ - Ordering granularity, denominated in steps: the Business sells this item in integer multiples of `increment` steps. Its effective value is the provided value or 1. Advisory merchandising policy, not a representational bound: Platform-authored quantities SHOULD be integer multiples of the effective increment; the Business MAY accept, revise, or reject an off-increment request with a recoverable business outcome and MUST NOT silently reinterpret it. Business-authored quantities (checkout revisions, fulfillment events, adjustments) are bounded only by `scale`. - """ diff --git a/src/ucp_sdk/models/schemas/common/types/quantity_unit_create_request.py b/src/ucp_sdk/models/schemas/common/types/quantity_unit_create_request.py deleted file mode 100644 index 7a38b38..0000000 --- a/src/ucp_sdk/models/schemas/common/types/quantity_unit_create_request.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from pydantic import ConfigDict, Field - -from .unit_create_request import UnitCreateRequest - - -class QuantityUnitCreateRequest(UnitCreateRequest): - """ - Sale-basis descriptor for quantities: the shared unit descriptor plus the Business's ordering policy. Its unit-descriptor machine identity remains (`unit`, effective `scale`); `display_text` and `increment` are excluded from identity and mismatch comparison. - """ - - model_config = ConfigDict( - extra="allow", - ) - increment: int | None = Field(1, ge=1) - """ - Ordering granularity, denominated in steps: the Business sells this item in integer multiples of `increment` steps. Its effective value is the provided value or 1. Advisory merchandising policy, not a representational bound: Platform-authored quantities SHOULD be integer multiples of the effective increment; the Business MAY accept, revise, or reject an off-increment request with a recoverable business outcome and MUST NOT silently reinterpret it. Business-authored quantities (checkout revisions, fulfillment events, adjustments) are bounded only by `scale`. - """ diff --git a/src/ucp_sdk/models/schemas/common/types/quantity_unit_update_request.py b/src/ucp_sdk/models/schemas/common/types/quantity_unit_update_request.py deleted file mode 100644 index cadcad3..0000000 --- a/src/ucp_sdk/models/schemas/common/types/quantity_unit_update_request.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from pydantic import ConfigDict, Field - -from .unit_update_request import UnitUpdateRequest - - -class QuantityUnitUpdateRequest(UnitUpdateRequest): - """ - Sale-basis descriptor for quantities: the shared unit descriptor plus the Business's ordering policy. Its unit-descriptor machine identity remains (`unit`, effective `scale`); `display_text` and `increment` are excluded from identity and mismatch comparison. - """ - - model_config = ConfigDict( - extra="allow", - ) - increment: int | None = Field(1, ge=1) - """ - Ordering granularity, denominated in steps: the Business sells this item in integer multiples of `increment` steps. Its effective value is the provided value or 1. Advisory merchandising policy, not a representational bound: Platform-authored quantities SHOULD be integer multiples of the effective increment; the Business MAY accept, revise, or reject an off-increment request with a recoverable business outcome and MUST NOT silently reinterpret it. Business-authored quantities (checkout revisions, fulfillment events, adjustments) are bounded only by `scale`. - """ diff --git a/src/ucp_sdk/models/schemas/common/types/request_constraints.py b/src/ucp_sdk/models/schemas/common/types/request_constraints.py deleted file mode 100644 index 58b3294..0000000 --- a/src/ucp_sdk/models/schemas/common/types/request_constraints.py +++ /dev/null @@ -1,72 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from pydantic import BaseModel, ConfigDict, Field, field_validator - -from . import constraint_expression - - -class RequestConstraints(BaseModel): - """ - Binds the shared Constraint Expression grammar to data in the next UCP request to the same resource. - """ - - model_config = ConfigDict( - extra="forbid", - ) - path: str | None = None - """ - A complete RFC 9535 JSONPath query evaluated against the next logical UCP request to the same resource. - """ - required: list[str] | None = Field(None, min_length=1) - """ - Property names required by the constrained object. Must be non-empty: an empty array applies no constraint. - """ - properties: ( - dict[ - str, - constraint_expression.ConstraintExpression - | constraint_expression.ValueConstraint, - ] - | None - ) = Field(None, min_length=1) - """ - Constraints keyed by property name. Must be non-empty: an empty object applies no constraint. - """ - anyOf: list[constraint_expression.ConstraintExpression] | None = Field( - None, min_length=1 - ) - """ - Alternative Object Constraints. The constrained object must satisfy at least one. A branch must be non-empty: an empty branch is satisfied by every object and neutralizes the alternation. - """ - - @field_validator("required", mode="after") - def _enforce_unique_items_required(cls, value): # noqa: N805 - """JSON Schema uniqueItems: reject duplicate entries.""" - if value is None: - return value - seen = [] - for item in value: - if item in seen: - raise ValueError( - "Items must be unique (schema uniqueItems=true)" - ) - seen.append(item) - return value diff --git a/src/ucp_sdk/models/schemas/common/types/unit.py b/src/ucp_sdk/models/schemas/common/types/unit.py deleted file mode 100644 index bddaa3b..0000000 --- a/src/ucp_sdk/models/schemas/common/types/unit.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from pydantic import BaseModel, ConfigDict, Field - - -class Unit(BaseModel): - """ - A reusable unit descriptor for quantities and measures. Its unit-descriptor machine identity is (`unit`, effective `scale`), where effective `scale` is the provided `scale` or 0; `display_text` is excluded. - """ - - model_config = ConfigDict( - extra="allow", - ) - unit: str - """ - Stable machine identifier. The Business SHOULD use the exact UN/CEFACT Rec20 Common Code when one accurately identifies the unit. Otherwise, the Business MAY use a custom unit identifier and MUST use it consistently for the same unit. The Platform MUST treat an unrecognized identifier as opaque. - """ - scale: int | None = Field(0, ge=0, le=15) - """ - One step equals `10^-scale` of `unit`. When `unit` is `C62`, `scale`, if present, MUST be 0. The maximum of 15 is derived from the interoperable integer range: at scale 16 a single whole unit (10^16 steps) is no longer representable, so larger scales cannot denominate one unit of their own basis. Businesses needing finer granularity use a smaller unit. - """ - display_text: str - """ - Required printable unit label provided by the Business. The Platform MUST use it when it does not recognize `unit`; for a recognized UN/CEFACT Rec 20 Common Code, the Platform MAY substitute its own localized label. It does not participate in unit identity or mismatch comparison. - """ diff --git a/src/ucp_sdk/models/schemas/common/types/unit_create_request.py b/src/ucp_sdk/models/schemas/common/types/unit_create_request.py deleted file mode 100644 index 2fd5282..0000000 --- a/src/ucp_sdk/models/schemas/common/types/unit_create_request.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from pydantic import BaseModel, ConfigDict, Field - - -class UnitCreateRequest(BaseModel): - """ - A reusable unit descriptor for quantities and measures. Its unit-descriptor machine identity is (`unit`, effective `scale`), where effective `scale` is the provided `scale` or 0; `display_text` is excluded. - """ - - model_config = ConfigDict( - extra="allow", - ) - unit: str - """ - Stable machine identifier. The Business SHOULD use the exact UN/CEFACT Rec20 Common Code when one accurately identifies the unit. Otherwise, the Business MAY use a custom unit identifier and MUST use it consistently for the same unit. The Platform MUST treat an unrecognized identifier as opaque. - """ - scale: int | None = Field(0, ge=0, le=15) - """ - One step equals `10^-scale` of `unit`. When `unit` is `C62`, `scale`, if present, MUST be 0. The maximum of 15 is derived from the interoperable integer range: at scale 16 a single whole unit (10^16 steps) is no longer representable, so larger scales cannot denominate one unit of their own basis. Businesses needing finer granularity use a smaller unit. - """ - display_text: str - """ - Required printable unit label provided by the Business. The Platform MUST use it when it does not recognize `unit`; for a recognized UN/CEFACT Rec 20 Common Code, the Platform MAY substitute its own localized label. It does not participate in unit identity or mismatch comparison. - """ diff --git a/src/ucp_sdk/models/schemas/common/types/unit_update_request.py b/src/ucp_sdk/models/schemas/common/types/unit_update_request.py deleted file mode 100644 index a38f7d5..0000000 --- a/src/ucp_sdk/models/schemas/common/types/unit_update_request.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from pydantic import BaseModel, ConfigDict, Field - - -class UnitUpdateRequest(BaseModel): - """ - A reusable unit descriptor for quantities and measures. Its unit-descriptor machine identity is (`unit`, effective `scale`), where effective `scale` is the provided `scale` or 0; `display_text` is excluded. - """ - - model_config = ConfigDict( - extra="allow", - ) - unit: str - """ - Stable machine identifier. The Business SHOULD use the exact UN/CEFACT Rec20 Common Code when one accurately identifies the unit. Otherwise, the Business MAY use a custom unit identifier and MUST use it consistently for the same unit. The Platform MUST treat an unrecognized identifier as opaque. - """ - scale: int | None = Field(0, ge=0, le=15) - """ - One step equals `10^-scale` of `unit`. When `unit` is `C62`, `scale`, if present, MUST be 0. The maximum of 15 is derived from the interoperable integer range: at scale 16 a single whole unit (10^16 steps) is no longer representable, so larger scales cannot denominate one unit of their own basis. Businesses needing finer granularity use a smaller unit. - """ - display_text: str - """ - Required printable unit label provided by the Business. The Platform MUST use it when it does not recognize `unit`; for a recognized UN/CEFACT Rec 20 Common Code, the Platform MAY substitute its own localized label. It does not participate in unit identity or mismatch comparison. - """ diff --git a/src/ucp_sdk/models/schemas/profile.py b/src/ucp_sdk/models/schemas/profile.py deleted file mode 100644 index 500c36d..0000000 --- a/src/ucp_sdk/models/schemas/profile.py +++ /dev/null @@ -1,127 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from pydantic import BaseModel, ConfigDict, Field - -from . import ucp as ucp_1 - - -class JwkPublicKey(BaseModel): - """ - Public JSON Web Key used for HTTP Message Signatures and signed webhook verification. UCP profiles publish public keys only; private key material MUST NOT appear in a profile. Well-known key types: EC (ECDSA P-256, P-384) and OKP (EdDSA Ed25519); OKP keys are RECOMMENDED for signers opting into Web Bot Auth (WBA) interop on HTTP transport. A single profile MAY publish keys of either or both types; consumers select keys by kid. The kty, crv, and alg vocabularies are OPEN: verifiers MUST tolerate key types, curves, and algorithms they do not recognize, selecting keys by kid at verification time. An unsupported key affects only the signature that references it (algorithm_unsupported) and MUST NOT cause whole-profile rejection. Additional public JWK members are permitted; consumers ignore unknown members. - """ - - model_config = ConfigDict( - extra="allow", - ) - kid: str - """ - Key identifier referenced by Signature-Input keyid. For keys used in dual-audience (Web Bot Auth) signatures, the kid MUST be the key's JWK SHA-256 Thumbprint (RFC 7638) so UCP-Agent and Signature-Agent lookups resolve the same key; otherwise the kid MAY be any stable string. - """ - kty: str = Field(..., examples=["EC", "OKP"]) - """ - JWK key type. Well-known values: EC for ECDSA (P-256, P-384); OKP for EdDSA (Ed25519). Open vocabulary; verifiers tolerate unrecognized types and select keys by kid. - """ - crv: str | None = Field(None, examples=["P-256", "P-384", "Ed25519"]) - """ - Curve name. Well-known values: P-256, P-384 (EC); Ed25519 (OKP). Open vocabulary. - """ - x: str | None = None - """ - Public key value, base64url-encoded. For EC, the x coordinate (RFC 7518 §6.2); for OKP, the public key (RFC 8037 §2). - """ - y: str | None = None - """ - EC public key y coordinate, base64url-encoded (RFC 7518 §6.2). Not used by OKP keys. - """ - alg: str | None = Field(None, examples=["ES256", "ES384", "EdDSA"]) - """ - JWA algorithm associated with this public key. Optional; verifiers derive the algorithm from crv when alg is omitted. When present for a well-known curve it MUST match: ES256 with P-256, ES384 with P-384, EdDSA with Ed25519. - """ - use: str | None = None - """ - JWK public key use. UCP examples use sig for signatures. - """ - - -class UcpProfileDocument(BaseModel): - """ - Variant-neutral wrapper schema for UCP profile documents. Use the business_schema definition to validate business profiles and the platform_schema definition to validate platform profiles. - """ - - model_config = ConfigDict( - extra="allow", - ) - ucp: ucp_1.Base - """ - Protocol metadata, capabilities, services, and payment handlers advertised by this party. - """ - keys: list[JwkPublicKey] | None = None - """ - Canonical UCP profile field for publishing signing keys, as a JWK Set per RFC 7517. When a profile publishes signing keys, they MUST appear here; this is where every UCP verifier reads them. Publishing keys[] makes the UCP profile a valid JWK Set that a signer can reuse as its Web Bot Auth key source: a WBA-shape verifier resolving via Signature-Agent type=jwks_uri pointed at this profile reads these keys, and the cimd and directory variants reach them through their own documents. See the Deployment Patterns for WBA Interop section in the overview for hosting patterns. - """ - - -class Base(BaseModel): - """ - Common wrapper for UCP profile documents. - """ - - model_config = ConfigDict( - extra="allow", - ) - ucp: ucp_1.Base - """ - Protocol metadata, capabilities, services, and payment handlers advertised by this party. - """ - keys: list[JwkPublicKey] | None = None - """ - Canonical UCP profile field for publishing signing keys, as a JWK Set per RFC 7517. When a profile publishes signing keys, they MUST appear here; this is where every UCP verifier reads them. Publishing keys[] makes the UCP profile a valid JWK Set that a signer can reuse as its Web Bot Auth key source: a WBA-shape verifier resolving via Signature-Agent type=jwks_uri pointed at this profile reads these keys, and the cimd and directory variants reach them through their own documents. See the Deployment Patterns for WBA Interop section in the overview for hosting patterns. - """ - - -class BusinessSchema(BaseModel): - """ - Profile document hosted by a business at /.well-known/ucp. - """ - - model_config = ConfigDict( - extra="allow", - ) - ucp: ucp_1.BusinessSchema - keys: list[JwkPublicKey] | None = None - """ - Canonical UCP profile field for publishing signing keys, as a JWK Set per RFC 7517. When a profile publishes signing keys, they MUST appear here; this is where every UCP verifier reads them. Publishing keys[] makes the UCP profile a valid JWK Set that a signer can reuse as its Web Bot Auth key source: a WBA-shape verifier resolving via Signature-Agent type=jwks_uri pointed at this profile reads these keys, and the cimd and directory variants reach them through their own documents. See the Deployment Patterns for WBA Interop section in the overview for hosting patterns. - """ - - -class PlatformSchema(BaseModel): - """ - Profile document hosted by a platform and advertised to businesses via UCP-Agent. - """ - - model_config = ConfigDict( - extra="allow", - ) - ucp: ucp_1.PlatformSchema - keys: list[JwkPublicKey] | None = None - """ - Canonical UCP profile field for publishing signing keys, as a JWK Set per RFC 7517. When a profile publishes signing keys, they MUST appear here; this is where every UCP verifier reads them. Publishing keys[] makes the UCP profile a valid JWK Set that a signer can reuse as its Web Bot Auth key source: a WBA-shape verifier resolving via Signature-Agent type=jwks_uri pointed at this profile reads these keys, and the cimd and directory variants reach them through their own documents. See the Deployment Patterns for WBA Interop section in the overview for hosting patterns. - """ diff --git a/src/ucp_sdk/models/schemas/service.py b/src/ucp_sdk/models/schemas/service.py index c7638e0..cf33914 100644 --- a/src/ucp_sdk/models/schemas/service.py +++ b/src/ucp_sdk/models/schemas/service.py @@ -27,7 +27,7 @@ "UcpService", Annotated[Any, Field(..., title="UCP Service")] ) """ -Service declaration with one transport binding. Each transport binding is a separate entry in the service array; `version` identifies the service, not the transport. +Service binding for a specific transport. Each transport binding is a separate entry in the service array. """ @@ -103,7 +103,7 @@ class PlatformSchema(BaseModel): """ -class PlatformSchema8(BaseModel): +class PlatformSchema7(BaseModel): """ Full service declaration for platform-level discovery. All transports require `version`, `spec`, and `transport`. REST, MCP, and embedded additionally require `schema`. """ @@ -141,7 +141,7 @@ class PlatformSchema8(BaseModel): """ -class PlatformSchema9(BaseModel): +class PlatformSchema8(BaseModel): """ Full service declaration for platform-level discovery. All transports require `version`, `spec`, and `transport`. REST, MCP, and embedded additionally require `schema`. """ @@ -179,7 +179,7 @@ class PlatformSchema9(BaseModel): """ -class PlatformSchema10(BaseModel): +class PlatformSchema9(BaseModel): """ Full service declaration for platform-level discovery. All transports require `version`, `spec`, and `transport`. REST, MCP, and embedded additionally require `schema`. """ @@ -217,10 +217,10 @@ class PlatformSchema10(BaseModel): """ -PlatformSchema6 = TypeAliasType( - "PlatformSchema6", +PlatformSchema5 = TypeAliasType( + "PlatformSchema5", Annotated[ - PlatformSchema | PlatformSchema8 | PlatformSchema9 | PlatformSchema10, + PlatformSchema | PlatformSchema7 | PlatformSchema8 | PlatformSchema9, Field(..., title="Service (Platform Schema)"), ], ) @@ -267,7 +267,7 @@ class BusinessSchema(BaseModel): """ -class BusinessSchema5(BaseModel): +class BusinessSchema4(BaseModel): """ Service binding for business/merchant configuration. May override platform endpoints. """ @@ -305,7 +305,7 @@ class BusinessSchema5(BaseModel): """ -class BusinessSchema6(BaseModel): +class BusinessSchema5(BaseModel): """ Service binding for business/merchant configuration. May override platform endpoints. """ @@ -361,7 +361,7 @@ class Config(BaseModel): """ -class BusinessSchema7(BaseModel): +class BusinessSchema6(BaseModel): """ Service binding for business/merchant configuration. May override platform endpoints. """ @@ -399,10 +399,10 @@ class BusinessSchema7(BaseModel): """ -BusinessSchema3 = TypeAliasType( - "BusinessSchema3", +BusinessSchema2 = TypeAliasType( + "BusinessSchema2", Annotated[ - BusinessSchema | BusinessSchema5 | BusinessSchema6 | BusinessSchema7, + BusinessSchema | BusinessSchema4 | BusinessSchema5 | BusinessSchema6, Field(..., title="Service (Business Schema)"), ], ) diff --git a/src/ucp_sdk/models/schemas/shopping/buyer_consent.py b/src/ucp_sdk/models/schemas/shopping/buyer_consent.py index dbcb931..830a810 100644 --- a/src/ucp_sdk/models/schemas/shopping/buyer_consent.py +++ b/src/ucp_sdk/models/schemas/shopping/buyer_consent.py @@ -18,13 +18,11 @@ from __future__ import annotations -from typing import Annotated, Any, Literal +from typing import Annotated, Any from pydantic import BaseModel, ConfigDict, Field from typing_extensions import TypeAliasType -from ..common.types import link, reverse_domain_name -from .cart import Cart as Cart_1 from .checkout import Checkout as Checkout_1 from .types.buyer import Buyer as Buyer_1 @@ -33,79 +31,39 @@ Annotated[Any, Field(..., title="Buyer Consent Extension")], ) """ -Extends the buyer object with per-purpose consent. Each purpose is keyed by a reverse-DNS identifier and carries the current `granted` state, the `source` of that state (business default or platform-captured buyer decision), a `description`, optional `links`, and optional `segments` for finer-grained channel, vendor, or program decisions scoped to that purpose. +Extends Checkout with buyer consent tracking for privacy compliance via the buyer object. """ -class ConsentSegment(BaseModel): +class Consent(BaseModel): """ - A buyer's consent decision for a specific refinement of a parent purpose (e.g., email marketing under the marketing purpose). Overrides the parent's `granted` value for this scope. Segments do not nest further. + User consent states for data processing """ model_config = ConfigDict( extra="allow", ) - granted: bool + analytics: bool | None = None """ - Whether consent has been granted for this segment. Overrides the parent purpose's `granted` value for this specific scope. + Consent for analytics and performance tracking. """ - source: Literal["business", "platform"] + preferences: bool | None = None """ - Identifies the party that asserted the current `granted` value for this segment. `business` means the value reflects the business's default policy; `platform` means the value reflects an explicit buyer decision captured by the platform. + Consent for storing user preferences. """ - description: str + marketing: bool | None = None """ - Human-readable description of what the buyer is consenting to within this segment (e.g., 'Promotional emails and exclusive offers'). + Consent for marketing communications. """ - links: list[link.Link] | None = None + sale_of_data: bool | None = None """ - Optional segment-specific links (e.g., channel terms or privacy disclosures). + Consent for selling data to third parties (CCPA). """ -class ConsentPurpose(BaseModel): - """ - A buyer's consent decision for a purpose (e.g., marketing, analytics). Carries the current binary state, its source (business default or platform-captured buyer decision), human-readable context, and optional refinements scoping the decision to specific channels, vendors, or programs. - """ - - model_config = ConfigDict( - extra="allow", - ) - granted: bool - """ - Whether consent has been granted for this purpose. The `source` field identifies who asserted this state (business default or platform-captured buyer preference). - """ - source: Literal["business", "platform"] - """ - Identifies the party that asserted the current `granted` value. `business` means the value reflects the business's default policy; `platform` means the value reflects an explicit buyer decision captured by the platform. - """ - description: str - """ - Human-readable description of what the buyer is consenting to (e.g., 'Promotional communications across all channels'). - """ - links: list[link.Link] | None = None - """ - Optional links providing context (e.g., privacy policy, terms). - """ - segments: ( - dict[reverse_domain_name.ReverseDomainName, ConsentSegment] | None - ) = None - """ - Optional refinements scoping this purpose to specific channels, vendors, or programs. Keys are reverse-DNS identifiers. UCP currently defines two well-known segment identifiers under `dev.ucp.consent.marketing`: `dev.ucp.consent.marketing.email`, `dev.ucp.consent.marketing.sms`. Other segments follow vendor or merchant reverse-DNS conventions. - """ - - -Consent = TypeAliasType( - "Consent", dict[reverse_domain_name.ReverseDomainName, ConsentPurpose] -) -""" -Per-purpose consent. Keys are reverse-DNS purpose identifiers. UCP defines four well-known purposes: `dev.ucp.consent.marketing`, `dev.ucp.consent.analytics`, `dev.ucp.consent.preferences`, `dev.ucp.consent.sale_or_sharing`. Vendors and merchants may define additional purposes under their own reverse-DNS namespace. -""" - - class Buyer(Buyer_1): """ - Buyer object extended with per-purpose consent. + Buyer object extended with consent tracking. """ model_config = ConfigDict( @@ -113,27 +71,13 @@ class Buyer(Buyer_1): ) consent: Consent | None = None """ - Per-purpose consent decisions and business-advertised consent options. - """ - - -class Cart(Cart_1): - """ - Cart extended with buyer consent. - """ - - model_config = ConfigDict( - extra="allow", - ) - buyer: Buyer | None = None - """ - Buyer with consent tracking. + Consent tracking fields. """ class Checkout(Checkout_1): """ - Checkout extended with buyer consent. + Checkout extended with consent tracking via buyer object. """ model_config = ConfigDict( diff --git a/src/ucp_sdk/models/schemas/shopping/cart.py b/src/ucp_sdk/models/schemas/shopping/cart.py index 96b14aa..97caa5c 100644 --- a/src/ucp_sdk/models/schemas/shopping/cart.py +++ b/src/ucp_sdk/models/schemas/shopping/cart.py @@ -21,15 +21,13 @@ from pydantic import AnyUrl, AwareDatetime, BaseModel, ConfigDict from .. import ucp as ucp_1 -from ..common.types import actions as actions_1 -from ..common.types import context as context_1 -from ..common.types import link, message, policy -from ..common.types import signals as signals_1 -from ..common.types import totals as totals_1 from .checkout import Checkout as Checkout_1 from .types import attribution as attribution_1 from .types import buyer as buyer_1 -from .types import line_item +from .types import context as context_1 +from .types import line_item, link, message +from .types import signals as signals_1 +from .types import totals as totals_1 class Cart(BaseModel): @@ -67,10 +65,6 @@ class Cart(BaseModel): """ Estimated cost breakdown. May be partial if shipping/tax not yet calculable. """ - actions: actions_1.Actions | None = None - """ - Outstanding extension-defined Actions for this cart. - """ messages: list[message.Message] | None = None """ Validation messages, warnings, or informational notices. @@ -79,10 +73,6 @@ class Cart(BaseModel): """ Optional merchant links (policies, FAQs). """ - policies: list[policy.Policy] | None = None - """ - Policies (e.g., return/refund terms) that apply to the items in this cart. `applies_to` targets are relative to the response root; when absent or empty, refer to the URLs in `links[]`. - """ continue_url: AnyUrl | None = None """ URL for cart handoff and session recovery. Enables sharing and human-in-the-loop flows. diff --git a/src/ucp_sdk/models/schemas/shopping/cart_create_request.py b/src/ucp_sdk/models/schemas/shopping/cart_create_request.py index 42788fa..d7a93f6 100644 --- a/src/ucp_sdk/models/schemas/shopping/cart_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/cart_create_request.py @@ -20,12 +20,13 @@ from pydantic import BaseModel, ConfigDict -from ..common.types import context_create_request, signals_create_request from .checkout_create_request import CheckoutCreateRequest from .types import ( attribution_create_request, buyer_create_request, + context_create_request, line_item_create_request, + signals_create_request, ) diff --git a/src/ucp_sdk/models/schemas/shopping/cart_update_request.py b/src/ucp_sdk/models/schemas/shopping/cart_update_request.py index 83c6418..7c523ac 100644 --- a/src/ucp_sdk/models/schemas/shopping/cart_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/cart_update_request.py @@ -20,12 +20,13 @@ from pydantic import BaseModel, ConfigDict -from ..common.types import context_update_request, signals_update_request from .checkout_update_request import CheckoutUpdateRequest from .types import ( attribution_update_request, buyer_update_request, + context_update_request, line_item_update_request, + signals_update_request, ) @@ -37,6 +38,10 @@ class CartUpdateRequest(BaseModel): model_config = ConfigDict( extra="allow", ) + id: str + """ + Unique cart identifier. + """ line_items: list[line_item_update_request.LineItemUpdateRequest] """ Cart line items. Same structure as checkout. Full replacement on update. diff --git a/src/ucp_sdk/models/schemas/shopping/catalog_lookup.py b/src/ucp_sdk/models/schemas/shopping/catalog_lookup.py index a6f02fc..fed3d93 100644 --- a/src/ucp_sdk/models/schemas/shopping/catalog_lookup.py +++ b/src/ucp_sdk/models/schemas/shopping/catalog_lookup.py @@ -21,17 +21,16 @@ from pydantic import BaseModel, ConfigDict, Field from .. import ucp as ucp_1 -from ..common.types import actions as actions_1 -from ..common.types import context as context_1 -from ..common.types import message, policy -from ..common.types import signals as signals_1 from .types import attribution as attribution_1 +from .types import context as context_1 from .types import ( detail_option_value, input_correlation, + message, search_filters, selected_option, ) +from .types import signals as signals_1 from .types.product import Product as Product_1 from .types.variant import Variant @@ -81,6 +80,13 @@ class LookupRequest(BaseModel): attribution: attribution_1.Attribution | None = None +class Product(Product_1): + model_config = ConfigDict( + extra="allow", + ) + variants: list[LookupVariant] | None = None + + class GetProductRequest(BaseModel): """ Request body for single-product retrieval. Supports interactive variant narrowing via selected and preferences. @@ -120,11 +126,22 @@ class Option(BaseModel): ) -class Product(Product_1): +class DetailProduct(Product_1): + """ + A product in a get_product response, extended with effective selections and availability signals on option values. + """ + model_config = ConfigDict( extra="allow", ) - variants: list[LookupVariant] | None = None + selected: list[selected_option.SelectedOption] | None = None + """ + Effective option selections that anchor the featured variant and availability signals. Required when the product has configurable options; may be empty or omitted for products with no option axes. + """ + options: list[Option] | None = None + """ + Product options with availability signals relative to the effective selections. + """ class LookupResponse(BaseModel): @@ -136,36 +153,10 @@ class LookupResponse(BaseModel): """ Products matching the requested identifiers. May contain fewer items if some identifiers not found, or more if identifiers match multiple products. """ - actions: actions_1.Actions | None = None - """ - Outstanding extension-defined Actions for this catalog lookup response. - """ messages: list[message.Message] | None = None """ Errors, warnings, or informational messages about the requested items. """ - policies: list[policy.Policy] | None = None - """ - Policies (e.g., return/refund terms) that apply to the products in this response. `applies_to` targets are relative to the response root; when absent or empty, refer to the URLs in `links[]`. - """ - - -class DetailProduct(Product_1): - """ - A product in a get_product response, extended with effective selections and availability signals on option values. - """ - - model_config = ConfigDict( - extra="allow", - ) - selected: list[selected_option.SelectedOption] | None = None - """ - Effective option selections that anchor the featured variant and availability signals. Required when the product has configurable options; may be empty or omitted for products with no option axes. - """ - options: list[Option] | None = None - """ - Product options with availability signals relative to the effective selections. - """ class GetProductResponse(BaseModel): @@ -177,15 +168,7 @@ class GetProductResponse(BaseModel): """ The requested product with full detail. Singular — this is a single-resource operation. """ - actions: actions_1.Actions | None = None - """ - Outstanding extension-defined Actions for this product response. - """ messages: list[message.Message] | None = None """ Warnings or informational messages about the product (e.g., price recently changed, limited availability). """ - policies: list[policy.Policy] | None = None - """ - Policies (e.g., return/refund terms) that apply to this product. `applies_to` targets are relative to the response root; when absent or empty, refer to the URLs in `links[]`. - """ diff --git a/src/ucp_sdk/models/schemas/shopping/catalog_search.py b/src/ucp_sdk/models/schemas/shopping/catalog_search.py index 6fef5d6..d405d19 100644 --- a/src/ucp_sdk/models/schemas/shopping/catalog_search.py +++ b/src/ucp_sdk/models/schemas/shopping/catalog_search.py @@ -21,14 +21,12 @@ from pydantic import BaseModel, ConfigDict from .. import ucp as ucp_1 -from ..common.types import actions as actions_1 -from ..common.types import context as context_1 -from ..common.types import message -from ..common.types import pagination as pagination_1 -from ..common.types import policy -from ..common.types import signals as signals_1 from .types import attribution as attribution_1 +from .types import context as context_1 +from .types import message +from .types import pagination as pagination_1 from .types import product, search_filters +from .types import signals as signals_1 class CatalogSearch(BaseModel): @@ -66,15 +64,7 @@ class SearchResponse(BaseModel): Products matching the search criteria. """ pagination: pagination_1.Response | None = None - actions: actions_1.Actions | None = None - """ - Outstanding extension-defined Actions for this catalog search response. - """ messages: list[message.Message] | None = None """ Errors, warnings, or informational messages about the search results. """ - policies: list[policy.Policy] | None = None - """ - Policies (e.g., return/refund terms) that apply to the products in these search results. `applies_to` targets are relative to the response root; when absent or empty, refer to the URLs in `links[]`. - """ diff --git a/src/ucp_sdk/models/schemas/shopping/checkout.py b/src/ucp_sdk/models/schemas/shopping/checkout.py index 768f2d4..5a4259f 100644 --- a/src/ucp_sdk/models/schemas/shopping/checkout.py +++ b/src/ucp_sdk/models/schemas/shopping/checkout.py @@ -23,15 +23,13 @@ from pydantic import AnyUrl, AwareDatetime, BaseModel, ConfigDict from .. import ucp as ucp_1 -from ..common.types import actions as actions_1 -from ..common.types import context as context_1 -from ..common.types import link, message, policy -from ..common.types import signals as signals_1 -from ..common.types import totals as totals_1 from . import payment as payment_1 from .types import attribution as attribution_1 from .types import buyer as buyer_1 -from .types import line_item, order_confirmation +from .types import context as context_1 +from .types import line_item, link, message, order_confirmation +from .types import signals as signals_1 +from .types import totals as totals_1 class Checkout(BaseModel): @@ -67,7 +65,7 @@ class Checkout(BaseModel): "canceled", ] """ - Checkout state indicating the current phase and required processing. See Checkout Status lifecycle documentation for state transition details. + Checkout state indicating the current phase and required action. See Checkout Status lifecycle documentation for state transition details. """ currency: str """ @@ -77,10 +75,6 @@ class Checkout(BaseModel): """ Different cart totals. """ - actions: actions_1.Actions | None = None - """ - Outstanding extension-defined Actions for this checkout. - """ messages: list[message.Message] | None = None """ List of messages with error and info about the checkout session state. @@ -89,10 +83,6 @@ class Checkout(BaseModel): """ Links to be displayed by the platform (Privacy Policy, TOS). Mandatory for legal compliance. """ - policies: list[policy.Policy] | None = None - """ - Policies (e.g., return/refund terms) that apply to the items in this checkout. `applies_to` targets are relative to the response root; when absent or empty, refer to the URLs in `links[]`. - """ expires_at: AwareDatetime | None = None """ RFC 3339 expiry timestamp. Default TTL is 6 hours from creation if not sent. diff --git a/src/ucp_sdk/models/schemas/shopping/checkout_complete_request.py b/src/ucp_sdk/models/schemas/shopping/checkout_complete_request.py index bcfd2af..31a56c6 100644 --- a/src/ucp_sdk/models/schemas/shopping/checkout_complete_request.py +++ b/src/ucp_sdk/models/schemas/shopping/checkout_complete_request.py @@ -20,9 +20,8 @@ from pydantic import BaseModel, ConfigDict -from ..common.types import signals_complete_request from . import payment_complete_request -from .types import attribution_complete_request +from .types import attribution_complete_request, signals_complete_request class CheckoutCompleteRequest(BaseModel): diff --git a/src/ucp_sdk/models/schemas/shopping/checkout_create_request.py b/src/ucp_sdk/models/schemas/shopping/checkout_create_request.py index 5d18403..eaea128 100644 --- a/src/ucp_sdk/models/schemas/shopping/checkout_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/checkout_create_request.py @@ -20,12 +20,13 @@ from pydantic import BaseModel, ConfigDict -from ..common.types import context_create_request, signals_create_request from . import payment_create_request from .types import ( attribution_create_request, buyer_create_request, + context_create_request, line_item_create_request, + signals_create_request, ) diff --git a/src/ucp_sdk/models/schemas/shopping/checkout_update_request.py b/src/ucp_sdk/models/schemas/shopping/checkout_update_request.py index 564df8e..045042d 100644 --- a/src/ucp_sdk/models/schemas/shopping/checkout_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/checkout_update_request.py @@ -20,12 +20,13 @@ from pydantic import BaseModel, ConfigDict -from ..common.types import context_update_request, signals_update_request from . import payment_update_request from .types import ( attribution_update_request, buyer_update_request, + context_update_request, line_item_update_request, + signals_update_request, ) diff --git a/src/ucp_sdk/models/schemas/shopping/discount.py b/src/ucp_sdk/models/schemas/shopping/discount.py index c69a549..f0121ee 100644 --- a/src/ucp_sdk/models/schemas/shopping/discount.py +++ b/src/ucp_sdk/models/schemas/shopping/discount.py @@ -23,10 +23,10 @@ from pydantic import BaseModel, ConfigDict, Field from typing_extensions import TypeAliasType -from ..common.types import amount as amount_1 -from ..common.types import reverse_domain_name from .cart import Cart as Cart_1 from .checkout import Checkout as Checkout_1 +from .types import amount as amount_1 +from .types import reverse_domain_name DiscountExtension = TypeAliasType( "DiscountExtension", Annotated[Any, Field(..., title="Discount Extension")] diff --git a/src/ucp_sdk/models/schemas/shopping/fulfillment.py b/src/ucp_sdk/models/schemas/shopping/fulfillment.py index 07238e5..fd919f5 100644 --- a/src/ucp_sdk/models/schemas/shopping/fulfillment.py +++ b/src/ucp_sdk/models/schemas/shopping/fulfillment.py @@ -20,39 +20,24 @@ from typing import Annotated, Any -from pydantic import BaseModel, ConfigDict, Field +from pydantic import ConfigDict, Field from typing_extensions import TypeAliasType -from ..common.types import description as description_1 -from .catalog_lookup import DetailProduct -from .catalog_lookup import GetProductRequest as GetProductRequest_1 -from .catalog_lookup import GetProductResponse as GetProductResponse_1 -from .catalog_lookup import LookupRequest as LookupRequest_1 -from .catalog_lookup import LookupResponse as LookupResponse_1 -from .catalog_lookup import LookupVariant -from .catalog_search import SearchRequest as SearchRequest_1 -from .catalog_search import SearchResponse as SearchResponse_1 from .checkout import Checkout as Checkout_1 -from .types import availability as availability_1 from .types import fulfillment as fulfillment_1 from .types import ( fulfillment_available_method, - fulfillment_destination_filter, fulfillment_group, fulfillment_method, fulfillment_option, - fulfillment_option_base, ) -from .types.product import Product -from .types.search_filters import SearchFilters -from .types.variant import Variant FulfillmentExtension = TypeAliasType( "FulfillmentExtension", Annotated[Any, Field(..., title="Fulfillment Extension")], ) """ -Extends Catalog with fulfillment discovery and Checkout with hierarchical fulfillment. +Extends Checkout with fulfillment support using methods, destinations, and groups. """ @@ -65,129 +50,11 @@ ) -class CatalogFulfillmentMethod(BaseModel): - """ - A fulfillment method on a catalog variant: how the variant can be fulfilled, and its availability. - """ - - model_config = ConfigDict( - extra="allow", - ) - type: str - """ - Fulfillment method type. Well-known values: `shipping`, `pickup`. Businesses MAY use additional values. - """ - description: description_1.Description | None = None - """ - Short buyer-facing summary (e.g. 'Ships in 2–4 business days'). - """ - availability: availability_1.Availability | None = None - """ - Availability of this variant via this method at the specified or inferred location. - """ - location: str | None = None - """ - Stable, opaque identifier for the Business Location resolved for this place-based fulfillment method. The Business recognizes the same ID when submitted as `selected_destination_id` for that method; recognition does not reserve inventory or guarantee eligibility, and current terms are revalidated. - """ - options: list[fulfillment_option_base.FulfillmentOptionBase] | None = None - """ - Representative fulfillment options for this method (e.g. Standard, Express). Without a destination or full cart, a Business SHOULD preview meaningful boundary options (e.g. cheapest, fastest); more specific options are negotiated in Checkout once line items and destination are known. - """ - - -class CatalogFulfillment(BaseModel): - """ - How a catalog variant can be fulfilled. Mirrors checkout `fulfillment`. - """ - - model_config = ConfigDict( - extra="allow", - ) - methods: list[CatalogFulfillmentMethod] | None = None - """ - Fulfillment methods for this variant. - """ - - FulfillmentOption = TypeAliasType( "FulfillmentOption", fulfillment_option.FulfillmentOption ) -class FulfillmentVariant(Variant): - """ - A catalog variant with fulfillment. - """ - - model_config = ConfigDict( - extra="allow", - ) - fulfillment: CatalogFulfillment | None = None - - -class FulfillmentLookupVariant(LookupVariant): - """ - A lookup variant (carrying input correlation) enriched with fulfillment. - """ - - model_config = ConfigDict( - extra="allow", - ) - fulfillment: CatalogFulfillment | None = None - - -class FulfillmentSearchFilters(SearchFilters): - """ - Catalog filters extended with a fulfillment destination filter and a method-type filter. - """ - - model_config = ConfigDict( - extra="allow", - ) - fulfills_to: ( - fulfillment_destination_filter.FulfillmentDestinationFilter | None - ) = None - """ - Explicit destination where items are fulfilled. It may differ from the locality or Business Location supplied in `context` (e.g. a gift delivered directly to the recipient). The filter restricts results to what can be fulfilled there and seeds method `availability`. It supersedes `context` only for fulfillment destination and availability resolution. - """ - methods: list[str] | None = None - """ - Restrict results to these fulfillment method types (e.g. ["pickup"]). Well-known values: `shipping`, `pickup`. - """ - - -class FulfillmentSearchRequest(SearchRequest_1): - model_config = ConfigDict( - extra="allow", - ) - filters: FulfillmentSearchFilters | None = None - - -class FulfillmentLookupRequest(LookupRequest_1): - model_config = ConfigDict( - extra="allow", - ) - filters: FulfillmentSearchFilters | None = None - - -class FulfillmentGetProductRequest(GetProductRequest_1): - model_config = ConfigDict( - extra="allow", - ) - filters: FulfillmentSearchFilters | None = None - - -SearchRequest = TypeAliasType("SearchRequest", FulfillmentSearchRequest) - - -LookupRequest = TypeAliasType("LookupRequest", FulfillmentLookupRequest) - - -GetProductRequest = TypeAliasType( - "GetProductRequest", FulfillmentGetProductRequest -) - - FulfillmentGroup = TypeAliasType( "FulfillmentGroup", fulfillment_group.FulfillmentGroup ) @@ -198,71 +65,6 @@ class FulfillmentGetProductRequest(GetProductRequest_1): ) -class FulfillmentProduct(Product): - """ - A catalog product whose variants are fulfillment-enriched. Used by search. - """ - - model_config = ConfigDict( - extra="allow", - ) - variants: list[FulfillmentVariant] | None = None - - -class FulfillmentLookupProduct(Product): - """ - A lookup product whose variants are fulfillment-enriched, preserving input correlation. Used by lookup. - """ - - model_config = ConfigDict( - extra="allow", - ) - variants: list[FulfillmentLookupVariant] | None = None - - -class FulfillmentDetailProduct(DetailProduct): - """ - A get_product detail product (carrying selected/options availability signals) whose variants are fulfillment-enriched. Used by get_product. - """ - - model_config = ConfigDict( - extra="allow", - ) - variants: list[FulfillmentVariant] | None = None - - -class FulfillmentSearchResponse(SearchResponse_1): - model_config = ConfigDict( - extra="allow", - ) - products: list[FulfillmentProduct] | None = None - - -class FulfillmentLookupResponse(LookupResponse_1): - model_config = ConfigDict( - extra="allow", - ) - products: list[FulfillmentLookupProduct] | None = None - - -class FulfillmentGetProductResponse(GetProductResponse_1): - model_config = ConfigDict( - extra="allow", - ) - product: FulfillmentDetailProduct | None = None - - -SearchResponse = TypeAliasType("SearchResponse", FulfillmentSearchResponse) - - -LookupResponse = TypeAliasType("LookupResponse", FulfillmentLookupResponse) - - -GetProductResponse = TypeAliasType( - "GetProductResponse", FulfillmentGetProductResponse -) - - Fulfillment = TypeAliasType("Fulfillment", fulfillment_1.Fulfillment) diff --git a/src/ucp_sdk/models/schemas/shopping/order.py b/src/ucp_sdk/models/schemas/shopping/order.py index 47e95f0..ede4135 100644 --- a/src/ucp_sdk/models/schemas/shopping/order.py +++ b/src/ucp_sdk/models/schemas/shopping/order.py @@ -21,11 +21,10 @@ from pydantic import AnyUrl, BaseModel, ConfigDict from .. import ucp as ucp_1 -from ..common.types import message, policy -from ..common.types import totals as totals_1 from .types import adjustment from .types import attribution as attribution_1 -from .types import expectation, fulfillment_event, order_line_item +from .types import expectation, fulfillment_event, message, order_line_item +from .types import totals as totals_1 class PlatformSchema(BaseModel): @@ -105,10 +104,6 @@ class Order(BaseModel): """ Different totals for the order. """ - policies: list[policy.Policy] | None = None - """ - Snapshot of the policies that applied to the items at checkout, captured on the order as a durable record. `applies_to` targets are relative to the response root. - """ messages: list[message.Message] | None = None """ Business outcome messages (errors, warnings, informational). Present when the business needs to communicate status or issues to the platform. diff --git a/src/ucp_sdk/models/schemas/shopping/order_create_request.py b/src/ucp_sdk/models/schemas/shopping/order_create_request.py index e5f36ca..a31c315 100644 --- a/src/ucp_sdk/models/schemas/shopping/order_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/order_create_request.py @@ -21,12 +21,13 @@ from pydantic import AnyUrl, BaseModel, ConfigDict from .. import ucp_create_request -from ..common.types import message_create_request, totals_create_request from .types import ( adjustment_create_request, expectation_create_request, fulfillment_event_create_request, + message_create_request, order_line_item_create_request, + totals_create_request, ) diff --git a/src/ucp_sdk/models/schemas/shopping/order_update_request.py b/src/ucp_sdk/models/schemas/shopping/order_update_request.py index 959b3ae..fd4a285 100644 --- a/src/ucp_sdk/models/schemas/shopping/order_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/order_update_request.py @@ -21,12 +21,13 @@ from pydantic import AnyUrl, BaseModel, ConfigDict from .. import ucp_update_request -from ..common.types import message_update_request, totals_update_request from .types import ( adjustment_update_request, expectation_update_request, fulfillment_event_update_request, + message_update_request, order_line_item_update_request, + totals_update_request, ) diff --git a/src/ucp_sdk/models/schemas/shopping/payment_authentication.py b/src/ucp_sdk/models/schemas/shopping/payment_authentication.py deleted file mode 100644 index 41d5ccb..0000000 --- a/src/ucp_sdk/models/schemas/shopping/payment_authentication.py +++ /dev/null @@ -1,101 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from typing import Annotated, Any - -from pydantic import AnyUrl, BaseModel, ConfigDict, Field -from typing_extensions import TypeAliasType - -from .checkout import Checkout as Checkout_1 - -PaymentAuthenticationExtension = TypeAliasType( - "PaymentAuthenticationExtension", - Annotated[Any, Field(..., title="Payment Authentication Extension")], -) -""" -Extends Checkout with standard device data collection and 3DS challenge Action types used during payment authentication. -""" - - -class Config(BaseModel): - model_config = ConfigDict( - extra="allow", - ) - payment_instrument_id: str = Field(..., min_length=1) - """ - ID of the payment instrument in the containing Checkout associated with this device data collection Action. - """ - url: AnyUrl - """ - URL for the invisible device data collection surface. - """ - - -class DevUcpPaymentDeviceDataCollectionItem(BaseModel): - model_config = ConfigDict( - extra="allow", - ) - config: Config - - -class Config1(BaseModel): - model_config = ConfigDict( - extra="allow", - ) - payment_instrument_id: str = Field(..., min_length=1) - """ - ID of the payment instrument in the containing Checkout associated with this 3DS challenge Action. - """ - url: AnyUrl - """ - URL for the buyer-facing 3DS challenge surface. - """ - - -class DevUcpPaymentThreeDsChallengeItem(BaseModel): - model_config = ConfigDict( - extra="allow", - ) - config: Config1 - - -class Actions(BaseModel): - model_config = ConfigDict( - extra="allow", - ) - dev_ucp_payment_device_data_collection: ( - list[DevUcpPaymentDeviceDataCollectionItem] | None - ) = Field(None, alias="dev.ucp.payment.device_data_collection") - """ - A 3DS device data collection Action. - """ - dev_ucp_payment_three_ds_challenge: ( - list[DevUcpPaymentThreeDsChallengeItem] | None - ) = Field(None, alias="dev.ucp.payment.three_ds_challenge") - """ - A 3DS challenge Action. - """ - - -class Checkout(Checkout_1): - model_config = ConfigDict( - extra="allow", - ) - actions: Actions | None = None diff --git a/src/ucp_sdk/models/schemas/shopping/payment_terms.py b/src/ucp_sdk/models/schemas/shopping/payment_terms.py deleted file mode 100644 index 7b75937..0000000 --- a/src/ucp_sdk/models/schemas/shopping/payment_terms.py +++ /dev/null @@ -1,99 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from typing import Annotated, Any - -from pydantic import BaseModel, ConfigDict, Field -from typing_extensions import TypeAliasType - -from .checkout import Checkout as Checkout_1 -from .order import Order as Order_1 -from .types import payment_term - -PaymentTermsExtension = TypeAliasType( - "PaymentTermsExtension", - Annotated[Any, Field(..., title="Payment Terms Extension")], -) -""" -Extends Checkout with selectable payment terms, letting a Business offer alternative schedules for when payment for the checkout is due, and projects the accepted term onto the resulting Order. -""" - - -PaymentTerm = TypeAliasType("PaymentTerm", payment_term.PaymentTerm) - - -class Payment(BaseModel): - """ - Payment object extended with selectable payment terms. - """ - - model_config = ConfigDict( - extra="allow", - ) - terms: list[PaymentTerm] | None = Field(None, min_length=1) - """ - Payment terms the Buyer can choose from. An unselected term's amounts are indicative; the selected term's schedule amounts sum to the checkout total. - """ - selected_term_id: str | None = None - """ - ID of the selected payment term. MUST match one `terms[].id` from the latest Checkout response. Present in a response whenever `terms` is, and absent when it is not: the Checkout total is the selected term's total, so a list of terms without a selection would show an amount that matches no stated term. Where the Buyer has made no choice, the Business selects a default. Omitted on create requests because term IDs are checkout-scoped and no terms exist yet, and on complete requests because the term is already agreed by then. Selecting a term is an Update Checkout mutation: the Business response is authoritative for all derived state. - """ - - -class OrderPayment(BaseModel): - """ - Order payment details carrying the term the Buyer accepted at checkout. - """ - - model_config = ConfigDict( - extra="allow", - ) - accepted_term: PaymentTerm | None = None - """ - The payment term the Buyer accepted at checkout. Businesses MUST carry it forward so the Order states the amounts owed and when, and MUST ensure its schedule amounts sum to the Order total. The available terms are checkout state and are not projected. - """ - - -class Checkout(Checkout_1): - """ - Checkout extended with selectable payment terms. - """ - - model_config = ConfigDict( - extra="allow", - ) - payment: Payment | None = None - """ - Payment details with available and selected payment terms. - """ - - -class Order(Order_1): - """ - Order extended with the payment term accepted at checkout. - """ - - model_config = ConfigDict( - extra="allow", - ) - payment: OrderPayment | None = None - """ - Payment details for the Order, including the accepted payment term. - """ diff --git a/src/ucp_sdk/models/schemas/shopping/permalink.py b/src/ucp_sdk/models/schemas/shopping/permalink.py deleted file mode 100644 index b05c9a2..0000000 --- a/src/ucp_sdk/models/schemas/shopping/permalink.py +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from typing import Annotated, Any - -from pydantic import AnyUrl, BaseModel, ConfigDict, Field -from typing_extensions import TypeAliasType - -PermalinkCapability = TypeAliasType( - "PermalinkCapability", - Annotated[Any, Field(..., title="Permalink Capability")], -) -""" -Browser-addressable shopping intent capability: defines a Business browser endpoint and redirect resolution. It defines no shopping-state fields of its own; permalink query parameters address existing UCP field paths. -""" - - -Endpoint = TypeAliasType("Endpoint", AnyUrl) -""" -Absolute HTTPS browser endpoint with a non-empty authority and without userinfo, query, fragment, whitespace, backslashes, or trailing slash. Optional compact item path and query parameters are appended to this endpoint. -""" - - -class Config(BaseModel): - """ - Business browser endpoint configuration for shopping permalinks. - """ - - model_config = ConfigDict( - extra="allow", - ) - endpoint: Endpoint - - -Permalink = TypeAliasType("Permalink", Any) diff --git a/src/ucp_sdk/models/schemas/shopping/split_payments.py b/src/ucp_sdk/models/schemas/shopping/split_payments.py deleted file mode 100644 index b98f336..0000000 --- a/src/ucp_sdk/models/schemas/shopping/split_payments.py +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from typing import Annotated, Any - -from pydantic import BaseModel, ConfigDict, Field -from typing_extensions import TypeAliasType - -from ..common.types import amount as amount_1 -from .checkout import Checkout as Checkout_1 -from .types import instrument_group -from .types.payment_instrument import PaymentInstrument as PaymentInstrument_1 - -SplitPaymentsExtension = TypeAliasType( - "SplitPaymentsExtension", - Annotated[Any, Field(..., title="Split Payments Extension")], -) -""" -Enables buyers to use multiple payment instruments for a single checkout. -""" - - -InstrumentGroup = TypeAliasType( - "InstrumentGroup", instrument_group.InstrumentGroup -) - - -SplitPayments = TypeAliasType("SplitPayments", Any) - - -class PaymentInstrument(PaymentInstrument_1): - """ - Payment instrument extended with an optional per-instrument amount for split payments. - """ - - model_config = ConfigDict( - extra="allow", - ) - amount: amount_1.Amount | None = None - """ - Contribution amount for this instrument in `checkout.currency` minor units (ISO 4217). On request: the platform's requested contribution (omit for open-amount). On response: the actual amount authorized or charged (omitted when not finally processed). - """ - - -class Payment(BaseModel): - model_config = ConfigDict( - extra="allow", - ) - instruments: list[PaymentInstrument] | None = None - """ - Payment instruments in allocation priority order. - """ - - -class Checkout(Checkout_1): - """ - Checkout extended with split payment instrument amounts. - """ - - model_config = ConfigDict( - extra="allow", - ) - payment: Payment | None = None diff --git a/src/ucp_sdk/models/schemas/common/types/location_summary_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/account_info.py similarity index 74% rename from src/ucp_sdk/models/schemas/common/types/location_summary_update_request.py rename to src/ucp_sdk/models/schemas/shopping/types/account_info.py index 7102a5e..aeb2665 100644 --- a/src/ucp_sdk/models/schemas/common/types/location_summary_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/account_info.py @@ -21,15 +21,15 @@ from pydantic import BaseModel, ConfigDict -class LocationSummaryUpdateRequest(BaseModel): +class PaymentAccountInfo(BaseModel): """ - A summary of a business location. + Non-sensitive backend identifiers for linking. """ model_config = ConfigDict( extra="allow", ) - id: str + payment_account_reference: str | None = None """ - Stable, opaque, Business-scoped Location identifier. + EMVCo PAR. A unique identifier linking a payment card to a specific account, enabling tracking across tokens (Apple Pay, physical card, etc). """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/adjustment.py b/src/ucp_sdk/models/schemas/shopping/types/adjustment.py index 3ae0b00..99cdfe4 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/adjustment.py +++ b/src/ucp_sdk/models/schemas/shopping/types/adjustment.py @@ -20,10 +20,9 @@ from typing import Literal -from pydantic import AwareDatetime, BaseModel, ConfigDict, Field +from pydantic import AwareDatetime, BaseModel, ConfigDict -from ...common.types import measure as measure_1 -from ...common.types import total +from . import total class LineItem(BaseModel): @@ -34,13 +33,9 @@ class LineItem(BaseModel): """ Line item ID reference. """ - quantity: int = Field(..., ge=-9007199254740991, le=9007199254740991) + quantity: int """ - Signed integer count of steps of the referenced line item's `quantity_unit` (`10^-scale` × `unit`); when `quantity_unit` is absent, it counts whole items (`each`). Negative values represent reductions (e.g. returns); positive values represent additions (e.g. exchanges). - """ - measure: measure_1.Measure | None = None - """ - The settled measurement this adjustment reconciles (for example, actual picked weight), present when the line's price settles by measurement. Its unit identity MUST match the line's pricing basis (`item.unit_price` measure/reference unit); no unit conversion. A pure price settlement uses `quantity: 0` together with `measure` and a totals delta. + Signed quantity affected by this adjustment. Negative values represent reductions (e.g. returns); positive values represent additions (e.g. exchanges). """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/adjustment_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/adjustment_create_request.py index f3a7abb..44881cd 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/adjustment_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/adjustment_create_request.py @@ -20,9 +20,9 @@ from typing import Literal -from pydantic import AwareDatetime, BaseModel, ConfigDict, Field +from pydantic import AwareDatetime, BaseModel, ConfigDict -from ...common.types import measure_create_request, total_create_request +from . import total_create_request class LineItem(BaseModel): @@ -33,13 +33,9 @@ class LineItem(BaseModel): """ Line item ID reference. """ - quantity: int = Field(..., ge=-9007199254740991, le=9007199254740991) + quantity: int """ - Signed integer count of steps of the referenced line item's `quantity_unit` (`10^-scale` × `unit`); when `quantity_unit` is absent, it counts whole items (`each`). Negative values represent reductions (e.g. returns); positive values represent additions (e.g. exchanges). - """ - measure: measure_create_request.MeasureCreateRequest | None = None - """ - The settled measurement this adjustment reconciles (for example, actual picked weight), present when the line's price settles by measurement. Its unit identity MUST match the line's pricing basis (`item.unit_price` measure/reference unit); no unit conversion. A pure price settlement uses `quantity: 0` together with `measure` and a totals delta. + Signed quantity affected by this adjustment. Negative values represent reductions (e.g. returns); positive values represent additions (e.g. exchanges). """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/adjustment_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/adjustment_update_request.py index 3fd1b3b..632c2e7 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/adjustment_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/adjustment_update_request.py @@ -20,9 +20,9 @@ from typing import Literal -from pydantic import AwareDatetime, BaseModel, ConfigDict, Field +from pydantic import AwareDatetime, BaseModel, ConfigDict -from ...common.types import measure_update_request, total_update_request +from . import total_update_request class LineItem(BaseModel): @@ -33,13 +33,9 @@ class LineItem(BaseModel): """ Line item ID reference. """ - quantity: int = Field(..., ge=-9007199254740991, le=9007199254740991) + quantity: int """ - Signed integer count of steps of the referenced line item's `quantity_unit` (`10^-scale` × `unit`); when `quantity_unit` is absent, it counts whole items (`each`). Negative values represent reductions (e.g. returns); positive values represent additions (e.g. exchanges). - """ - measure: measure_update_request.MeasureUpdateRequest | None = None - """ - The settled measurement this adjustment reconciles (for example, actual picked weight), present when the line's price settles by measurement. Its unit identity MUST match the line's pricing basis (`item.unit_price` measure/reference unit); no unit conversion. A pure price settlement uses `quantity: 0` together with `measure` and a totals delta. + Signed quantity affected by this adjustment. Negative values represent reductions (e.g. returns); positive values represent additions (e.g. exchanges). """ diff --git a/src/ucp_sdk/models/schemas/common/types/amount.py b/src/ucp_sdk/models/schemas/shopping/types/amount.py similarity index 91% rename from src/ucp_sdk/models/schemas/common/types/amount.py rename to src/ucp_sdk/models/schemas/shopping/types/amount.py index f4d901d..0715e52 100644 --- a/src/ucp_sdk/models/schemas/common/types/amount.py +++ b/src/ucp_sdk/models/schemas/shopping/types/amount.py @@ -24,8 +24,7 @@ from typing_extensions import TypeAliasType Amount = TypeAliasType( - "Amount", - Annotated[int, Field(..., ge=0, le=9007199254740991, title="Amount")], + "Amount", Annotated[int, Field(..., ge=0, title="Amount")] ) """ Monetary amount in the currency's minor unit as defined by ISO 4217. Refer to the currency's exponent to determine minor-to-major ratio (e.g., 2 for USD, 0 for JPY, 3 for KWD). diff --git a/src/ucp_sdk/models/schemas/shopping/types/available_payment_instrument.py b/src/ucp_sdk/models/schemas/shopping/types/available_payment_instrument.py index b58ae7c..dda328c 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/available_payment_instrument.py +++ b/src/ucp_sdk/models/schemas/shopping/types/available_payment_instrument.py @@ -18,9 +18,9 @@ from __future__ import annotations -from pydantic import BaseModel, ConfigDict +from typing import Any -from ...common.types import constraint_expression +from pydantic import BaseModel, ConfigDict, Field class AvailablePaymentInstrument(BaseModel): @@ -35,7 +35,7 @@ class AvailablePaymentInstrument(BaseModel): """ The instrument type identifier (e.g., 'card', 'gift_card'). References an instrument schema's type constant. """ - constraints: constraint_expression.ConstraintExpression | None = None + constraints: dict[str, Any] | None = Field(None, min_length=1) """ - A Constraint Expression describing the instrument this entry makes available. Keys in `properties` name members of the `constraint_target` declared by the instrument schema for this `type`. Requirements on submitted request data belong in `ucp.request_constraints` instead. + Constraints on this instrument type. Structure depends on instrument type and active capabilities. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/availability.py b/src/ucp_sdk/models/schemas/shopping/types/binding.py similarity index 61% rename from src/ucp_sdk/models/schemas/shopping/types/availability.py rename to src/ucp_sdk/models/schemas/shopping/types/binding.py index 46b9ab9..16f6961 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/availability.py +++ b/src/ucp_sdk/models/schemas/shopping/types/binding.py @@ -20,20 +20,22 @@ from pydantic import BaseModel, ConfigDict +from . import payment_identity -class Availability(BaseModel): + +class Binding(BaseModel): """ - Availability of an item: whether it can be obtained, and a qualifying status. + Binds a token to a specific checkout session and participant. Prevents token reuse across different checkouts or participants. """ model_config = ConfigDict( extra="allow", ) - available: bool | None = None + checkout_id: str """ - Whether this can be obtained. See status for fulfillment details. + The checkout session identifier this token is bound to. """ - status: str | None = None + identity: payment_identity.PaymentIdentity | None = None """ - Qualifies available with fulfillment state. Well-known values: `in_stock`, `backorder`, `preorder`, `out_of_stock`, `discontinued`. + The participant this token is bound to. Required when acting on behalf of another participant (e.g., agent tokenizing for merchant). Omit when the authenticated caller is the binding target. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/business_fulfillment_config.py b/src/ucp_sdk/models/schemas/shopping/types/business_fulfillment_config.py index 7515f7e..55a9007 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/business_fulfillment_config.py +++ b/src/ucp_sdk/models/schemas/shopping/types/business_fulfillment_config.py @@ -18,16 +18,26 @@ from __future__ import annotations +from typing import Literal + from pydantic import BaseModel, ConfigDict -class MultiDestinationItem(BaseModel): +class AllowsMultiDestination(BaseModel): + """ + Permits multiple destinations per method type. + """ + model_config = ConfigDict( - extra="allow", + extra="forbid", ) - method: str + shipping: bool | None = None + """ + Multiple shipping destinations allowed. + """ + pickup: bool | None = None """ - Fulfillment method type (e.g. `shipping`, `pickup`). Optional per-method constraints MAY be added alongside. + Multiple pickup locations allowed. """ @@ -39,11 +49,13 @@ class BusinessFulfillmentConfig(BaseModel): model_config = ConfigDict( extra="allow", ) - multi_destination: list[MultiDestinationItem] | None = None + allows_multi_destination: AllowsMultiDestination | None = None """ - Method types that permit multiple destinations within one cart (e.g. split shipping across addresses). Listing a method permits it; an omitted method does not. Open — businesses MAY list any method type. + Permits multiple destinations per method type. """ - method_combinations: list[list[str]] | None = None + allows_method_combinations: ( + list[list[Literal["shipping", "pickup"]]] | None + ) = None """ - Method-type combinations the business permits within one cart. Each inner array is a permitted set of method `type` values (e.g. shipping + pickup). + Allowed method type combinations. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/business_split_payments_config.py b/src/ucp_sdk/models/schemas/shopping/types/business_split_payments_config.py deleted file mode 100644 index 0f87555..0000000 --- a/src/ucp_sdk/models/schemas/shopping/types/business_split_payments_config.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from typing import Annotated - -from pydantic import BaseModel, ConfigDict, Field -from typing_extensions import TypeAliasType - -from . import instrument_group - -AllowedCombination = TypeAliasType( - "AllowedCombination", - Annotated[list[instrument_group.InstrumentGroup], Field(..., min_length=1)], -) -""" -A single valid combination: an array of instrument groups that together define the constraints. All groups must be satisfied (AND logic). -""" - - -class BusinessSplitPaymentsConfig(BaseModel): - """ - Business-level configuration for split payments. Declaring the capability means multiple payment instruments are supported; this config declares which combinations are valid. - """ - - model_config = ConfigDict( - extra="allow", - ) - allowed_combinations: list[AllowedCombination] = Field(..., min_length=1) - """ - Array of valid instrument combinations. Each combination is an array of instrument groups. A payment is valid if it matches any combination. - """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/card_credential.py b/src/ucp_sdk/models/schemas/shopping/types/card_credential.py index b7f671a..43b231a 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/card_credential.py +++ b/src/ucp_sdk/models/schemas/shopping/types/card_credential.py @@ -27,7 +27,7 @@ class CardCredential(PaymentCredential): """ - Deprecated: use PAN Credential (`pan_credential.json`) or Network Token Credential (`network_token_credential.json`). A card credential containing sensitive payment card details including raw Primary Account Numbers (PANs). This credential type MUST NOT be used for checkout, only with payment handlers that tokenize or encrypt credentials. CRITICAL: Both parties handling CardCredential (sender and receiver) MUST be PCI DSS compliant. Transmission MUST use HTTPS/TLS with strong cipher suites. + A card credential containing sensitive payment card details including raw Primary Account Numbers (PANs). This credential type MUST NOT be used for checkout, only with payment handlers that tokenize or encrypt credentials. CRITICAL: Both parties handling CardCredential (sender and receiver) MUST be PCI DSS compliant. Transmission MUST use HTTPS/TLS with strong cipher suites. """ model_config = ConfigDict( @@ -39,7 +39,7 @@ class CardCredential(PaymentCredential): """ card_number_type: Literal["fpan", "network_token", "dpan"] """ - Deprecated: the credential type now carries this distinction. The type of card number. Network tokens are preferred with fallback to FPAN. See PCI Scope for more details. + The type of card number. Network tokens are preferred with fallback to FPAN. See PCI Scope for more details. """ number: str | None = Field(None, examples=["4242424242424242"]) """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/card_payment_instrument.py b/src/ucp_sdk/models/schemas/shopping/types/card_payment_instrument.py index ea5ba62..e75ecd4 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/card_payment_instrument.py +++ b/src/ucp_sdk/models/schemas/shopping/types/card_payment_instrument.py @@ -20,8 +20,9 @@ from typing import Literal -from pydantic import AnyUrl, BaseModel, ConfigDict, Field +from pydantic import AnyUrl, BaseModel, ConfigDict, Field, field_validator +from .available_payment_instrument import AvailablePaymentInstrument from .payment_instrument import PaymentInstrument @@ -35,7 +36,7 @@ class Display(BaseModel): ) brand: str | None = None """ - The card brand/network shown to the buyer (e.g., visa, mastercard, amex). Presentational only. + The card brand/network (e.g., visa, mastercard, amex). """ last_digits: str | None = None """ @@ -59,20 +60,40 @@ class Display(BaseModel): """ -class ConstraintTarget(BaseModel): +class Constraints(BaseModel): + model_config = ConfigDict( + extra="allow", + ) + brands: list[str] | None = Field(None, min_length=1) """ - The object an available card instrument's `constraints` describes. It declares the constrainable members and their types and is never carried in a payload. + Limit to specific card brands (e.g., ['visa', 'mastercard', 'amex']). + """ + + @field_validator("brands", mode="after") + def _enforce_unique_items_brands(cls, value): # noqa: N805 + """JSON Schema uniqueItems: reject duplicate entries.""" + if value is None: + return value + seen = [] + for item in value: + if item in seen: + raise ValueError( + "Items must be unique (schema uniqueItems=true)" + ) + seen.append(item) + return value + + +class AvailableCardPaymentInstrument(AvailablePaymentInstrument): + """ + Declares card instrument availability with card-specific constraints. """ model_config = ConfigDict( extra="allow", ) - brand: str | None = Field( - None, examples=["visa", "mastercard", "cartebancaire"] - ) - """ - Card scheme. Derived from the account number, not submitted. - """ + type: Literal["card"] | None = None + constraints: Constraints | None = None class CardPaymentInstrument(PaymentInstrument): @@ -87,10 +108,6 @@ class CardPaymentInstrument(PaymentInstrument): """ Indicates this is a card payment instrument. """ - network: str | None = None - """ - Card network elected for this transaction, typically a co-badged selection. When present, the business MAY decline if the card cannot route over it and MUST NOT substitute another. - """ display: Display | None = None """ Display information for this card payment instrument. diff --git a/src/ucp_sdk/models/schemas/common/types/context.py b/src/ucp_sdk/models/schemas/shopping/types/context.py similarity index 72% rename from src/ucp_sdk/models/schemas/common/types/context.py rename to src/ucp_sdk/models/schemas/shopping/types/context.py index b4bb158..66b4d73 100644 --- a/src/ucp_sdk/models/schemas/common/types/context.py +++ b/src/ucp_sdk/models/schemas/shopping/types/context.py @@ -21,24 +21,9 @@ from pydantic import BaseModel, ConfigDict, field_validator from . import reverse_domain_name -from .locality import Locality -class PaymentItem(BaseModel): - model_config = ConfigDict( - extra="allow", - ) - handler: reverse_domain_name.ReverseDomainName - """ - Handler registry key advertised in the Business profile's `ucp.payment_handlers`. - """ - types: list[str] | None = None - """ - Optional preferred instrument types for this handler, in priority order, aligned with the handler's advertised `payment_instrument.type` values (for example `card` or `bank`). Unrecognized values MUST be ignored. - """ - - -class Context(Locality): +class Context(BaseModel): """ Provisional buyer signals for relevance and localization—not authoritative data. Businesses SHOULD use these values when verified inputs (e.g., shipping address) are absent, and MAY ignore or down-rank them if inconsistent with higher-confidence signals (authenticated account, risk detection) or regulatory constraints (export controls). Eligibility and policy enforcement MUST occur at checkout time using binding transaction data. Context SHOULD be non-identifying and can be disclosed progressively—coarse signals early, finer resolution as the session progresses. Higher-resolution data (shipping address, billing address) supersedes context. """ @@ -46,9 +31,17 @@ class Context(Locality): model_config = ConfigDict( extra="allow", ) - location: str | None = None + address_country: str | None = None + """ + The country. Recommended to be in 2-letter ISO 3166-1 alpha-2 format, for example "US". For backward compatibility, a 3-letter ISO 3166-1 alpha-3 country code such as "SGP" or a full country name such as "Singapore" can also be used. Optional hint for market context (currency, availability, pricing)—higher-resolution data (e.g., shipping address) supersedes this value. + """ + address_region: str | None = None + """ + The region in which the locality is, and which is in the country. For example, California or another appropriate first-level Administrative division. Optional hint for progressive localization—higher-resolution data (e.g., shipping address) supersedes this value. """ - Stable, opaque identifier for a Location in the Business's namespace. This provisional, non-binding hint is distinct from the Buyer's locality. The operation specification or an active capability/extension defines its effects. A common example in retail shopping is the default home store ID selected and saved by the user when purchasing groceries. + postal_code: str | None = None + """ + The postal code. For example, 94043. Optional hint for regional refinement—higher-resolution data (e.g., shipping address) supersedes this value. """ intent: str | None = None """ @@ -66,10 +59,6 @@ class Context(Locality): """ Buyer claims about eligible benefits such as loyalty membership, payment instrument perks, and similar. Recognized claims MAY inform the Business response (e.g., member-only product availability, adjusted pricing in catalog, provisional discounts at cart or checkout). Businesses MUST ignore unrecognized values without error. Values MUST use reverse-domain naming (e.g., 'com.example.loyalty_gold', 'org.school.student') and MUST be non-identifying. """ - payment: list[PaymentItem] | None = None - """ - Buyer-preferred payment handlers in priority order (most preferred first). Each entry names a handler advertised in the Business profile's `ucp.payment_handlers`, optionally narrowed to preferred instrument types. The Business SHOULD use it to preselect or prioritize the handler (and type, when given) and MAY ignore unavailable or ineligible entries; unrecognized values MUST be ignored without error. - """ @field_validator("eligibility", mode="after") def _enforce_unique_items_eligibility(cls, value): # noqa: N805 diff --git a/src/ucp_sdk/models/schemas/common/types/context_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/context_create_request.py similarity index 68% rename from src/ucp_sdk/models/schemas/common/types/context_create_request.py rename to src/ucp_sdk/models/schemas/shopping/types/context_create_request.py index 6efdcb9..6c86b1a 100644 --- a/src/ucp_sdk/models/schemas/common/types/context_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/context_create_request.py @@ -21,24 +21,9 @@ from pydantic import BaseModel, ConfigDict from . import reverse_domain_name_create_request -from .locality_create_request import LocalityCreateRequest -class PaymentItem(BaseModel): - model_config = ConfigDict( - extra="allow", - ) - handler: reverse_domain_name_create_request.ReverseDomainNameCreateRequest - """ - Handler registry key advertised in the Business profile's `ucp.payment_handlers`. - """ - types: list[str] | None = None - """ - Optional preferred instrument types for this handler, in priority order, aligned with the handler's advertised `payment_instrument.type` values (for example `card` or `bank`). Unrecognized values MUST be ignored. - """ - - -class ContextCreateRequest(LocalityCreateRequest): +class ContextCreateRequest(BaseModel): """ Provisional buyer signals for relevance and localization—not authoritative data. Businesses SHOULD use these values when verified inputs (e.g., shipping address) are absent, and MAY ignore or down-rank them if inconsistent with higher-confidence signals (authenticated account, risk detection) or regulatory constraints (export controls). Eligibility and policy enforcement MUST occur at checkout time using binding transaction data. Context SHOULD be non-identifying and can be disclosed progressively—coarse signals early, finer resolution as the session progresses. Higher-resolution data (shipping address, billing address) supersedes context. """ @@ -46,9 +31,17 @@ class ContextCreateRequest(LocalityCreateRequest): model_config = ConfigDict( extra="allow", ) - location: str | None = None + address_country: str | None = None + """ + The country. Recommended to be in 2-letter ISO 3166-1 alpha-2 format, for example "US". For backward compatibility, a 3-letter ISO 3166-1 alpha-3 country code such as "SGP" or a full country name such as "Singapore" can also be used. Optional hint for market context (currency, availability, pricing)—higher-resolution data (e.g., shipping address) supersedes this value. + """ + address_region: str | None = None + """ + The region in which the locality is, and which is in the country. For example, California or another appropriate first-level Administrative division. Optional hint for progressive localization—higher-resolution data (e.g., shipping address) supersedes this value. """ - Stable, opaque identifier for a Location in the Business's namespace. This provisional, non-binding hint is distinct from the Buyer's locality. The operation specification or an active capability/extension defines its effects. A common example in retail shopping is the default home store ID selected and saved by the user when purchasing groceries. + postal_code: str | None = None + """ + The postal code. For example, 94043. Optional hint for regional refinement—higher-resolution data (e.g., shipping address) supersedes this value. """ intent: str | None = None """ @@ -69,7 +62,3 @@ class ContextCreateRequest(LocalityCreateRequest): """ Buyer claims about eligible benefits such as loyalty membership, payment instrument perks, and similar. Recognized claims MAY inform the Business response (e.g., member-only product availability, adjusted pricing in catalog, provisional discounts at cart or checkout). Businesses MUST ignore unrecognized values without error. Values MUST use reverse-domain naming (e.g., 'com.example.loyalty_gold', 'org.school.student') and MUST be non-identifying. """ - payment: list[PaymentItem] | None = None - """ - Buyer-preferred payment handlers in priority order (most preferred first). Each entry names a handler advertised in the Business profile's `ucp.payment_handlers`, optionally narrowed to preferred instrument types. The Business SHOULD use it to preselect or prioritize the handler (and type, when given) and MAY ignore unavailable or ineligible entries; unrecognized values MUST be ignored without error. - """ diff --git a/src/ucp_sdk/models/schemas/common/types/context_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/context_update_request.py similarity index 68% rename from src/ucp_sdk/models/schemas/common/types/context_update_request.py rename to src/ucp_sdk/models/schemas/shopping/types/context_update_request.py index b0bd4e1..79610e9 100644 --- a/src/ucp_sdk/models/schemas/common/types/context_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/context_update_request.py @@ -21,24 +21,9 @@ from pydantic import BaseModel, ConfigDict from . import reverse_domain_name_update_request -from .locality_update_request import LocalityUpdateRequest -class PaymentItem(BaseModel): - model_config = ConfigDict( - extra="allow", - ) - handler: reverse_domain_name_update_request.ReverseDomainNameUpdateRequest - """ - Handler registry key advertised in the Business profile's `ucp.payment_handlers`. - """ - types: list[str] | None = None - """ - Optional preferred instrument types for this handler, in priority order, aligned with the handler's advertised `payment_instrument.type` values (for example `card` or `bank`). Unrecognized values MUST be ignored. - """ - - -class ContextUpdateRequest(LocalityUpdateRequest): +class ContextUpdateRequest(BaseModel): """ Provisional buyer signals for relevance and localization—not authoritative data. Businesses SHOULD use these values when verified inputs (e.g., shipping address) are absent, and MAY ignore or down-rank them if inconsistent with higher-confidence signals (authenticated account, risk detection) or regulatory constraints (export controls). Eligibility and policy enforcement MUST occur at checkout time using binding transaction data. Context SHOULD be non-identifying and can be disclosed progressively—coarse signals early, finer resolution as the session progresses. Higher-resolution data (shipping address, billing address) supersedes context. """ @@ -46,9 +31,17 @@ class ContextUpdateRequest(LocalityUpdateRequest): model_config = ConfigDict( extra="allow", ) - location: str | None = None + address_country: str | None = None + """ + The country. Recommended to be in 2-letter ISO 3166-1 alpha-2 format, for example "US". For backward compatibility, a 3-letter ISO 3166-1 alpha-3 country code such as "SGP" or a full country name such as "Singapore" can also be used. Optional hint for market context (currency, availability, pricing)—higher-resolution data (e.g., shipping address) supersedes this value. + """ + address_region: str | None = None + """ + The region in which the locality is, and which is in the country. For example, California or another appropriate first-level Administrative division. Optional hint for progressive localization—higher-resolution data (e.g., shipping address) supersedes this value. """ - Stable, opaque identifier for a Location in the Business's namespace. This provisional, non-binding hint is distinct from the Buyer's locality. The operation specification or an active capability/extension defines its effects. A common example in retail shopping is the default home store ID selected and saved by the user when purchasing groceries. + postal_code: str | None = None + """ + The postal code. For example, 94043. Optional hint for regional refinement—higher-resolution data (e.g., shipping address) supersedes this value. """ intent: str | None = None """ @@ -69,7 +62,3 @@ class ContextUpdateRequest(LocalityUpdateRequest): """ Buyer claims about eligible benefits such as loyalty membership, payment instrument perks, and similar. Recognized claims MAY inform the Business response (e.g., member-only product availability, adjusted pricing in catalog, provisional discounts at cart or checkout). Businesses MUST ignore unrecognized values without error. Values MUST use reverse-domain naming (e.g., 'com.example.loyalty_gold', 'org.school.student') and MUST be non-identifying. """ - payment: list[PaymentItem] | None = None - """ - Buyer-preferred payment handlers in priority order (most preferred first). Each entry names a handler advertised in the Business profile's `ucp.payment_handlers`, optionally narrowed to preferred instrument types. The Business SHOULD use it to preselect or prioritize the handler (and type, when given) and MAY ignore unavailable or ineligible entries; unrecognized values MUST be ignored without error. - """ diff --git a/src/ucp_sdk/models/schemas/common/types/description.py b/src/ucp_sdk/models/schemas/shopping/types/description.py similarity index 100% rename from src/ucp_sdk/models/schemas/common/types/description.py rename to src/ucp_sdk/models/schemas/shopping/types/description.py diff --git a/src/ucp_sdk/models/schemas/common/types/error_code.py b/src/ucp_sdk/models/schemas/shopping/types/error_code.py similarity index 92% rename from src/ucp_sdk/models/schemas/common/types/error_code.py rename to src/ucp_sdk/models/schemas/shopping/types/error_code.py index 07e34dd..346ac0c 100644 --- a/src/ucp_sdk/models/schemas/common/types/error_code.py +++ b/src/ucp_sdk/models/schemas/shopping/types/error_code.py @@ -44,5 +44,5 @@ ], ) """ -Error code identifying the type of error. Standard errors are defined in capability specifications (see examples) and have standardized semantics; freeform codes are permitted. +Error code identifying the type of error. Standard errors are defined in specification (see examples), and have standardized semantics; freeform codes are permitted. """ diff --git a/src/ucp_sdk/models/schemas/common/types/error_code_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/error_code_create_request.py similarity index 92% rename from src/ucp_sdk/models/schemas/common/types/error_code_create_request.py rename to src/ucp_sdk/models/schemas/shopping/types/error_code_create_request.py index 7ccc827..c70c8e7 100644 --- a/src/ucp_sdk/models/schemas/common/types/error_code_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/error_code_create_request.py @@ -44,5 +44,5 @@ ], ) """ -Error code identifying the type of error. Standard errors are defined in capability specifications (see examples) and have standardized semantics; freeform codes are permitted. +Error code identifying the type of error. Standard errors are defined in specification (see examples), and have standardized semantics; freeform codes are permitted. """ diff --git a/src/ucp_sdk/models/schemas/common/types/error_code_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/error_code_update_request.py similarity index 92% rename from src/ucp_sdk/models/schemas/common/types/error_code_update_request.py rename to src/ucp_sdk/models/schemas/shopping/types/error_code_update_request.py index ec18e56..fab61ba 100644 --- a/src/ucp_sdk/models/schemas/common/types/error_code_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/error_code_update_request.py @@ -44,5 +44,5 @@ ], ) """ -Error code identifying the type of error. Standard errors are defined in capability specifications (see examples) and have standardized semantics; freeform codes are permitted. +Error code identifying the type of error. Standard errors are defined in specification (see examples), and have standardized semantics; freeform codes are permitted. """ diff --git a/src/ucp_sdk/models/schemas/common/types/error_response.py b/src/ucp_sdk/models/schemas/shopping/types/error_response.py similarity index 100% rename from src/ucp_sdk/models/schemas/common/types/error_response.py rename to src/ucp_sdk/models/schemas/shopping/types/error_response.py diff --git a/src/ucp_sdk/models/schemas/shopping/types/expectation.py b/src/ucp_sdk/models/schemas/shopping/types/expectation.py index 59163e2..03e8182 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/expectation.py +++ b/src/ucp_sdk/models/schemas/shopping/types/expectation.py @@ -18,9 +18,11 @@ from __future__ import annotations +from typing import Literal + from pydantic import BaseModel, ConfigDict, Field -from ...common.types import postal_address +from . import postal_address class LineItem(BaseModel): @@ -31,9 +33,9 @@ class LineItem(BaseModel): """ Line item ID reference. """ - quantity: int = Field(..., ge=1, le=9007199254740991) + quantity: int = Field(..., ge=1) """ - Integer count of steps of the referenced line item's `quantity_unit` (`10^-scale` × `unit`); when `quantity_unit` is absent, it counts whole items (`each`). + Quantity of this item in this expectation. """ @@ -53,9 +55,9 @@ class Expectation(BaseModel): """ Which line items and quantities are in this expectation. """ - method_type: str + method_type: Literal["shipping", "pickup", "digital"] """ - Delivery method type. Well-known values: `shipping`, `pickup`, `digital`; additional values MAY be used. + Delivery method type (shipping, pickup, digital). """ destination: postal_address.PostalAddress """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/expectation_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/expectation_create_request.py index 55f491f..c1084bf 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/expectation_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/expectation_create_request.py @@ -18,9 +18,11 @@ from __future__ import annotations +from typing import Literal + from pydantic import BaseModel, ConfigDict, Field -from ...common.types import postal_address_create_request +from . import postal_address_create_request class LineItem(BaseModel): @@ -31,9 +33,9 @@ class LineItem(BaseModel): """ Line item ID reference. """ - quantity: int = Field(..., ge=1, le=9007199254740991) + quantity: int = Field(..., ge=1) """ - Integer count of steps of the referenced line item's `quantity_unit` (`10^-scale` × `unit`); when `quantity_unit` is absent, it counts whole items (`each`). + Quantity of this item in this expectation. """ @@ -53,9 +55,9 @@ class ExpectationCreateRequest(BaseModel): """ Which line items and quantities are in this expectation. """ - method_type: str + method_type: Literal["shipping", "pickup", "digital"] """ - Delivery method type. Well-known values: `shipping`, `pickup`, `digital`; additional values MAY be used. + Delivery method type (shipping, pickup, digital). """ destination: postal_address_create_request.PostalAddressCreateRequest """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/expectation_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/expectation_update_request.py index a49a2d8..f0780a9 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/expectation_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/expectation_update_request.py @@ -18,9 +18,11 @@ from __future__ import annotations +from typing import Literal + from pydantic import BaseModel, ConfigDict, Field -from ...common.types import postal_address_update_request +from . import postal_address_update_request class LineItem(BaseModel): @@ -31,9 +33,9 @@ class LineItem(BaseModel): """ Line item ID reference. """ - quantity: int = Field(..., ge=1, le=9007199254740991) + quantity: int = Field(..., ge=1) """ - Integer count of steps of the referenced line item's `quantity_unit` (`10^-scale` × `unit`); when `quantity_unit` is absent, it counts whole items (`each`). + Quantity of this item in this expectation. """ @@ -53,9 +55,9 @@ class ExpectationUpdateRequest(BaseModel): """ Which line items and quantities are in this expectation. """ - method_type: str + method_type: Literal["shipping", "pickup", "digital"] """ - Delivery method type. Well-known values: `shipping`, `pickup`, `digital`; additional values MAY be used. + Delivery method type (shipping, pickup, digital). """ destination: postal_address_update_request.PostalAddressUpdateRequest """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_available_method.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_available_method.py index d5df375..4c9a1bb 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_available_method.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_available_method.py @@ -18,6 +18,8 @@ from __future__ import annotations +from typing import Literal + from pydantic import BaseModel, ConfigDict @@ -29,9 +31,9 @@ class FulfillmentAvailableMethod(BaseModel): model_config = ConfigDict( extra="allow", ) - type: str + type: Literal["shipping", "pickup"] """ - Fulfillment method type this availability applies to. Well-known values: `shipping`, `pickup`; businesses MAY use additional values. + Fulfillment method type this availability applies to. """ line_item_ids: list[str] """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination.py index fa07edf..b26f3e3 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination.py @@ -18,22 +18,21 @@ from __future__ import annotations -from pydantic import BaseModel, ConfigDict +from typing import Annotated +from pydantic import Field +from typing_extensions import TypeAliasType -class FulfillmentDestination(BaseModel): - """ - A destination for fulfillment. - """ +from . import retail_location, shipping_destination - model_config = ConfigDict( - extra="allow", - ) - type: str - """ - Destination contract discriminator. Required in Business responses and optional in Platform requests. Well-known values: `shipping_address`, `business_location`. The enclosing method contract defines request defaults and which fields the Platform may write; negotiated extensions define additional values. - """ - id: str - """ - Fulfillment destination identifier. - """ +FulfillmentDestination = TypeAliasType( + "FulfillmentDestination", + Annotated[ + shipping_destination.ShippingDestination + | retail_location.RetailLocation, + Field(..., title="Fulfillment Destination"), + ], +) +""" +A destination for fulfillment. +""" diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination_create_request.py index d46a2e8..4d7bbb5 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination_create_request.py @@ -18,22 +18,24 @@ from __future__ import annotations -from pydantic import BaseModel, ConfigDict +from typing import Annotated +from pydantic import Field +from typing_extensions import TypeAliasType -class FulfillmentDestinationCreateRequest(BaseModel): - """ - A destination for fulfillment. - """ +from . import ( + retail_location_create_request, + shipping_destination_create_request, +) - model_config = ConfigDict( - extra="allow", - ) - type: str | None = None - """ - Destination contract discriminator. Required in Business responses and optional in Platform requests. Well-known values: `shipping_address`, `business_location`. The enclosing method contract defines request defaults and which fields the Platform may write; negotiated extensions define additional values. - """ - id: str | None = None - """ - Fulfillment destination identifier. - """ +FulfillmentDestinationCreateRequest = TypeAliasType( + "FulfillmentDestinationCreateRequest", + Annotated[ + shipping_destination_create_request.ShippingDestinationCreateRequest + | retail_location_create_request.RetailLocationCreateRequest, + Field(..., title="Fulfillment Destination Create Request"), + ], +) +""" +A destination for fulfillment. +""" diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination_filter.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination_filter.py deleted file mode 100644 index b2af2b1..0000000 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination_filter.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from pydantic import ConfigDict - -from ...common.types.locality import Locality - - -class FulfillmentDestinationFilter(Locality): - """ - A specific destination, named by value or by reference: a coarse locality (`address_country` / `address_region` / `postal_code`), or a `location` id. Platforms SHOULD provide one or the other, not both; if both are present, a business SHOULD use the more specific — typically `location`. - """ - - model_config = ConfigDict( - extra="allow", - ) - location: str | None = None - """ - A reference to the destination (e.g. store, pickup location, saved address). - """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination_update_request.py index 0ea2cd1..add2079 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination_update_request.py @@ -18,22 +18,24 @@ from __future__ import annotations -from pydantic import BaseModel, ConfigDict +from typing import Annotated +from pydantic import Field +from typing_extensions import TypeAliasType -class FulfillmentDestinationUpdateRequest(BaseModel): - """ - A destination for fulfillment. - """ +from . import ( + retail_location_update_request, + shipping_destination_update_request, +) - model_config = ConfigDict( - extra="allow", - ) - type: str | None = None - """ - Destination contract discriminator. Required in Business responses and optional in Platform requests. Well-known values: `shipping_address`, `business_location`. The enclosing method contract defines request defaults and which fields the Platform may write; negotiated extensions define additional values. - """ - id: str | None = None - """ - Fulfillment destination identifier. - """ +FulfillmentDestinationUpdateRequest = TypeAliasType( + "FulfillmentDestinationUpdateRequest", + Annotated[ + shipping_destination_update_request.ShippingDestinationUpdateRequest + | retail_location_update_request.RetailLocationUpdateRequest, + Field(..., title="Fulfillment Destination Update Request"), + ], +) +""" +A destination for fulfillment. +""" diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_event.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_event.py index 7ae5f99..68e09c6 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_event.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_event.py @@ -29,9 +29,9 @@ class LineItem(BaseModel): """ Line item ID reference. """ - quantity: int = Field(..., ge=1, le=9007199254740991) + quantity: int = Field(..., ge=1) """ - Integer count of steps of the referenced line item's `quantity_unit` (`10^-scale` × `unit`); when `quantity_unit` is absent, it counts whole items (`each`). + Quantity fulfilled in this event. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_event_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_event_create_request.py index 633d362..a40632c 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_event_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_event_create_request.py @@ -29,9 +29,9 @@ class LineItem(BaseModel): """ Line item ID reference. """ - quantity: int = Field(..., ge=1, le=9007199254740991) + quantity: int = Field(..., ge=1) """ - Integer count of steps of the referenced line item's `quantity_unit` (`10^-scale` × `unit`); when `quantity_unit` is absent, it counts whole items (`each`). + Quantity fulfilled in this event. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_event_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_event_update_request.py index a67550e..2462a71 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_event_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_event_update_request.py @@ -29,9 +29,9 @@ class LineItem(BaseModel): """ Line item ID reference. """ - quantity: int = Field(..., ge=1, le=9007199254740991) + quantity: int = Field(..., ge=1) """ - Integer count of steps of the referenced line item's `quantity_unit` (`10^-scale` × `unit`); when `quantity_unit` is absent, it counts whole items (`each`). + Quantity fulfilled in this event. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method.py index b9f7c06..e022d8d 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method.py @@ -18,6 +18,8 @@ from __future__ import annotations +from typing import Literal + from pydantic import BaseModel, ConfigDict from . import fulfillment_destination, fulfillment_group @@ -25,7 +27,7 @@ class FulfillmentMethod(BaseModel): """ - A fulfillment method with destinations and groups. + A fulfillment method (shipping or pickup) with destinations and groups. """ model_config = ConfigDict( @@ -35,9 +37,9 @@ class FulfillmentMethod(BaseModel): """ Unique fulfillment method identifier. """ - type: str + type: Literal["shipping", "pickup"] """ - Fulfillment method type. Well-known values: `shipping`, `pickup`. Businesses MAY use additional values. + Fulfillment method type. """ line_item_ids: list[str] """ @@ -47,11 +49,11 @@ class FulfillmentMethod(BaseModel): list[fulfillment_destination.FulfillmentDestination] | None ) = None """ - Available destinations for this method. In Business responses, each destination carries a `type` and `id`. + Available destinations. For shipping: addresses. For pickup: retail locations. """ selected_destination_id: str | None = None """ - ID of the selected destination. Accepts any stable, Business-scoped ID the Business recognizes for this method, including Location IDs not yet enumerated in `destinations`. + ID of the selected destination. """ groups: list[fulfillment_group.FulfillmentGroup] | None = None """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method_create_request.py index 981c8cd..602c48d 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method_create_request.py @@ -18,26 +18,44 @@ from __future__ import annotations +from typing import Literal + from pydantic import BaseModel, ConfigDict -from . import fulfillment_group_create_request +from . import ( + fulfillment_destination_create_request, + fulfillment_group_create_request, +) class FulfillmentMethodCreateRequest(BaseModel): """ - A fulfillment method with destinations and groups. + A fulfillment method (shipping or pickup) with destinations and groups. """ model_config = ConfigDict( extra="allow", ) - type: str + type: Literal["shipping", "pickup"] + """ + Fulfillment method type. + """ + line_item_ids: list[str] | None = None + """ + Line item IDs fulfilled via this method. + """ + destinations: ( + list[ + fulfillment_destination_create_request.FulfillmentDestinationCreateRequest + ] + | None + ) = None """ - Fulfillment method type. Well-known values: `shipping`, `pickup`. Businesses MAY use additional values. + Available destinations. For shipping: addresses. For pickup: retail locations. """ selected_destination_id: str | None = None """ - ID of the selected destination. Accepts any stable, Business-scoped ID the Business recognizes for this method, including Location IDs not yet enumerated in `destinations`. + ID of the selected destination. """ groups: ( list[fulfillment_group_create_request.FulfillmentGroupCreateRequest] diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method_update_request.py index 3f06a19..712477f 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method_update_request.py @@ -18,14 +18,19 @@ from __future__ import annotations +from typing import Literal + from pydantic import BaseModel, ConfigDict -from . import fulfillment_group_update_request +from . import ( + fulfillment_destination_update_request, + fulfillment_group_update_request, +) class FulfillmentMethodUpdateRequest(BaseModel): """ - A fulfillment method with destinations and groups. + A fulfillment method (shipping or pickup) with destinations and groups. """ model_config = ConfigDict( @@ -35,17 +40,26 @@ class FulfillmentMethodUpdateRequest(BaseModel): """ Unique fulfillment method identifier. """ - type: str | None = None + type: Literal["shipping", "pickup"] | None = None """ - Fulfillment method type. Well-known values: `shipping`, `pickup`. Businesses MAY use additional values. + Fulfillment method type. """ line_item_ids: list[str] """ Line item IDs fulfilled via this method. """ + destinations: ( + list[ + fulfillment_destination_update_request.FulfillmentDestinationUpdateRequest + ] + | None + ) = None + """ + Available destinations. For shipping: addresses. For pickup: retail locations. + """ selected_destination_id: str | None = None """ - ID of the selected destination. Accepts any stable, Business-scoped ID the Business recognizes for this method, including Location IDs not yet enumerated in `destinations`. + ID of the selected destination. """ groups: ( list[fulfillment_group_update_request.FulfillmentGroupUpdateRequest] diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option.py index b5f3ff1..93b3bf8 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option.py @@ -18,20 +18,31 @@ from __future__ import annotations -from pydantic import AwareDatetime, ConfigDict +from pydantic import AwareDatetime, BaseModel, ConfigDict -from ...common.types import total -from .fulfillment_option_base import FulfillmentOptionBase +from . import total -class FulfillmentOption(FulfillmentOptionBase): +class FulfillmentOption(BaseModel): """ - A fulfillment option within a group (e.g., Standard Shipping $5, Express $15). Extends the fulfillment option base with cost and timing. + A fulfillment option within a group (e.g., Standard Shipping $5, Express $15). """ model_config = ConfigDict( extra="allow", ) + id: str + """ + Unique fulfillment option identifier. + """ + title: str + """ + Short label (e.g., 'Express Shipping', 'Curbside Pickup'). + """ + description: str | None = None + """ + Complete context for buyer decision (e.g., 'Arrives Dec 12-15 via FedEx'). + """ carrier: str | None = None """ Carrier name (for shipping). diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_base_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_base_update_request.py deleted file mode 100644 index b0112af..0000000 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_base_update_request.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from pydantic import BaseModel, ConfigDict - - -class FulfillmentOptionBaseUpdateRequest(BaseModel): - """ - Common base for a fulfillment option: an addressable, renderable choice (e.g. Standard, Express). Catalog uses this base directly; checkout composes it with cost and timing. - """ - - model_config = ConfigDict( - extra="allow", - ) diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_create_request.py index 4cbda60..d08ee75 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_create_request.py @@ -18,16 +18,12 @@ from __future__ import annotations -from pydantic import ConfigDict +from pydantic import BaseModel, ConfigDict -from .fulfillment_option_base_create_request import ( - FulfillmentOptionBaseCreateRequest, -) - -class FulfillmentOptionCreateRequest(FulfillmentOptionBaseCreateRequest): +class FulfillmentOptionCreateRequest(BaseModel): """ - A fulfillment option within a group (e.g., Standard Shipping $5, Express $15). Extends the fulfillment option base with cost and timing. + A fulfillment option within a group (e.g., Standard Shipping $5, Express $15). """ model_config = ConfigDict( diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_update_request.py index d2928a7..363e7f3 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_update_request.py @@ -18,16 +18,12 @@ from __future__ import annotations -from pydantic import ConfigDict +from pydantic import BaseModel, ConfigDict -from .fulfillment_option_base_update_request import ( - FulfillmentOptionBaseUpdateRequest, -) - -class FulfillmentOptionUpdateRequest(FulfillmentOptionBaseUpdateRequest): +class FulfillmentOptionUpdateRequest(BaseModel): """ - A fulfillment option within a group (e.g., Standard Shipping $5, Express $15). Extends the fulfillment option base with cost and timing. + A fulfillment option within a group (e.g., Standard Shipping $5, Express $15). """ model_config = ConfigDict( diff --git a/src/ucp_sdk/models/schemas/common/types/info_code.py b/src/ucp_sdk/models/schemas/shopping/types/info_code.py similarity index 90% rename from src/ucp_sdk/models/schemas/common/types/info_code.py rename to src/ucp_sdk/models/schemas/shopping/types/info_code.py index e691c86..a06eb3f 100644 --- a/src/ucp_sdk/models/schemas/common/types/info_code.py +++ b/src/ucp_sdk/models/schemas/shopping/types/info_code.py @@ -40,5 +40,5 @@ ], ) """ -Info code identifying the type of informational message. Standard codes are defined in capability specifications (see examples) and have standardized semantics; freeform codes are permitted. +Info code identifying the type of informational message. Standard codes are defined in capability specs (see examples), and have standardized semantics; freeform codes are permitted. """ diff --git a/src/ucp_sdk/models/schemas/common/types/info_code_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/info_code_create_request.py similarity index 90% rename from src/ucp_sdk/models/schemas/common/types/info_code_create_request.py rename to src/ucp_sdk/models/schemas/shopping/types/info_code_create_request.py index ad7cba6..5a065eb 100644 --- a/src/ucp_sdk/models/schemas/common/types/info_code_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/info_code_create_request.py @@ -40,5 +40,5 @@ ], ) """ -Info code identifying the type of informational message. Standard codes are defined in capability specifications (see examples) and have standardized semantics; freeform codes are permitted. +Info code identifying the type of informational message. Standard codes are defined in capability specs (see examples), and have standardized semantics; freeform codes are permitted. """ diff --git a/src/ucp_sdk/models/schemas/common/types/info_code_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/info_code_update_request.py similarity index 90% rename from src/ucp_sdk/models/schemas/common/types/info_code_update_request.py rename to src/ucp_sdk/models/schemas/shopping/types/info_code_update_request.py index 65c287f..ff78415 100644 --- a/src/ucp_sdk/models/schemas/common/types/info_code_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/info_code_update_request.py @@ -40,5 +40,5 @@ ], ) """ -Info code identifying the type of informational message. Standard codes are defined in capability specifications (see examples) and have standardized semantics; freeform codes are permitted. +Info code identifying the type of informational message. Standard codes are defined in capability specs (see examples), and have standardized semantics; freeform codes are permitted. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/instrument_group.py b/src/ucp_sdk/models/schemas/shopping/types/instrument_group.py deleted file mode 100644 index 55bb991..0000000 --- a/src/ucp_sdk/models/schemas/shopping/types/instrument_group.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from pydantic import BaseModel, ConfigDict, Field - - -class InstrumentGroup(BaseModel): - """ - A constraint within an allowed combination that defines which instrument types can fill this group and how many are permitted. - """ - - model_config = ConfigDict( - extra="allow", - ) - types: list[str] = Field(..., min_length=1) - """ - Instrument types accepted by this group (OR logic). Any listed type qualifies. - """ - min: int | None = Field(0, ge=0) - """ - Minimum number of instruments required from this group. Defaults to 0 (optional). - """ - max: int | None = Field(1, ge=1) - """ - Maximum number of instruments allowed from this group. Defaults to 1. MUST be greater than or equal to `min`. - """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/item.py b/src/ucp_sdk/models/schemas/shopping/types/item.py index 1d07c83..cfcc71c 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/item.py +++ b/src/ucp_sdk/models/schemas/shopping/types/item.py @@ -20,9 +20,7 @@ from pydantic import AnyUrl, BaseModel, ConfigDict -from ...common.types import amount -from ...common.types import quantity_unit as quantity_unit_1 -from . import unit_price as unit_price_1 +from . import amount class Item(BaseModel): @@ -39,15 +37,7 @@ class Item(BaseModel): """ price: amount.Amount """ - Unit price in ISO 4217 minor units. Price is the amount per one whole `quantity_unit.unit` (for example, per lb or per hour); when `quantity_unit` is absent, it is per `each`. - """ - quantity_unit: quantity_unit_1.QuantityUnit | None = None - """ - Sale basis this item's `quantity` is denominated in. On an authoritative Business response, absence encodes the default `each` machine identity (`C62`, 0); the Business MUST include this descriptor for every non-`each` response. On Platform requests, omission makes no assertion: the Business interprets `quantity` using the item's authoritative sale basis. If the Platform includes this descriptor, it asserts the unit-descriptor machine identity. The Business MUST compare that machine identity (`unit`, effective `scale`), ignore `display_text` and `increment`, and resolve a mismatch by conversion surfaced as a visible line revision with a warning, or by rejection with a recoverable business outcome; silent reinterpretation is forbidden. An explicit `C62` descriptor at effective scale 0 matches an authoritative basis represented by an absent descriptor. - """ - unit_price: unit_price_1.UnitPrice | None = None - """ - Pricing basis for this item. On an authoritative Business response, the Business MUST include `unit_price` on every line whose pricing basis differs from its sale basis (for example, priced per pound but sold per `each`); presence on a line marks the rate as transactional rather than display-only. When the pricing basis is the sale basis, `item.price` fully denominates the charge and this field MAY be omitted. + Unit price in ISO 4217 minor units. """ image_url: AnyUrl | None = None """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/item_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/item_create_request.py index df9f0cd..bbef8e8 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/item_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/item_create_request.py @@ -20,8 +20,6 @@ from pydantic import BaseModel, ConfigDict -from ...common.types import quantity_unit_create_request - class ItemCreateRequest(BaseModel): model_config = ConfigDict( @@ -31,9 +29,3 @@ class ItemCreateRequest(BaseModel): """ The product identifier, often the SKU, required to resolve the product details associated with this line item. Should be recognized by both the Platform, and the Business. """ - quantity_unit: ( - quantity_unit_create_request.QuantityUnitCreateRequest | None - ) = None - """ - Sale basis this item's `quantity` is denominated in. On an authoritative Business response, absence encodes the default `each` machine identity (`C62`, 0); the Business MUST include this descriptor for every non-`each` response. On Platform requests, omission makes no assertion: the Business interprets `quantity` using the item's authoritative sale basis. If the Platform includes this descriptor, it asserts the unit-descriptor machine identity. The Business MUST compare that machine identity (`unit`, effective `scale`), ignore `display_text` and `increment`, and resolve a mismatch by conversion surfaced as a visible line revision with a warning, or by rejection with a recoverable business outcome; silent reinterpretation is forbidden. An explicit `C62` descriptor at effective scale 0 matches an authoritative basis represented by an absent descriptor. - """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/item_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/item_update_request.py index 96186f5..c957d16 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/item_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/item_update_request.py @@ -20,8 +20,6 @@ from pydantic import BaseModel, ConfigDict -from ...common.types import quantity_unit_update_request - class ItemUpdateRequest(BaseModel): model_config = ConfigDict( @@ -31,9 +29,3 @@ class ItemUpdateRequest(BaseModel): """ The product identifier, often the SKU, required to resolve the product details associated with this line item. Should be recognized by both the Platform, and the Business. """ - quantity_unit: ( - quantity_unit_update_request.QuantityUnitUpdateRequest | None - ) = None - """ - Sale basis this item's `quantity` is denominated in. On an authoritative Business response, absence encodes the default `each` machine identity (`C62`, 0); the Business MUST include this descriptor for every non-`each` response. On Platform requests, omission makes no assertion: the Business interprets `quantity` using the item's authoritative sale basis. If the Platform includes this descriptor, it asserts the unit-descriptor machine identity. The Business MUST compare that machine identity (`unit`, effective `scale`), ignore `display_text` and `increment`, and resolve a mismatch by conversion surfaced as a visible line revision with a warning, or by rejection with a recoverable business outcome; silent reinterpretation is forbidden. An explicit `C62` descriptor at effective scale 0 matches an authoritative basis represented by an absent descriptor. - """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/line_item.py b/src/ucp_sdk/models/schemas/shopping/types/line_item.py index cf31595..9f2befe 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/line_item.py +++ b/src/ucp_sdk/models/schemas/shopping/types/line_item.py @@ -20,8 +20,8 @@ from pydantic import BaseModel, ConfigDict, Field -from ...common.types import total from . import item as item_1 +from . import total class LineItem(BaseModel): @@ -34,9 +34,9 @@ class LineItem(BaseModel): ) id: str item: item_1.Item - quantity: int = Field(..., ge=1, le=9007199254740991) + quantity: int = Field(..., ge=1) """ - Always an integer step count. On Platform requests, steps use the item's Business-authoritative sale basis; omitting `item.quantity_unit` makes no assertion and does not imply `each`. On Business responses, `item.quantity_unit` describes the basis; if absent, it encodes the `each` machine identity (`C62`, 0) and `quantity` counts whole items. + Quantity of the item being purchased. """ totals: list[total.Total] """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/line_item_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/line_item_create_request.py index c669bb3..754e4fe 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/line_item_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/line_item_create_request.py @@ -32,7 +32,7 @@ class LineItemCreateRequest(BaseModel): extra="allow", ) item: item_create_request.ItemCreateRequest - quantity: int = Field(..., ge=1, le=9007199254740991) + quantity: int = Field(..., ge=1) """ - Always an integer step count. On Platform requests, steps use the item's Business-authoritative sale basis; omitting `item.quantity_unit` makes no assertion and does not imply `each`. On Business responses, `item.quantity_unit` describes the basis; if absent, it encodes the `each` machine identity (`C62`, 0) and `quantity` counts whole items. + Quantity of the item being purchased. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/line_item_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/line_item_update_request.py index a5c78e4..fc43593 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/line_item_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/line_item_update_request.py @@ -33,9 +33,9 @@ class LineItemUpdateRequest(BaseModel): ) id: str | None = None item: item_update_request.ItemUpdateRequest - quantity: int = Field(..., ge=1, le=9007199254740991) + quantity: int = Field(..., ge=1) """ - Always an integer step count. On Platform requests, steps use the item's Business-authoritative sale basis; omitting `item.quantity_unit` makes no assertion and does not imply `each`. On Business responses, `item.quantity_unit` describes the basis; if absent, it encodes the `each` machine identity (`C62`, 0) and `quantity` counts whole items. + Quantity of the item being purchased. """ parent_id: str | None = None """ diff --git a/src/ucp_sdk/models/schemas/common/types/link.py b/src/ucp_sdk/models/schemas/shopping/types/link.py similarity index 100% rename from src/ucp_sdk/models/schemas/common/types/link.py rename to src/ucp_sdk/models/schemas/shopping/types/link.py diff --git a/src/ucp_sdk/models/schemas/shopping/types/location_destination.py b/src/ucp_sdk/models/schemas/shopping/types/location_destination.py deleted file mode 100644 index 9860bac..0000000 --- a/src/ucp_sdk/models/schemas/shopping/types/location_destination.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from typing import Literal - -from pydantic import ConfigDict - -from ...common.types.location_summary import LocationSummary - - -class BusinessLocationDestination(LocationSummary): - """ - A business location fulfillment destination. Business-authored and response-only: the Platform selects a location via `selected_destination_id` rather than writing destinations. - """ - - model_config = ConfigDict( - extra="allow", - ) - type: Literal["business_location"] - """ - Destination type discriminator. Response-only. - """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/location_destination_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/location_destination_create_request.py deleted file mode 100644 index 90cb2a5..0000000 --- a/src/ucp_sdk/models/schemas/shopping/types/location_destination_create_request.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from pydantic import ConfigDict - -from ...common.types.location_summary_create_request import ( - LocationSummaryCreateRequest, -) - - -class BusinessLocationDestinationCreateRequest(LocationSummaryCreateRequest): - """ - A business location fulfillment destination. Business-authored and response-only: the Platform selects a location via `selected_destination_id` rather than writing destinations. - """ - - model_config = ConfigDict( - extra="allow", - ) diff --git a/src/ucp_sdk/models/schemas/shopping/types/location_destination_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/location_destination_update_request.py deleted file mode 100644 index 3154a71..0000000 --- a/src/ucp_sdk/models/schemas/shopping/types/location_destination_update_request.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from pydantic import ConfigDict - -from ...common.types.location_summary_update_request import ( - LocationSummaryUpdateRequest, -) - - -class BusinessLocationDestinationUpdateRequest(LocationSummaryUpdateRequest): - """ - A business location fulfillment destination. Business-authored and response-only: the Platform selects a location via `selected_destination_id` rather than writing destinations. - """ - - model_config = ConfigDict( - extra="allow", - ) diff --git a/src/ucp_sdk/models/schemas/common/types/media.py b/src/ucp_sdk/models/schemas/shopping/types/media.py similarity index 96% rename from src/ucp_sdk/models/schemas/common/types/media.py rename to src/ucp_sdk/models/schemas/shopping/types/media.py index b716792..dc8338a 100644 --- a/src/ucp_sdk/models/schemas/common/types/media.py +++ b/src/ucp_sdk/models/schemas/shopping/types/media.py @@ -23,7 +23,7 @@ class Media(BaseModel): """ - Media item (image, video, etc.). + Product media item (image, video, etc.). """ model_config = ConfigDict( diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_base.py b/src/ucp_sdk/models/schemas/shopping/types/merchant_fulfillment_config.py similarity index 54% rename from src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_base.py rename to src/ucp_sdk/models/schemas/shopping/types/merchant_fulfillment_config.py index b54b7de..f4b1afd 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_base.py +++ b/src/ucp_sdk/models/schemas/shopping/types/merchant_fulfillment_config.py @@ -18,28 +18,44 @@ from __future__ import annotations -from pydantic import BaseModel, ConfigDict +from typing import Literal -from ...common.types import description as description_1 +from pydantic import BaseModel, ConfigDict -class FulfillmentOptionBase(BaseModel): +class AllowsMultiDestination(BaseModel): """ - Common base for a fulfillment option: an addressable, renderable choice (e.g. Standard, Express). Catalog uses this base directly; checkout composes it with cost and timing. + Permits multiple destinations per method type. """ model_config = ConfigDict( - extra="allow", + extra="forbid", ) - id: str + shipping: bool | None = None + """ + Multiple shipping destinations allowed. """ - Unique identifier for this fulfillment option. + pickup: bool | None = None """ - title: str + Multiple pickup locations allowed. + """ + + +class MerchantFulfillmentConfig(BaseModel): + """ + Merchant's fulfillment configuration. + """ + + model_config = ConfigDict( + extra="allow", + ) + allows_multi_destination: AllowsMultiDestination | None = None """ - Short label that distinguishes this option from its siblings (e.g. 'Standard', 'Express Shipping', 'Curbside Pickup'). + Permits multiple destinations per method type. """ - description: description_1.Description | None = None + allows_method_combinations: ( + list[list[Literal["shipping", "pickup"]]] | None + ) = None """ - Supplementary context for the title (e.g. 'Arrives in 4 business days', 'Arrives Dec 12-15 via FedEx'). Directly renderable; MUST NOT repeat the title. + Allowed method type combinations. """ diff --git a/src/ucp_sdk/models/schemas/common/types/message.py b/src/ucp_sdk/models/schemas/shopping/types/message.py similarity index 100% rename from src/ucp_sdk/models/schemas/common/types/message.py rename to src/ucp_sdk/models/schemas/shopping/types/message.py diff --git a/src/ucp_sdk/models/schemas/common/types/message_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/message_create_request.py similarity index 100% rename from src/ucp_sdk/models/schemas/common/types/message_create_request.py rename to src/ucp_sdk/models/schemas/shopping/types/message_create_request.py diff --git a/src/ucp_sdk/models/schemas/common/types/message_error.py b/src/ucp_sdk/models/schemas/shopping/types/message_error.py similarity index 71% rename from src/ucp_sdk/models/schemas/common/types/message_error.py rename to src/ucp_sdk/models/schemas/shopping/types/message_error.py index 9ac973c..e74117c 100644 --- a/src/ucp_sdk/models/schemas/common/types/message_error.py +++ b/src/ucp_sdk/models/schemas/shopping/types/message_error.py @@ -36,7 +36,7 @@ class MessageError(BaseModel): code: error_code.ErrorCode path: str | None = None """ - RFC 9535 JSONPath to the component the message refers to (e.g., $.line_items[0]). + RFC 9535 JSONPath to the component the message refers to (e.g., $.items[1]). """ content_type: Literal["plain", "markdown"] | None = "plain" """ @@ -53,5 +53,5 @@ class MessageError(BaseModel): "unrecoverable", ] """ - Reflects the resource state and recommended action. 'recoverable': platform can resolve the condition in band, for example by modifying inputs or processing a related Action, and submit a new operation when needed. 'requires_buyer_input': merchant requires information their API doesn't support collecting programmatically (checkout incomplete). 'requires_buyer_review': buyer must authorize before order placement due to policy, regulatory, or entitlement rules. 'unrecoverable': no valid resource exists to act on, retry with new resource or inputs. Errors with 'requires_*' severity contribute to 'status: requires_escalation'. + Reflects the resource state and recommended action. 'recoverable': platform can resolve by modifying inputs and retrying via API. 'requires_buyer_input': merchant requires information their API doesn't support collecting programmatically (checkout incomplete). 'requires_buyer_review': buyer must authorize before order placement due to policy, regulatory, or entitlement rules. 'unrecoverable': no valid resource exists to act on, retry with new resource or inputs. Errors with 'requires_*' severity contribute to 'status: requires_escalation'. """ diff --git a/src/ucp_sdk/models/schemas/common/types/message_error_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/message_error_create_request.py similarity index 72% rename from src/ucp_sdk/models/schemas/common/types/message_error_create_request.py rename to src/ucp_sdk/models/schemas/shopping/types/message_error_create_request.py index cd13b78..9375f6c 100644 --- a/src/ucp_sdk/models/schemas/common/types/message_error_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/message_error_create_request.py @@ -36,7 +36,7 @@ class MessageErrorCreateRequest(BaseModel): code: error_code_create_request.ErrorCodeCreateRequest path: str | None = None """ - RFC 9535 JSONPath to the component the message refers to (e.g., $.line_items[0]). + RFC 9535 JSONPath to the component the message refers to (e.g., $.items[1]). """ content_type: Literal["plain", "markdown"] | None = "plain" """ @@ -53,5 +53,5 @@ class MessageErrorCreateRequest(BaseModel): "unrecoverable", ] """ - Reflects the resource state and recommended action. 'recoverable': platform can resolve the condition in band, for example by modifying inputs or processing a related Action, and submit a new operation when needed. 'requires_buyer_input': merchant requires information their API doesn't support collecting programmatically (checkout incomplete). 'requires_buyer_review': buyer must authorize before order placement due to policy, regulatory, or entitlement rules. 'unrecoverable': no valid resource exists to act on, retry with new resource or inputs. Errors with 'requires_*' severity contribute to 'status: requires_escalation'. + Reflects the resource state and recommended action. 'recoverable': platform can resolve by modifying inputs and retrying via API. 'requires_buyer_input': merchant requires information their API doesn't support collecting programmatically (checkout incomplete). 'requires_buyer_review': buyer must authorize before order placement due to policy, regulatory, or entitlement rules. 'unrecoverable': no valid resource exists to act on, retry with new resource or inputs. Errors with 'requires_*' severity contribute to 'status: requires_escalation'. """ diff --git a/src/ucp_sdk/models/schemas/common/types/message_error_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/message_error_update_request.py similarity index 72% rename from src/ucp_sdk/models/schemas/common/types/message_error_update_request.py rename to src/ucp_sdk/models/schemas/shopping/types/message_error_update_request.py index 94fcb77..3ad566d 100644 --- a/src/ucp_sdk/models/schemas/common/types/message_error_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/message_error_update_request.py @@ -36,7 +36,7 @@ class MessageErrorUpdateRequest(BaseModel): code: error_code_update_request.ErrorCodeUpdateRequest path: str | None = None """ - RFC 9535 JSONPath to the component the message refers to (e.g., $.line_items[0]). + RFC 9535 JSONPath to the component the message refers to (e.g., $.items[1]). """ content_type: Literal["plain", "markdown"] | None = "plain" """ @@ -53,5 +53,5 @@ class MessageErrorUpdateRequest(BaseModel): "unrecoverable", ] """ - Reflects the resource state and recommended action. 'recoverable': platform can resolve the condition in band, for example by modifying inputs or processing a related Action, and submit a new operation when needed. 'requires_buyer_input': merchant requires information their API doesn't support collecting programmatically (checkout incomplete). 'requires_buyer_review': buyer must authorize before order placement due to policy, regulatory, or entitlement rules. 'unrecoverable': no valid resource exists to act on, retry with new resource or inputs. Errors with 'requires_*' severity contribute to 'status: requires_escalation'. + Reflects the resource state and recommended action. 'recoverable': platform can resolve by modifying inputs and retrying via API. 'requires_buyer_input': merchant requires information their API doesn't support collecting programmatically (checkout incomplete). 'requires_buyer_review': buyer must authorize before order placement due to policy, regulatory, or entitlement rules. 'unrecoverable': no valid resource exists to act on, retry with new resource or inputs. Errors with 'requires_*' severity contribute to 'status: requires_escalation'. """ diff --git a/src/ucp_sdk/models/schemas/common/types/message_info.py b/src/ucp_sdk/models/schemas/shopping/types/message_info.py similarity index 93% rename from src/ucp_sdk/models/schemas/common/types/message_info.py rename to src/ucp_sdk/models/schemas/shopping/types/message_info.py index 2057e35..b8ef016 100644 --- a/src/ucp_sdk/models/schemas/common/types/message_info.py +++ b/src/ucp_sdk/models/schemas/shopping/types/message_info.py @@ -35,7 +35,7 @@ class MessageInfo(BaseModel): """ path: str | None = None """ - RFC 9535 JSONPath to the component the message refers to (e.g., $.line_items[0]). + RFC 9535 JSONPath to the component the message refers to. """ code: info_code.InfoCode | None = None content_type: Literal["plain", "markdown"] | None = "plain" diff --git a/src/ucp_sdk/models/schemas/common/types/message_info_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/message_info_create_request.py similarity index 93% rename from src/ucp_sdk/models/schemas/common/types/message_info_create_request.py rename to src/ucp_sdk/models/schemas/shopping/types/message_info_create_request.py index 79b7738..aa715d7 100644 --- a/src/ucp_sdk/models/schemas/common/types/message_info_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/message_info_create_request.py @@ -35,7 +35,7 @@ class MessageInfoCreateRequest(BaseModel): """ path: str | None = None """ - RFC 9535 JSONPath to the component the message refers to (e.g., $.line_items[0]). + RFC 9535 JSONPath to the component the message refers to. """ code: info_code_create_request.InfoCodeCreateRequest | None = None content_type: Literal["plain", "markdown"] | None = "plain" diff --git a/src/ucp_sdk/models/schemas/common/types/message_info_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/message_info_update_request.py similarity index 93% rename from src/ucp_sdk/models/schemas/common/types/message_info_update_request.py rename to src/ucp_sdk/models/schemas/shopping/types/message_info_update_request.py index 6a9f79c..5f206ad 100644 --- a/src/ucp_sdk/models/schemas/common/types/message_info_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/message_info_update_request.py @@ -35,7 +35,7 @@ class MessageInfoUpdateRequest(BaseModel): """ path: str | None = None """ - RFC 9535 JSONPath to the component the message refers to (e.g., $.line_items[0]). + RFC 9535 JSONPath to the component the message refers to. """ code: info_code_update_request.InfoCodeUpdateRequest | None = None content_type: Literal["plain", "markdown"] | None = "plain" diff --git a/src/ucp_sdk/models/schemas/common/types/message_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/message_update_request.py similarity index 100% rename from src/ucp_sdk/models/schemas/common/types/message_update_request.py rename to src/ucp_sdk/models/schemas/shopping/types/message_update_request.py diff --git a/src/ucp_sdk/models/schemas/common/types/message_warning.py b/src/ucp_sdk/models/schemas/shopping/types/message_warning.py similarity index 95% rename from src/ucp_sdk/models/schemas/common/types/message_warning.py rename to src/ucp_sdk/models/schemas/shopping/types/message_warning.py index e816234..772134f 100644 --- a/src/ucp_sdk/models/schemas/common/types/message_warning.py +++ b/src/ucp_sdk/models/schemas/shopping/types/message_warning.py @@ -35,7 +35,7 @@ class MessageWarning(BaseModel): """ path: str | None = None """ - RFC 9535 JSONPath to the component the message refers to (e.g., $.line_items[0]). + JSONPath (RFC 9535) to related field (e.g., $.line_items[0]). """ code: warning_code.WarningCode content: str diff --git a/src/ucp_sdk/models/schemas/common/types/message_warning_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/message_warning_create_request.py similarity index 95% rename from src/ucp_sdk/models/schemas/common/types/message_warning_create_request.py rename to src/ucp_sdk/models/schemas/shopping/types/message_warning_create_request.py index 712c72f..5294a25 100644 --- a/src/ucp_sdk/models/schemas/common/types/message_warning_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/message_warning_create_request.py @@ -35,7 +35,7 @@ class MessageWarningCreateRequest(BaseModel): """ path: str | None = None """ - RFC 9535 JSONPath to the component the message refers to (e.g., $.line_items[0]). + JSONPath (RFC 9535) to related field (e.g., $.line_items[0]). """ code: warning_code_create_request.WarningCodeCreateRequest content: str diff --git a/src/ucp_sdk/models/schemas/common/types/message_warning_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/message_warning_update_request.py similarity index 95% rename from src/ucp_sdk/models/schemas/common/types/message_warning_update_request.py rename to src/ucp_sdk/models/schemas/shopping/types/message_warning_update_request.py index 83944e6..44cd08d 100644 --- a/src/ucp_sdk/models/schemas/common/types/message_warning_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/message_warning_update_request.py @@ -35,7 +35,7 @@ class MessageWarningUpdateRequest(BaseModel): """ path: str | None = None """ - RFC 9535 JSONPath to the component the message refers to (e.g., $.line_items[0]). + JSONPath (RFC 9535) to related field (e.g., $.line_items[0]). """ code: warning_code_update_request.WarningCodeUpdateRequest content: str diff --git a/src/ucp_sdk/models/schemas/shopping/types/network_token_credential.py b/src/ucp_sdk/models/schemas/shopping/types/network_token_credential.py deleted file mode 100644 index 522e07b..0000000 --- a/src/ucp_sdk/models/schemas/shopping/types/network_token_credential.py +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from typing import Literal - -from pydantic import ConfigDict, Field - -from .payment_credential import PaymentCredential - - -class NetworkTokenCredential(PaymentCredential): - """ - A card-network token credential verified with a transaction cryptogram. The `number` field carries the network token or wallet-provisioned token rather than the underlying FPAN. - """ - - model_config = ConfigDict( - extra="allow", - ) - type: Literal["network_token"] - """ - The credential type identifier for network token credentials. - """ - number: str = Field(..., examples=["5204240000004242"]) - """ - Network token or wallet-provisioned token replacing the underlying FPAN. - """ - expiry_month: int | None = None - """ - The month of the token's expiration date (1-12). - """ - expiry_year: int | None = None - """ - The year of the token's expiration date. - """ - name: str | None = Field(None, examples=["Jane Doe"]) - """ - Cardholder name. - """ - cryptogram: str = Field(..., examples=["gXc5UCLnM6ckD7pjM1TdPA=="]) - """ - Transaction cryptogram or dynamic CVC (dCVV), in the long or short form expected by the card network or processor. - """ - eci_value: str | None = Field(None, examples=["07"]) - """ - Electronic Commerce Indicator / Security Level Indicator associated with the transaction. - """ - token_requestor_id: str | None = Field(None, examples=["12345678901"]) - """ - Payment network token requestor identifier, when required by the processor or network-token program. - """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/order_line_item.py b/src/ucp_sdk/models/schemas/shopping/types/order_line_item.py index 131c550..cd80f04 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/order_line_item.py +++ b/src/ucp_sdk/models/schemas/shopping/types/order_line_item.py @@ -22,29 +22,29 @@ from pydantic import BaseModel, ConfigDict, Field -from ...common.types import total as total_1 from . import item as item_1 +from . import total as total_1 class Quantity(BaseModel): """ - Tracks the line item's original, current active, and fulfilled quantities. All three values use the same inherited `item.quantity_unit`. When `item.quantity_unit` is absent on an authoritative order response, each step is one whole item (`each`) under the shared default. + Quantity tracking for the line item. """ model_config = ConfigDict( extra="allow", ) - original: int | None = Field(None, ge=0, le=9007199254740991) + original: int | None = Field(None, ge=0) """ - Quantity from the original checkout, expressed as an integer step count. + Quantity from the original checkout. """ - total: int = Field(..., ge=0, le=9007199254740991) + total: int = Field(..., ge=0) """ - Current active quantity after returns, cancellations, or other order changes, expressed as an integer step count. + Current total active quantity. May differ from original due to post-order modifications (e.g., returns or cancellations). """ - fulfilled: int = Field(..., ge=0, le=9007199254740991) + fulfilled: int = Field(..., ge=0) """ - Quantity fulfilled so far, expressed as an integer step count. + Quantity fulfilled so far. """ @@ -58,11 +58,11 @@ class OrderLineItem(BaseModel): """ item: item_1.Item """ - Purchased item data, including identity, price, and sale basis. + Product data (id, title, price, image_url). """ quantity: Quantity """ - Tracks the line item's original, current active, and fulfilled quantities. All three values use the same inherited `item.quantity_unit`. When `item.quantity_unit` is absent on an authoritative order response, each step is one whole item (`each`) under the shared default. + Quantity tracking for the line item. """ totals: list[total_1.Total] """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/order_line_item_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/order_line_item_create_request.py index 6e0fe34..56693e0 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/order_line_item_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/order_line_item_create_request.py @@ -22,29 +22,28 @@ from pydantic import BaseModel, ConfigDict, Field -from ...common.types import total_create_request -from . import item_create_request +from . import item_create_request, total_create_request class Quantity(BaseModel): """ - Tracks the line item's original, current active, and fulfilled quantities. All three values use the same inherited `item.quantity_unit`. When `item.quantity_unit` is absent on an authoritative order response, each step is one whole item (`each`) under the shared default. + Quantity tracking for the line item. """ model_config = ConfigDict( extra="allow", ) - original: int | None = Field(None, ge=0, le=9007199254740991) + original: int | None = Field(None, ge=0) """ - Quantity from the original checkout, expressed as an integer step count. + Quantity from the original checkout. """ - total: int = Field(..., ge=0, le=9007199254740991) + total: int = Field(..., ge=0) """ - Current active quantity after returns, cancellations, or other order changes, expressed as an integer step count. + Current total active quantity. May differ from original due to post-order modifications (e.g., returns or cancellations). """ - fulfilled: int = Field(..., ge=0, le=9007199254740991) + fulfilled: int = Field(..., ge=0) """ - Quantity fulfilled so far, expressed as an integer step count. + Quantity fulfilled so far. """ @@ -58,11 +57,11 @@ class OrderLineItemCreateRequest(BaseModel): """ item: item_create_request.ItemCreateRequest """ - Purchased item data, including identity, price, and sale basis. + Product data (id, title, price, image_url). """ quantity: Quantity """ - Tracks the line item's original, current active, and fulfilled quantities. All three values use the same inherited `item.quantity_unit`. When `item.quantity_unit` is absent on an authoritative order response, each step is one whole item (`each`) under the shared default. + Quantity tracking for the line item. """ totals: list[total_create_request.TotalCreateRequest] """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/order_line_item_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/order_line_item_update_request.py index 7db84e2..178d09c 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/order_line_item_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/order_line_item_update_request.py @@ -22,29 +22,28 @@ from pydantic import BaseModel, ConfigDict, Field -from ...common.types import total_update_request -from . import item_update_request +from . import item_update_request, total_update_request class Quantity(BaseModel): """ - Tracks the line item's original, current active, and fulfilled quantities. All three values use the same inherited `item.quantity_unit`. When `item.quantity_unit` is absent on an authoritative order response, each step is one whole item (`each`) under the shared default. + Quantity tracking for the line item. """ model_config = ConfigDict( extra="allow", ) - original: int | None = Field(None, ge=0, le=9007199254740991) + original: int | None = Field(None, ge=0) """ - Quantity from the original checkout, expressed as an integer step count. + Quantity from the original checkout. """ - total: int = Field(..., ge=0, le=9007199254740991) + total: int = Field(..., ge=0) """ - Current active quantity after returns, cancellations, or other order changes, expressed as an integer step count. + Current total active quantity. May differ from original due to post-order modifications (e.g., returns or cancellations). """ - fulfilled: int = Field(..., ge=0, le=9007199254740991) + fulfilled: int = Field(..., ge=0) """ - Quantity fulfilled so far, expressed as an integer step count. + Quantity fulfilled so far. """ @@ -58,11 +57,11 @@ class OrderLineItemUpdateRequest(BaseModel): """ item: item_update_request.ItemUpdateRequest """ - Purchased item data, including identity, price, and sale basis. + Product data (id, title, price, image_url). """ quantity: Quantity """ - Tracks the line item's original, current active, and fulfilled quantities. All three values use the same inherited `item.quantity_unit`. When `item.quantity_unit` is absent on an authoritative order response, each step is one whole item (`each`) under the shared default. + Quantity tracking for the line item. """ totals: list[total_update_request.TotalUpdateRequest] """ diff --git a/src/ucp_sdk/models/schemas/common/types/pagination.py b/src/ucp_sdk/models/schemas/shopping/types/pagination.py similarity index 100% rename from src/ucp_sdk/models/schemas/common/types/pagination.py rename to src/ucp_sdk/models/schemas/shopping/types/pagination.py diff --git a/src/ucp_sdk/models/schemas/shopping/types/pan_credential.py b/src/ucp_sdk/models/schemas/shopping/types/pan_credential.py deleted file mode 100644 index a7ed37c..0000000 --- a/src/ucp_sdk/models/schemas/shopping/types/pan_credential.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from typing import Literal - -from pydantic import ConfigDict, Field - -from .payment_credential import PaymentCredential - - -class PanCredential(PaymentCredential): - """ - A card credential carrying a funding primary account number (FPAN). Credential selection follows the shape of the value on the wire rather than its provenance: a network token surfaced in PAN form and verified with a `cvc` — as with credentials where a dynamic verification code proxies the cryptogram — is carried here, while a token verified with a discrete `cryptogram` uses Network Token Credential. This credential type MUST NOT be used for checkout, only with payment handlers that tokenize or encrypt credentials. CRITICAL: Both parties handling a PAN credential (sender and receiver) MUST be PCI DSS compliant. Transmission MUST use HTTPS/TLS with strong cipher suites. - """ - - model_config = ConfigDict( - extra="allow", - ) - type: Literal["pan"] - """ - The credential type identifier for PAN credentials. - """ - number: str = Field(..., examples=["4242424242424242"]) - """ - Funding primary account number (FPAN). - """ - expiry_month: int | None = None - """ - The month of the card's expiration date (1-12). - """ - expiry_year: int | None = None - """ - The year of the card's expiration date. - """ - name: str | None = Field(None, examples=["Jane Doe"]) - """ - Cardholder name. - """ - cvc: str | None = Field(None, examples=["223"], max_length=4) - """ - Card verification code. - """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/payment_identity.py b/src/ucp_sdk/models/schemas/shopping/types/payment_identity.py index 14b1881..b30f85d 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/payment_identity.py +++ b/src/ucp_sdk/models/schemas/shopping/types/payment_identity.py @@ -23,7 +23,7 @@ class PaymentIdentity(BaseModel): """ - Identity of a participant for token binding. The access_token uniquely identifies the participant whom tokens should be issued to. + Identity of a participant for token binding. The access_token uniquely identifies the participant who tokens should be bound to. """ model_config = ConfigDict( diff --git a/src/ucp_sdk/models/schemas/shopping/types/payment_instrument.py b/src/ucp_sdk/models/schemas/shopping/types/payment_instrument.py index 138c947..4b7bf78 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/payment_instrument.py +++ b/src/ucp_sdk/models/schemas/shopping/types/payment_instrument.py @@ -22,8 +22,7 @@ from pydantic import BaseModel, ConfigDict -from ...common.types import postal_address -from . import payment_credential +from . import payment_credential, postal_address class PaymentInstrument(BaseModel): @@ -36,7 +35,7 @@ class PaymentInstrument(BaseModel): ) id: str """ - A unique identifier for this instrument instance. Typically assigned by the platform for instruments it collects. For a business-owned saved instrument returned on an identity-linked response, this identifier is assigned by the business; the platform MUST treat it as an opaque, business-scoped reference, and the business resolves it server-side when the buyer selects it. + A unique identifier for this instrument instance, assigned by the platform. """ handler_id: str """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/payment_instrument_complete_request.py b/src/ucp_sdk/models/schemas/shopping/types/payment_instrument_complete_request.py index 7acd81f..2aac44e 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/payment_instrument_complete_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/payment_instrument_complete_request.py @@ -22,8 +22,10 @@ from pydantic import BaseModel, ConfigDict -from ...common.types import postal_address_complete_request -from . import payment_credential_complete_request +from . import ( + payment_credential_complete_request, + postal_address_complete_request, +) class PaymentInstrumentCompleteRequest(BaseModel): @@ -36,7 +38,7 @@ class PaymentInstrumentCompleteRequest(BaseModel): ) id: str """ - A unique identifier for this instrument instance. Typically assigned by the platform for instruments it collects. For a business-owned saved instrument returned on an identity-linked response, this identifier is assigned by the business; the platform MUST treat it as an opaque, business-scoped reference, and the business resolves it server-side when the buyer selects it. + A unique identifier for this instrument instance, assigned by the platform. """ handler_id: str """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/payment_instrument_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/payment_instrument_create_request.py index f13e02f..4d7117e 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/payment_instrument_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/payment_instrument_create_request.py @@ -22,8 +22,7 @@ from pydantic import BaseModel, ConfigDict -from ...common.types import postal_address_create_request -from . import payment_credential_create_request +from . import payment_credential_create_request, postal_address_create_request class PaymentInstrumentCreateRequest(BaseModel): @@ -36,7 +35,7 @@ class PaymentInstrumentCreateRequest(BaseModel): ) id: str """ - A unique identifier for this instrument instance. Typically assigned by the platform for instruments it collects. For a business-owned saved instrument returned on an identity-linked response, this identifier is assigned by the business; the platform MUST treat it as an opaque, business-scoped reference, and the business resolves it server-side when the buyer selects it. + A unique identifier for this instrument instance, assigned by the platform. """ handler_id: str """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/payment_instrument_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/payment_instrument_update_request.py index 2c30caf..0a72443 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/payment_instrument_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/payment_instrument_update_request.py @@ -22,8 +22,7 @@ from pydantic import BaseModel, ConfigDict -from ...common.types import postal_address_update_request -from . import payment_credential_update_request +from . import payment_credential_update_request, postal_address_update_request class PaymentInstrumentUpdateRequest(BaseModel): @@ -36,7 +35,7 @@ class PaymentInstrumentUpdateRequest(BaseModel): ) id: str """ - A unique identifier for this instrument instance. Typically assigned by the platform for instruments it collects. For a business-owned saved instrument returned on an identity-linked response, this identifier is assigned by the business; the platform MUST treat it as an opaque, business-scoped reference, and the business resolves it server-side when the buyer selects it. + A unique identifier for this instrument instance, assigned by the platform. """ handler_id: str """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/payment_schedule.py b/src/ucp_sdk/models/schemas/shopping/types/payment_schedule.py deleted file mode 100644 index 51e8cb9..0000000 --- a/src/ucp_sdk/models/schemas/shopping/types/payment_schedule.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from pydantic import AwareDatetime, BaseModel, ConfigDict - -from ...common.types import amount as amount_1 -from ...common.types import description as description_1 - - -class PaymentSchedule(BaseModel): - """ - A single payment that settles part or all of the checkout under a payment term. Timing is stated in buyer-facing text; `type` and `due_at` are supplementary machine-readable signals derived from it. - """ - - model_config = ConfigDict( - extra="allow", - ) - id: str - """ - Identifier for this payment schedule, unique within its payment term. Businesses SHOULD keep it stable across responses while the schedule remains the same payment. - """ - type: str - """ - Timing class, drawn from an open vocabulary. `immediate` is the only value with defined meaning: the payment is due when the checkout is completed. Any other value means the payment is not due at completion, and `description` states when it is due. Whether a due payment is authorized, captured, or settled at that moment is payment-handler behavior and outside this extension. Businesses MAY use additional values (e.g. `deferred`, `on_shipment`); Platforms MUST treat unrecognized values as not due at completion. - """ - description: description_1.Description - """ - Complete buyer-facing statement of when and how this payment is due. Businesses MUST make this field sufficient on its own: a Platform that recognizes no `type` value and reads no other field MUST be able to present this schedule correctly. Platforms MAY use `type` and `due_at` for enhanced presentation, but MUST NOT present derived timing that contradicts this field. - """ - due_at: AwareDatetime | None = None - """ - Absolute RFC 3339 date-time when this payment is due, when the Business can determine one at checkout. Supplementary to `description`, never a replacement for it. Omitted when the due date depends on a future event (e.g. 'due on delivery'); the timing is then stated in `description` alone. - """ - amount: amount_1.Amount - """ - The amount charged when this payment is taken, inclusive of tax and every other charge, in the Checkout currency's minor units (ISO 4217). A schedule states an amount rather than a totals breakdown: the purchase is priced once at the Checkout, and a schedule moves part or all of that price. Where the selected term changes what the purchase costs, that difference appears in `checkout.totals`, not here. - """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/payment_term.py b/src/ucp_sdk/models/schemas/shopping/types/payment_term.py deleted file mode 100644 index 0f66739..0000000 --- a/src/ucp_sdk/models/schemas/shopping/types/payment_term.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from pydantic import BaseModel, ConfigDict, Field - -from ...common.types import description as description_1 -from . import payment_schedule - - -class PaymentTerm(BaseModel): - """ - A way of paying for the checkout: one or more payment schedules that together cover its total. - """ - - model_config = ConfigDict( - extra="allow", - ) - id: str - """ - Unique identifier for this payment term within the checkout. Referenced by `payment.selected_term_id`. - """ - title: str - """ - Short label that distinguishes this term from its siblings (e.g. 'Pay now', 'Pay in 4', 'Deposit + balance at check-in'). - """ - description: description_1.Description | None = None - """ - Supplementary context for the title (e.g. 'Save 5% by paying today'). Directly renderable; MUST NOT repeat the title. - """ - schedules: list[payment_schedule.PaymentSchedule] = Field(..., min_length=1) - """ - Payment schedules that settle this checkout under this term, in the order they come due. - """ diff --git a/src/ucp_sdk/models/schemas/common/types/postal_address.py b/src/ucp_sdk/models/schemas/shopping/types/postal_address.py similarity index 100% rename from src/ucp_sdk/models/schemas/common/types/postal_address.py rename to src/ucp_sdk/models/schemas/shopping/types/postal_address.py diff --git a/src/ucp_sdk/models/schemas/common/types/postal_address_complete_request.py b/src/ucp_sdk/models/schemas/shopping/types/postal_address_complete_request.py similarity index 100% rename from src/ucp_sdk/models/schemas/common/types/postal_address_complete_request.py rename to src/ucp_sdk/models/schemas/shopping/types/postal_address_complete_request.py diff --git a/src/ucp_sdk/models/schemas/common/types/postal_address_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/postal_address_create_request.py similarity index 100% rename from src/ucp_sdk/models/schemas/common/types/postal_address_create_request.py rename to src/ucp_sdk/models/schemas/shopping/types/postal_address_create_request.py diff --git a/src/ucp_sdk/models/schemas/common/types/postal_address_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/postal_address_update_request.py similarity index 100% rename from src/ucp_sdk/models/schemas/common/types/postal_address_update_request.py rename to src/ucp_sdk/models/schemas/shopping/types/postal_address_update_request.py diff --git a/src/ucp_sdk/models/schemas/common/types/price.py b/src/ucp_sdk/models/schemas/shopping/types/price.py similarity index 100% rename from src/ucp_sdk/models/schemas/common/types/price.py rename to src/ucp_sdk/models/schemas/shopping/types/price.py diff --git a/src/ucp_sdk/models/schemas/common/types/price_filter.py b/src/ucp_sdk/models/schemas/shopping/types/price_filter.py similarity index 100% rename from src/ucp_sdk/models/schemas/common/types/price_filter.py rename to src/ucp_sdk/models/schemas/shopping/types/price_filter.py diff --git a/src/ucp_sdk/models/schemas/common/types/price_range.py b/src/ucp_sdk/models/schemas/shopping/types/price_range.py similarity index 92% rename from src/ucp_sdk/models/schemas/common/types/price_range.py rename to src/ucp_sdk/models/schemas/shopping/types/price_range.py index 1c8e47b..d3129db 100644 --- a/src/ucp_sdk/models/schemas/common/types/price_range.py +++ b/src/ucp_sdk/models/schemas/shopping/types/price_range.py @@ -25,7 +25,7 @@ class PriceRange(BaseModel): """ - A price range representing minimum and maximum values (e.g., a common example in retail shopping is when prices vary across product variants). + A price range representing minimum and maximum values (e.g., across product variants). """ model_config = ConfigDict( diff --git a/src/ucp_sdk/models/schemas/shopping/types/product.py b/src/ucp_sdk/models/schemas/shopping/types/product.py index 57b9363..6fa39d0 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/product.py +++ b/src/ucp_sdk/models/schemas/shopping/types/product.py @@ -22,10 +22,11 @@ from pydantic import AnyUrl, BaseModel, ConfigDict, Field -from ...common.types import description as description_1 -from ...common.types import media as media_1 -from ...common.types import price_range as price_range_1 -from . import category, product_option +from . import category +from . import description as description_1 +from . import media as media_1 +from . import price_range as price_range_1 +from . import product_option from . import rating as rating_1 from . import variant diff --git a/src/ucp_sdk/models/schemas/common/types/location_summary.py b/src/ucp_sdk/models/schemas/shopping/types/retail_location.py similarity index 85% rename from src/ucp_sdk/models/schemas/common/types/location_summary.py rename to src/ucp_sdk/models/schemas/shopping/types/retail_location.py index 8ae5eef..c0353af 100644 --- a/src/ucp_sdk/models/schemas/common/types/location_summary.py +++ b/src/ucp_sdk/models/schemas/shopping/types/retail_location.py @@ -23,9 +23,9 @@ from . import postal_address -class LocationSummary(BaseModel): +class RetailLocation(BaseModel): """ - A summary of a business location. + A pickup location (retail store, locker, etc.). """ model_config = ConfigDict( @@ -33,11 +33,11 @@ class LocationSummary(BaseModel): ) id: str """ - Stable, opaque, Business-scoped Location identifier. + Unique location identifier. """ name: str """ - Buyer-facing, Business-owned display name. + Location name (e.g., store name). """ address: postal_address.PostalAddress | None = None """ diff --git a/src/ucp_sdk/models/schemas/common/types/location_summary_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/retail_location_create_request.py similarity index 70% rename from src/ucp_sdk/models/schemas/common/types/location_summary_create_request.py rename to src/ucp_sdk/models/schemas/shopping/types/retail_location_create_request.py index 683453b..4d42caf 100644 --- a/src/ucp_sdk/models/schemas/common/types/location_summary_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/retail_location_create_request.py @@ -20,16 +20,24 @@ from pydantic import BaseModel, ConfigDict +from . import postal_address_create_request -class LocationSummaryCreateRequest(BaseModel): + +class RetailLocationCreateRequest(BaseModel): """ - A summary of a business location. + A pickup location (retail store, locker, etc.). """ model_config = ConfigDict( extra="allow", ) - id: str + name: str + """ + Location name (e.g., store name). + """ + address: postal_address_create_request.PostalAddressCreateRequest | None = ( + None + ) """ - Stable, opaque, Business-scoped Location identifier. + Physical address of the location. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_base_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/retail_location_update_request.py similarity index 68% rename from src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_base_create_request.py rename to src/ucp_sdk/models/schemas/shopping/types/retail_location_update_request.py index 5431e66..b5aa0de 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_base_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/retail_location_update_request.py @@ -20,12 +20,24 @@ from pydantic import BaseModel, ConfigDict +from . import postal_address_update_request -class FulfillmentOptionBaseCreateRequest(BaseModel): + +class RetailLocationUpdateRequest(BaseModel): """ - Common base for a fulfillment option: an addressable, renderable choice (e.g. Standard, Express). Catalog uses this base directly; checkout composes it with cost and timing. + A pickup location (retail store, locker, etc.). """ model_config = ConfigDict( extra="allow", ) + name: str + """ + Location name (e.g., store name). + """ + address: postal_address_update_request.PostalAddressUpdateRequest | None = ( + None + ) + """ + Physical address of the location. + """ diff --git a/src/ucp_sdk/models/schemas/common/types/reverse_domain_name.py b/src/ucp_sdk/models/schemas/shopping/types/reverse_domain_name.py similarity index 57% rename from src/ucp_sdk/models/schemas/common/types/reverse_domain_name.py rename to src/ucp_sdk/models/schemas/shopping/types/reverse_domain_name.py index 733442e..3905247 100644 --- a/src/ucp_sdk/models/schemas/common/types/reverse_domain_name.py +++ b/src/ucp_sdk/models/schemas/shopping/types/reverse_domain_name.py @@ -29,20 +29,11 @@ str, Field( ..., - examples=[ - "dev.ucp.shopping.checkout", - "dev.ucp.common.identity_linking", - "com.example.loyalty_gold", - "com.example-shop.checkout", - "com.2example.cart", - "uk.co.example-shop.checkout", - "xn--p1ai.example.checkout", - ], - pattern="^[a-z](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9_])?)+$", + pattern="^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$", title="Reverse Domain Name", ), ], ) """ -Reverse-domain identifier used for collision-safe namespacing of capabilities, services, handlers, eligibility claims, and extension-contributed keys. Must contain at least two dot-separated segments (e.g., 'dev.ucp.shopping.checkout', 'com.example.loyalty_gold'). Segments after the first are domain- or identifier-derived: they may contain interior hyphens, may start with a digit, and may contain underscores (e.g., 'com.example-shop.checkout', 'com.2example.cart', 'dev.ucp.common.identity_linking'), but must not start or end with a hyphen. The first segment (the reversed top-level domain) is letters and digits, and may contain interior hyphens to support internationalized (punycode) top-level domains such as 'xn--p1ai'. +Reverse-domain identifier used for collision-safe namespacing of capabilities, services, handlers, eligibility claims, and extension-contributed keys. Must contain at least two dot-separated segments (e.g., 'dev.ucp.shopping.checkout', 'com.example.loyalty_gold'). """ diff --git a/src/ucp_sdk/models/schemas/common/types/reverse_domain_name_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/reverse_domain_name_create_request.py similarity index 58% rename from src/ucp_sdk/models/schemas/common/types/reverse_domain_name_create_request.py rename to src/ucp_sdk/models/schemas/shopping/types/reverse_domain_name_create_request.py index b8ae8ba..01bec46 100644 --- a/src/ucp_sdk/models/schemas/common/types/reverse_domain_name_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/reverse_domain_name_create_request.py @@ -29,20 +29,11 @@ str, Field( ..., - examples=[ - "dev.ucp.shopping.checkout", - "dev.ucp.common.identity_linking", - "com.example.loyalty_gold", - "com.example-shop.checkout", - "com.2example.cart", - "uk.co.example-shop.checkout", - "xn--p1ai.example.checkout", - ], - pattern="^[a-z](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9_])?)+$", + pattern="^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$", title="Reverse Domain Name Create Request", ), ], ) """ -Reverse-domain identifier used for collision-safe namespacing of capabilities, services, handlers, eligibility claims, and extension-contributed keys. Must contain at least two dot-separated segments (e.g., 'dev.ucp.shopping.checkout', 'com.example.loyalty_gold'). Segments after the first are domain- or identifier-derived: they may contain interior hyphens, may start with a digit, and may contain underscores (e.g., 'com.example-shop.checkout', 'com.2example.cart', 'dev.ucp.common.identity_linking'), but must not start or end with a hyphen. The first segment (the reversed top-level domain) is letters and digits, and may contain interior hyphens to support internationalized (punycode) top-level domains such as 'xn--p1ai'. +Reverse-domain identifier used for collision-safe namespacing of capabilities, services, handlers, eligibility claims, and extension-contributed keys. Must contain at least two dot-separated segments (e.g., 'dev.ucp.shopping.checkout', 'com.example.loyalty_gold'). """ diff --git a/src/ucp_sdk/models/schemas/common/types/reverse_domain_name_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/reverse_domain_name_update_request.py similarity index 58% rename from src/ucp_sdk/models/schemas/common/types/reverse_domain_name_update_request.py rename to src/ucp_sdk/models/schemas/shopping/types/reverse_domain_name_update_request.py index f0beeca..613ed16 100644 --- a/src/ucp_sdk/models/schemas/common/types/reverse_domain_name_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/reverse_domain_name_update_request.py @@ -29,20 +29,11 @@ str, Field( ..., - examples=[ - "dev.ucp.shopping.checkout", - "dev.ucp.common.identity_linking", - "com.example.loyalty_gold", - "com.example-shop.checkout", - "com.2example.cart", - "uk.co.example-shop.checkout", - "xn--p1ai.example.checkout", - ], - pattern="^[a-z](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9_])?)+$", + pattern="^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$", title="Reverse Domain Name Update Request", ), ], ) """ -Reverse-domain identifier used for collision-safe namespacing of capabilities, services, handlers, eligibility claims, and extension-contributed keys. Must contain at least two dot-separated segments (e.g., 'dev.ucp.shopping.checkout', 'com.example.loyalty_gold'). Segments after the first are domain- or identifier-derived: they may contain interior hyphens, may start with a digit, and may contain underscores (e.g., 'com.example-shop.checkout', 'com.2example.cart', 'dev.ucp.common.identity_linking'), but must not start or end with a hyphen. The first segment (the reversed top-level domain) is letters and digits, and may contain interior hyphens to support internationalized (punycode) top-level domains such as 'xn--p1ai'. +Reverse-domain identifier used for collision-safe namespacing of capabilities, services, handlers, eligibility claims, and extension-contributed keys. Must contain at least two dot-separated segments (e.g., 'dev.ucp.shopping.checkout', 'com.example.loyalty_gold'). """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/search_filters.py b/src/ucp_sdk/models/schemas/shopping/types/search_filters.py index c57be17..6b35cd2 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/search_filters.py +++ b/src/ucp_sdk/models/schemas/shopping/types/search_filters.py @@ -20,7 +20,7 @@ from pydantic import BaseModel, ConfigDict -from ...common.types import price_filter +from . import price_filter class SearchFilters(BaseModel): diff --git a/src/ucp_sdk/models/schemas/shopping/types/shipping_destination.py b/src/ucp_sdk/models/schemas/shopping/types/shipping_destination.py index f5abc26..f8b929d 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/shipping_destination.py +++ b/src/ucp_sdk/models/schemas/shopping/types/shipping_destination.py @@ -18,11 +18,9 @@ from __future__ import annotations -from typing import Literal - from pydantic import ConfigDict -from ...common.types.postal_address import PostalAddress +from .postal_address import PostalAddress class ShippingDestination(PostalAddress): @@ -37,7 +35,3 @@ class ShippingDestination(PostalAddress): """ ID specific to this shipping destination. """ - type: Literal["shipping_address"] - """ - Destination type discriminator. - """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/shipping_destination_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/shipping_destination_create_request.py index b654698..b454152 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/shipping_destination_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/shipping_destination_create_request.py @@ -18,13 +18,9 @@ from __future__ import annotations -from typing import Literal - from pydantic import ConfigDict -from ...common.types.postal_address_create_request import ( - PostalAddressCreateRequest, -) +from .postal_address_create_request import PostalAddressCreateRequest class ShippingDestinationCreateRequest(PostalAddressCreateRequest): @@ -39,7 +35,3 @@ class ShippingDestinationCreateRequest(PostalAddressCreateRequest): """ ID specific to this shipping destination. """ - type: Literal["shipping_address"] | None = None - """ - Destination type discriminator. - """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/shipping_destination_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/shipping_destination_update_request.py index c3b5904..3ab1733 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/shipping_destination_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/shipping_destination_update_request.py @@ -18,13 +18,9 @@ from __future__ import annotations -from typing import Literal - from pydantic import ConfigDict -from ...common.types.postal_address_update_request import ( - PostalAddressUpdateRequest, -) +from .postal_address_update_request import PostalAddressUpdateRequest class ShippingDestinationUpdateRequest(PostalAddressUpdateRequest): @@ -39,7 +35,3 @@ class ShippingDestinationUpdateRequest(PostalAddressUpdateRequest): """ ID specific to this shipping destination. """ - type: Literal["shipping_address"] | None = None - """ - Destination type discriminator. - """ diff --git a/src/ucp_sdk/models/schemas/common/types/signals.py b/src/ucp_sdk/models/schemas/shopping/types/signals.py similarity index 95% rename from src/ucp_sdk/models/schemas/common/types/signals.py rename to src/ucp_sdk/models/schemas/shopping/types/signals.py index 7176f00..2e0ad9c 100644 --- a/src/ucp_sdk/models/schemas/common/types/signals.py +++ b/src/ucp_sdk/models/schemas/shopping/types/signals.py @@ -44,7 +44,7 @@ class Signals(BaseModel): def _enforce_property_names(self): """JSON Schema propertyNames: every extra key must match the declared reverse-domain pattern (schema propertyNames).""" - pattern = "^[a-z](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9_])?)+$" + pattern = "^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$" for key in self.model_extra or {}: if re.fullmatch(pattern, key) is None: raise ValueError( diff --git a/src/ucp_sdk/models/schemas/common/types/signals_complete_request.py b/src/ucp_sdk/models/schemas/shopping/types/signals_complete_request.py similarity index 95% rename from src/ucp_sdk/models/schemas/common/types/signals_complete_request.py rename to src/ucp_sdk/models/schemas/shopping/types/signals_complete_request.py index 0e46c33..fa2ecbf 100644 --- a/src/ucp_sdk/models/schemas/common/types/signals_complete_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/signals_complete_request.py @@ -44,7 +44,7 @@ class SignalsCompleteRequest(BaseModel): def _enforce_property_names(self): """JSON Schema propertyNames: every extra key must match the declared reverse-domain pattern (schema propertyNames).""" - pattern = "^[a-z](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9_])?)+$" + pattern = "^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$" for key in self.model_extra or {}: if re.fullmatch(pattern, key) is None: raise ValueError( diff --git a/src/ucp_sdk/models/schemas/common/types/signals_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/signals_create_request.py similarity index 95% rename from src/ucp_sdk/models/schemas/common/types/signals_create_request.py rename to src/ucp_sdk/models/schemas/shopping/types/signals_create_request.py index 6857861..df0b091 100644 --- a/src/ucp_sdk/models/schemas/common/types/signals_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/signals_create_request.py @@ -44,7 +44,7 @@ class SignalsCreateRequest(BaseModel): def _enforce_property_names(self): """JSON Schema propertyNames: every extra key must match the declared reverse-domain pattern (schema propertyNames).""" - pattern = "^[a-z](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9_])?)+$" + pattern = "^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$" for key in self.model_extra or {}: if re.fullmatch(pattern, key) is None: raise ValueError( diff --git a/src/ucp_sdk/models/schemas/common/types/signals_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/signals_update_request.py similarity index 95% rename from src/ucp_sdk/models/schemas/common/types/signals_update_request.py rename to src/ucp_sdk/models/schemas/shopping/types/signals_update_request.py index 6d6a714..37d37a8 100644 --- a/src/ucp_sdk/models/schemas/common/types/signals_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/signals_update_request.py @@ -44,7 +44,7 @@ class SignalsUpdateRequest(BaseModel): def _enforce_property_names(self): """JSON Schema propertyNames: every extra key must match the declared reverse-domain pattern (schema propertyNames).""" - pattern = "^[a-z](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9_])?)+$" + pattern = "^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$" for key in self.model_extra or {}: if re.fullmatch(pattern, key) is None: raise ValueError( diff --git a/src/ucp_sdk/models/schemas/common/types/signed_amount.py b/src/ucp_sdk/models/schemas/shopping/types/signed_amount.py similarity index 84% rename from src/ucp_sdk/models/schemas/common/types/signed_amount.py rename to src/ucp_sdk/models/schemas/shopping/types/signed_amount.py index 95a93cd..481b1c2 100644 --- a/src/ucp_sdk/models/schemas/common/types/signed_amount.py +++ b/src/ucp_sdk/models/schemas/shopping/types/signed_amount.py @@ -24,16 +24,7 @@ from typing_extensions import TypeAliasType SignedAmount = TypeAliasType( - "SignedAmount", - Annotated[ - int, - Field( - ..., - ge=-9007199254740991, - le=9007199254740991, - title="Signed Amount", - ), - ], + "SignedAmount", Annotated[int, Field(..., title="Signed Amount")] ) """ Monetary amount in the currency's minor unit as defined by ISO 4217. Refer to the currency's exponent to determine minor-to-major ratio (e.g., 2 for USD, 0 for JPY, 3 for KWD). May be negative — the sign is intrinsic to the value (e.g., discounts are negative, charges are positive). diff --git a/src/ucp_sdk/models/schemas/common/types/signed_amount_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/signed_amount_create_request.py similarity index 85% rename from src/ucp_sdk/models/schemas/common/types/signed_amount_create_request.py rename to src/ucp_sdk/models/schemas/shopping/types/signed_amount_create_request.py index baec495..436d0f2 100644 --- a/src/ucp_sdk/models/schemas/common/types/signed_amount_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/signed_amount_create_request.py @@ -25,15 +25,7 @@ SignedAmountCreateRequest = TypeAliasType( "SignedAmountCreateRequest", - Annotated[ - int, - Field( - ..., - ge=-9007199254740991, - le=9007199254740991, - title="Signed Amount Create Request", - ), - ], + Annotated[int, Field(..., title="Signed Amount Create Request")], ) """ Monetary amount in the currency's minor unit as defined by ISO 4217. Refer to the currency's exponent to determine minor-to-major ratio (e.g., 2 for USD, 0 for JPY, 3 for KWD). May be negative — the sign is intrinsic to the value (e.g., discounts are negative, charges are positive). diff --git a/src/ucp_sdk/models/schemas/common/types/signed_amount_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/signed_amount_update_request.py similarity index 85% rename from src/ucp_sdk/models/schemas/common/types/signed_amount_update_request.py rename to src/ucp_sdk/models/schemas/shopping/types/signed_amount_update_request.py index 3e09efe..985bd10 100644 --- a/src/ucp_sdk/models/schemas/common/types/signed_amount_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/signed_amount_update_request.py @@ -25,15 +25,7 @@ SignedAmountUpdateRequest = TypeAliasType( "SignedAmountUpdateRequest", - Annotated[ - int, - Field( - ..., - ge=-9007199254740991, - le=9007199254740991, - title="Signed Amount Update Request", - ), - ], + Annotated[int, Field(..., title="Signed Amount Update Request")], ) """ Monetary amount in the currency's minor unit as defined by ISO 4217. Refer to the currency's exponent to determine minor-to-major ratio (e.g., 2 for USD, 0 for JPY, 3 for KWD). May be negative — the sign is intrinsic to the value (e.g., discounts are negative, charges are positive). diff --git a/src/ucp_sdk/models/schemas/common/types/total.py b/src/ucp_sdk/models/schemas/shopping/types/total.py similarity index 100% rename from src/ucp_sdk/models/schemas/common/types/total.py rename to src/ucp_sdk/models/schemas/shopping/types/total.py diff --git a/src/ucp_sdk/models/schemas/common/types/total_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/total_create_request.py similarity index 100% rename from src/ucp_sdk/models/schemas/common/types/total_create_request.py rename to src/ucp_sdk/models/schemas/shopping/types/total_create_request.py diff --git a/src/ucp_sdk/models/schemas/common/types/total_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/total_update_request.py similarity index 100% rename from src/ucp_sdk/models/schemas/common/types/total_update_request.py rename to src/ucp_sdk/models/schemas/shopping/types/total_update_request.py diff --git a/src/ucp_sdk/models/schemas/common/types/totals.py b/src/ucp_sdk/models/schemas/shopping/types/totals.py similarity index 100% rename from src/ucp_sdk/models/schemas/common/types/totals.py rename to src/ucp_sdk/models/schemas/shopping/types/totals.py diff --git a/src/ucp_sdk/models/schemas/common/types/totals_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/totals_create_request.py similarity index 100% rename from src/ucp_sdk/models/schemas/common/types/totals_create_request.py rename to src/ucp_sdk/models/schemas/shopping/types/totals_create_request.py diff --git a/src/ucp_sdk/models/schemas/common/types/totals_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/totals_update_request.py similarity index 100% rename from src/ucp_sdk/models/schemas/common/types/totals_update_request.py rename to src/ucp_sdk/models/schemas/shopping/types/totals_update_request.py diff --git a/src/ucp_sdk/models/schemas/shopping/types/unit_price.py b/src/ucp_sdk/models/schemas/shopping/types/unit_price.py deleted file mode 100644 index 9760096..0000000 --- a/src/ucp_sdk/models/schemas/shopping/types/unit_price.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from typing import Any - -from pydantic import BaseModel, ConfigDict, Field - -from ...common.types import amount as amount_1 -from ...common.types.measure import Measure as Measure_1 - - -class Measure(Measure_1): - """ - Product quantity in packaging/content (for example, a 750 mL bottle), distinct from `quantity_unit`, which defines the sale basis. Its integer `value` MUST be at least 1. - """ - - model_config = ConfigDict( - extra="allow", - ) - value: Any | None = Field(None, ge=1) - - -class Reference(Measure_1): - """ - Denominator for unit price display (for example, per 100 mL or per 1 kg). Its integer `value` MUST be at least 1. - """ - - model_config = ConfigDict( - extra="allow", - ) - value: Any | None = Field(None, ge=1) - - -class UnitPrice(BaseModel): - """ - Price per standard unit of measurement. MAY be omitted when unit pricing does not apply. `unit_price.currency` MUST equal `price.currency`; the comparator MUST NOT perform currency conversion. `measure.unit` and `reference.unit` MUST be identical; cross-unit conversion is not permitted. Their scales MAY differ; each value represents `value × 10^-scale`. - """ - - model_config = ConfigDict( - extra="allow", - ) - amount: amount_1.Amount - """ - Unit price in ISO 4217 minor units. After satisfying the same-unit invariant, the Business MUST compute the comparator as `(price.amount / (measure.value × 10^-measure.scale)) × (reference.value × 10^-reference.scale)` and round it once to ISO 4217 minor units according to its pricing rules. The returned `unit_price.amount` is authoritative; the Platform MUST NOT recompute or substitute its own result. - """ - currency: str = Field(..., pattern="^[A-Z]{3}$") - """ - ISO 4217 currency code. - """ - measure: Measure - """ - Product quantity in packaging/content (for example, a 750 mL bottle), distinct from `quantity_unit`, which defines the sale basis. Its integer `value` MUST be at least 1. - """ - reference: Reference - """ - Denominator for unit price display (for example, per 100 mL or per 1 kg). Its integer `value` MUST be at least 1. - """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/variant.py b/src/ucp_sdk/models/schemas/shopping/types/variant.py index 4e93a4c..e45f245 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/variant.py +++ b/src/ucp_sdk/models/schemas/shopping/types/variant.py @@ -20,18 +20,16 @@ from typing import Any -from pydantic import AnyUrl, BaseModel, ConfigDict - -from ...common.types import description as description_1 -from ...common.types import link -from ...common.types import media as media_1 -from ...common.types import price as price_1 -from ...common.types import quantity_unit as quantity_unit_1 -from . import availability as availability_1 +from pydantic import AnyUrl, BaseModel, ConfigDict, Field + +from . import amount as amount_1 from . import category +from . import description as description_1 +from . import link +from . import media as media_1 +from . import price as price_1 from . import rating as rating_1 from . import selected_option -from . import unit_price as unit_price_1 class Barcode(BaseModel): @@ -48,6 +46,86 @@ class Barcode(BaseModel): """ +class Measure(BaseModel): + """ + Product quantity in packaging (e.g., 750ml bottle). + """ + + model_config = ConfigDict( + extra="allow", + ) + value: float + """ + Package quantity. + """ + unit: str + """ + Unit of measurement. + """ + + +class Reference(BaseModel): + """ + Denominator for unit price display (e.g., per 100ml, per 1kg). + """ + + model_config = ConfigDict( + extra="allow", + ) + value: int + """ + Reference quantity. + """ + unit: str + """ + Unit of measurement. + """ + + +class UnitPrice(BaseModel): + """ + Price per standard unit of measurement. MAY be omitted when unit pricing does not apply. + """ + + model_config = ConfigDict( + extra="allow", + ) + amount: amount_1.Amount + """ + Unit price in ISO 4217 minor units. Business MUST return precomputed unit price value: (variant.price / measure.value) * reference.value. + """ + currency: str = Field(..., pattern="^[A-Z]{3}$") + """ + ISO 4217 currency code. + """ + measure: Measure + """ + Product quantity in packaging (e.g., 750ml bottle). + """ + reference: Reference + """ + Denominator for unit price display (e.g., per 100ml, per 1kg). + """ + + +class Availability(BaseModel): + """ + Variant availability for purchase. + """ + + model_config = ConfigDict( + extra="allow", + ) + available: bool | None = None + """ + Whether this variant can be purchased. See status for fulfillment details. + """ + status: str | None = None + """ + Qualifies available with fulfillment state. Well-known values: `in_stock`, `backorder`, `preorder`, `out_of_stock`, `discontinued`. + """ + + class Seller(BaseModel): """ Optional seller context for this variant. @@ -108,21 +186,17 @@ class Variant(BaseModel): """ price: price_1.Price """ - Current selling price. Price is the amount per one whole `quantity_unit.unit` (for example, per lb or per hour); when `quantity_unit` is absent, it is per `each`. Line total is `price × quantity × 10^-scale`, computed and rounded once by the Business; `totals` remain authoritative. - """ - quantity_unit: quantity_unit_1.QuantityUnit | None = None - """ - Sale basis this variant's `quantity` is denominated in. The default sale basis is `each`, whose machine identity is (`C62`, 0); `C62` is the UN/CEFACT Rec20 code for one/each. An absent catalog descriptor encodes that default. An `increment` advertises the ordering granularity in steps (for example, `scale` 2 with `increment` 25 sells in 0.25-unit multiples). + Current selling price. """ list_price: price_1.Price | None = None """ List price before discounts (for strikethrough display). """ - unit_price: unit_price_1.UnitPrice | None = None + unit_price: UnitPrice | None = None """ - Price per standard unit of measurement, for shelf-style comparison display. MAY be omitted when unit pricing does not apply. + Price per standard unit of measurement. MAY be omitted when unit pricing does not apply. """ - availability: availability_1.Availability | None = None + availability: Availability | None = None """ Variant availability for purchase. """ diff --git a/src/ucp_sdk/models/schemas/common/types/warning_code.py b/src/ucp_sdk/models/schemas/shopping/types/warning_code.py similarity index 88% rename from src/ucp_sdk/models/schemas/common/types/warning_code.py rename to src/ucp_sdk/models/schemas/shopping/types/warning_code.py index e14ff58..753a9ca 100644 --- a/src/ucp_sdk/models/schemas/common/types/warning_code.py +++ b/src/ucp_sdk/models/schemas/shopping/types/warning_code.py @@ -33,7 +33,6 @@ "final_sale", "prop65", "fulfillment_changed", - "payment_term_changed", "age_restricted", ], title="Warning Code", @@ -41,5 +40,5 @@ ], ) """ -Warning code identifying the type of warning. Standard codes are defined in capability specifications (see examples) and have standardized semantics; freeform codes are permitted. +Warning code identifying the type of warning. Standard codes are defined in capability specs (see examples), and have standardized semantics; freeform codes are permitted. """ diff --git a/src/ucp_sdk/models/schemas/common/types/warning_code_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/warning_code_create_request.py similarity index 88% rename from src/ucp_sdk/models/schemas/common/types/warning_code_create_request.py rename to src/ucp_sdk/models/schemas/shopping/types/warning_code_create_request.py index 27d72d9..e6dd78d 100644 --- a/src/ucp_sdk/models/schemas/common/types/warning_code_create_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/warning_code_create_request.py @@ -33,7 +33,6 @@ "final_sale", "prop65", "fulfillment_changed", - "payment_term_changed", "age_restricted", ], title="Warning Code Create Request", @@ -41,5 +40,5 @@ ], ) """ -Warning code identifying the type of warning. Standard codes are defined in capability specifications (see examples) and have standardized semantics; freeform codes are permitted. +Warning code identifying the type of warning. Standard codes are defined in capability specs (see examples), and have standardized semantics; freeform codes are permitted. """ diff --git a/src/ucp_sdk/models/schemas/common/types/warning_code_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/warning_code_update_request.py similarity index 88% rename from src/ucp_sdk/models/schemas/common/types/warning_code_update_request.py rename to src/ucp_sdk/models/schemas/shopping/types/warning_code_update_request.py index e9cb732..0ef6133 100644 --- a/src/ucp_sdk/models/schemas/common/types/warning_code_update_request.py +++ b/src/ucp_sdk/models/schemas/shopping/types/warning_code_update_request.py @@ -33,7 +33,6 @@ "final_sale", "prop65", "fulfillment_changed", - "payment_term_changed", "age_restricted", ], title="Warning Code Update Request", @@ -41,5 +40,5 @@ ], ) """ -Warning code identifying the type of warning. Standard codes are defined in capability specifications (see examples) and have standardized semantics; freeform codes are permitted. +Warning code identifying the type of warning. Standard codes are defined in capability specs (see examples), and have standardized semantics; freeform codes are permitted. """ diff --git a/src/ucp_sdk/models/schemas/transports/a2a_message.py b/src/ucp_sdk/models/schemas/transports/a2a_message.py deleted file mode 100644 index 618f658..0000000 --- a/src/ucp_sdk/models/schemas/transports/a2a_message.py +++ /dev/null @@ -1,133 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from typing import Annotated, Any, Literal - -from pydantic import AnyUrl, BaseModel, ConfigDict, Field -from typing_extensions import TypeAliasType - -from .jsonrpc import Request, SuccessResponse - - -class Extension(BaseModel): - """ - A2A Agent Card extension advertisement for UCP. - """ - - model_config = ConfigDict( - extra="allow", - ) - uri: AnyUrl - """ - Extension URI. UCP uses its versioned reference URI. - """ - description: str | None = None - params: dict[str, Any] | None = None - """ - Extension parameters such as advertised UCP capabilities. - """ - - -class AgentCard(BaseModel): - """ - A2A Agent Card fragment advertising UCP support through extensions. - """ - - model_config = ConfigDict( - extra="allow", - ) - extensions: list[Extension] = Field(..., min_length=1) - - -class Part(BaseModel): - """ - A2A message part. UCP examples use text parts for natural language and data parts for structured UCP payloads. - """ - - model_config = ConfigDict( - extra="allow", - ) - type: str | None = None - kind: str | None = None - text: str | None = None - data: dict[str, Any] | None = None - """ - Structured data payload. UCP reserves a2a.ucp.* keys for UCP payloads. - """ - - -class Message(BaseModel): - """ - A2A Message carrying natural-language or structured UCP data parts. - """ - - model_config = ConfigDict( - extra="allow", - ) - role: Literal["user", "agent"] - """ - Message sender role. - """ - parts: list[Part] = Field(..., min_length=1) - messageId: str - kind: Literal["message"] - contextId: str - - -class Params(BaseModel): - model_config = ConfigDict( - extra="allow", - ) - message: Message - - -class MessageRequest(Request): - """ - A2A message/send JSON-RPC request whose params carry a UCP-bearing Message from the platform to the business agent. - """ - - model_config = ConfigDict( - extra="allow", - ) - method: Literal["message/send"] | None = None - params: Params - - -class MessageResponse(SuccessResponse): - """ - JSON-RPC success response whose result is an A2A Message from the business agent. - """ - - model_config = ConfigDict( - extra="allow", - ) - result: Message | None = None - - -A2AUcpMessageEnvelope = TypeAliasType( - "A2AUcpMessageEnvelope", - Annotated[ - AgentCard | MessageRequest | MessageResponse, - Field(..., title="A2A UCP Message Envelope"), - ], -) -""" -Minimal A2A envelope shapes used by UCP's A2A checkout binding. This schema validates UCP's transport mapping points — Agent Card extension advertisement, inbound A2A Message requests, and JSON-RPC responses carrying A2A Message results — without attempting to re-specify the full A2A protocol. -""" diff --git a/src/ucp_sdk/models/schemas/transports/embedded_message.py b/src/ucp_sdk/models/schemas/transports/embedded_message.py deleted file mode 100644 index 7ffc673..0000000 --- a/src/ucp_sdk/models/schemas/transports/embedded_message.py +++ /dev/null @@ -1,109 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from typing import Annotated, Any - -from pydantic import ConfigDict, Field, model_validator -from typing_extensions import TypeAliasType - -from . import jsonrpc -from .jsonrpc import Request as Request_1 -from .jsonrpc import SuccessResponse - -Method = TypeAliasType( - "Method", - Annotated[ - str, - Field( - ..., - pattern="^(ec|ep\\.cart)\\.[a-z][a-z0-9_]*(?:\\.[a-z][a-z0-9_]*)*$", - ), - ], -) -""" -Embedded Protocol method name. Checkout methods use ec.* and cart methods use ep.cart.*. -""" - - -class Request(Request_1): - """ - Embedded Protocol request or notification envelope. Messages with id expect a response; messages without id are notifications. - """ - - model_config = ConfigDict( - extra="allow", - ) - method: Method | None = None - params: dict[str, Any] - """ - Capability-specific EP parameters. - """ - - -class Response(SuccessResponse): - """ - Embedded Protocol success response envelope. UCP application-level success and error outcomes are both carried in result.ucp.status. - """ - - model_config = ConfigDict( - extra="allow", - ) - result: dict[str, Any] | None = None - """ - Capability-specific EP result. Application-level status is defined by capability schemas; see Embedded Protocol response handling. - """ - - @model_validator(mode="after") - def _enforce_conditional_required(self): - """JSON Schema if/then: enforce conditionally required fields.""" - rules = [ - { - "discriminator": "has_next_page", - "values": [True], - "required": ["cursor"], - } - ] - for rule in rules: - if getattr(self, rule["discriminator"], None) not in rule["values"]: - continue - for field in rule["required"]: - if field not in self.model_fields_set: - raise ValueError( - f"Field {field!r} is required by a schema condition" - ) - return self - - -ErrorResponse = TypeAliasType("ErrorResponse", jsonrpc.ErrorResponse) -""" -JSON-RPC transport-level error response for EP messages. Application-level failures use the response result with result.ucp.status=error instead. -""" - - -EmbeddedProtocolMessageEnvelope = TypeAliasType( - "EmbeddedProtocolMessageEnvelope", - Annotated[ - Request | Response | ErrorResponse, - Field(..., title="Embedded Protocol Message Envelope"), - ], -) -""" -JSON-RPC envelope for UCP Embedded Protocol (EP) messages exchanged between a host and an embedded context. This schema constrains the shared transport envelope and method namespace while leaving capability-specific params and result payloads to their capability schemas. -""" diff --git a/src/ucp_sdk/models/schemas/transports/jsonrpc.py b/src/ucp_sdk/models/schemas/transports/jsonrpc.py deleted file mode 100644 index f8ffdd3..0000000 --- a/src/ucp_sdk/models/schemas/transports/jsonrpc.py +++ /dev/null @@ -1,121 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from typing import Annotated, Any, Literal - -from pydantic import BaseModel, ConfigDict, Field -from typing_extensions import TypeAliasType - -Id = TypeAliasType("Id", str | float | None) -""" -JSON-RPC request identifier. Notifications omit id; responses echo the request id, or use null when the request id could not be determined. -""" - - -class Error(BaseModel): - """ - JSON-RPC transport-level error object. UCP business outcomes use result payloads with UCP messages instead of this object. - """ - - model_config = ConfigDict( - extra="allow", - ) - code: int - """ - JSON-RPC error code. Standard codes are negative integers; UCP bindings reserve business errors for UCP messages. - """ - message: str - """ - Short transport-level error description. - """ - data: Any | None = None - """ - Optional machine-readable transport error details. - """ - - -class Request(BaseModel): - """ - JSON-RPC request or notification envelope. Presence of id makes the message a request; absence of id makes it a notification. - """ - - model_config = ConfigDict( - extra="allow", - ) - jsonrpc: Literal["2.0"] - """ - JSON-RPC protocol version. - """ - id: Id | None = None - method: str = Field(..., min_length=1) - """ - Transport method name. Binding-specific schemas constrain the method namespace. - """ - params: dict[str, Any] | list[Any] | None = None - """ - Method parameters. Binding-specific schemas define the object shape. - """ - - -class SuccessResponse(BaseModel): - """ - JSON-RPC success response envelope. - """ - - model_config = ConfigDict( - extra="allow", - ) - jsonrpc: Literal["2.0"] - """ - JSON-RPC protocol version. - """ - id: Id - result: Any - """ - Successful transport result. UCP bindings define the nested result payload. - """ - - -class ErrorResponse(BaseModel): - """ - JSON-RPC transport error response envelope. This is for protocol-level failures, not UCP application-level messages. - """ - - model_config = ConfigDict( - extra="forbid", - ) - jsonrpc: Literal["2.0"] - """ - JSON-RPC protocol version. - """ - id: Id - error: Error - - -JsonRpc20Envelope = TypeAliasType( - "JsonRpc20Envelope", - Annotated[ - Request | SuccessResponse | ErrorResponse, - Field(..., title="JSON-RPC 2.0 Envelope"), - ], -) -""" -Common JSON-RPC 2.0 transport envelope used by UCP JSON-RPC-based bindings. This schema intentionally validates only the protocol envelope; binding-specific params and result payloads are validated by transport-specific schemas or extracted UCP payload schemas. -""" diff --git a/src/ucp_sdk/models/schemas/transports/mcp_tool_call.py b/src/ucp_sdk/models/schemas/transports/mcp_tool_call.py deleted file mode 100644 index 6418787..0000000 --- a/src/ucp_sdk/models/schemas/transports/mcp_tool_call.py +++ /dev/null @@ -1,157 +0,0 @@ -# Copyright 2026 UCP Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# generated by datamodel-codegen -# pylint: disable=all -# pyformat: disable - -from __future__ import annotations - -from typing import Annotated, Any, Literal - -from pydantic import BaseModel, ConfigDict, Field, model_validator -from typing_extensions import TypeAliasType - -from . import jsonrpc -from .jsonrpc import Request as Request_1 -from .jsonrpc import SuccessResponse - - -class UcpAgent(BaseModel): - """ - UCP-Agent metadata carried inside MCP tool arguments. - """ - - model_config = ConfigDict( - extra="allow", - ) - profile: str - """ - Platform profile URI advertised to the business. - """ - - -class Meta(BaseModel): - """ - UCP request metadata passed through MCP params.arguments.meta. - """ - - model_config = ConfigDict( - extra="allow", - ) - ucp_agent: UcpAgent | None = Field(None, alias="ucp-agent") - idempotency_key: str | None = Field(None, alias="idempotency-key") - """ - Optional idempotency key for retry-safe mutating operations. - """ - - -class Arguments(BaseModel): - """ - MCP tool arguments. UCP reserves meta for transport metadata; operation payload fields such as checkout, cart, order id, or catalog inputs are operation-specific. - """ - - model_config = ConfigDict( - extra="allow", - ) - meta: Meta | None = None - - -class Params(BaseModel): - model_config = ConfigDict( - extra="allow", - ) - name: str = Field(..., min_length=1) - """ - MCP tool name matching the UCP operation binding, such as create_checkout or get_cart. - """ - arguments: Arguments - - -class Request(Request_1): - """ - MCP tools/call request envelope for invoking a UCP operation. - """ - - model_config = ConfigDict( - extra="allow", - ) - method: Literal["tools/call"] | None = None - params: Params - - -class ContentPart(BaseModel): - """ - MCP content part returned for clients that do not consume structuredContent. - """ - - model_config = ConfigDict( - extra="allow", - ) - type: str - text: str | None = None - - -class Result(BaseModel): - model_config = ConfigDict( - extra="allow", - ) - structuredContent: dict[str, Any] - """ - The UCP response payload for the operation. - """ - content: list[ContentPart] | None = None - - -class Response(SuccessResponse): - """ - MCP tools/call response envelope. UCP payloads are carried in result.structuredContent; content is compatibility output. - """ - - model_config = ConfigDict( - extra="allow", - ) - result: Result | None = None - - @model_validator(mode="after") - def _enforce_conditional_required(self): - """JSON Schema if/then: enforce conditionally required fields.""" - rules = [ - { - "discriminator": "has_next_page", - "values": [True], - "required": ["cursor"], - } - ] - for rule in rules: - if getattr(self, rule["discriminator"], None) not in rule["values"]: - continue - for field in rule["required"]: - if field not in self.model_fields_set: - raise ValueError( - f"Field {field!r} is required by a schema condition" - ) - return self - - -McpToolCallEnvelope = TypeAliasType( - "McpToolCallEnvelope", - Annotated[ - Request | Response | jsonrpc.ErrorResponse, - Field(..., title="MCP Tool Call Envelope"), - ], -) -""" -UCP's MCP transport envelope for JSON-RPC tools/call messages. The schema validates the MCP mapping layer: operation name in params.name, UCP metadata and domain arguments in params.arguments, and UCP output in result.structuredContent. -""" diff --git a/src/ucp_sdk/models/schemas/ucp.py b/src/ucp_sdk/models/schemas/ucp.py index 15e3acf..373f7a9 100644 --- a/src/ucp_sdk/models/schemas/ucp.py +++ b/src/ucp_sdk/models/schemas/ucp.py @@ -24,14 +24,13 @@ from typing_extensions import TypeAliasType from . import capability, payment_handler, service -from .common.types import request_constraints as request_constraints_1 -from .common.types import reverse_domain_name +from .shopping.types import reverse_domain_name Version = TypeAliasType( "Version", Annotated[str, Field(..., pattern="^\\d{4}-\\d{2}-\\d{2}$")] ) """ -Version identifier in YYYY-MM-DD format. +UCP version in YYYY-MM-DD format. """ @@ -63,7 +62,7 @@ class Requires(BaseModel): ) protocol: VersionConstraint | None = None """ - Required range for the selected `ucp.version`. + Required protocol version. """ capabilities: ( dict[reverse_domain_name.ReverseDomainName, VersionConstraint] | None @@ -73,12 +72,6 @@ class Requires(BaseModel): """ -MapOrder = TypeAliasType("MapOrder", dict[str, list[str]]) -""" -Preferred key order for map-valued fields in the scope annotated by the containing `ucp` member. Each property names a target map, and its array lists target keys in preferred order. Lists may be partial and are not allowlists. -""" - - class Entity(BaseModel): """ Shared foundation for all UCP entities. @@ -109,18 +102,6 @@ class Entity(BaseModel): """ -class Members(BaseModel): - """ - Members defined inside the reserved `ucp` protocol object. The object is open for forward compatibility: consumers MUST ignore unrecognized members. Only UCP core defines members, and every defined member MUST be safe to ignore. - """ - - model_config = ConfigDict( - extra="allow", - ) - map_order: MapOrder | None = None - request_constraints: request_constraints_1.RequestConstraints | None = None - - class Base(BaseModel): """ Base UCP metadata with shared properties for all schema types. @@ -130,10 +111,6 @@ class Base(BaseModel): extra="allow", ) version: Version - map_order: MapOrder | None = None - """ - Preferred key-traversal order for sibling registry fields inside the root `ucp` envelope (`services`, `capabilities`, and `payment_handlers`). - """ status: Literal["success", "error"] | None = "success" """ Application-level status of the UCP operation. @@ -197,7 +174,7 @@ class PlatformSchema(Base): extra="allow", ) services: dict[ - reverse_domain_name.ReverseDomainName, list[service.PlatformSchema6] + reverse_domain_name.ReverseDomainName, list[service.PlatformSchema5] ] """ Service registry keyed by reverse-domain name. @@ -234,7 +211,7 @@ class BusinessSchema(Base): Previous protocol versions this business supports, mapped to profile URIs. Businesses that support older protocol versions SHOULD advertise each version and link to its profile. Each URI points to a complete, self-contained profile for that version. When omitted, only `version` is supported. """ services: dict[ - reverse_domain_name.ReverseDomainName, list[service.BusinessSchema3] + reverse_domain_name.ReverseDomainName, list[service.BusinessSchema2] ] """ Service registry keyed by reverse-domain name. diff --git a/src/ucp_sdk/models/schemas/ucp_create_request.py b/src/ucp_sdk/models/schemas/ucp_create_request.py index 3336fd6..bba6e04 100644 --- a/src/ucp_sdk/models/schemas/ucp_create_request.py +++ b/src/ucp_sdk/models/schemas/ucp_create_request.py @@ -24,14 +24,13 @@ from typing_extensions import TypeAliasType from . import capability, payment_handler, service -from .common.types import request_constraints as request_constraints_1 -from .common.types import reverse_domain_name_create_request +from .shopping.types import reverse_domain_name_create_request Version = TypeAliasType( "Version", Annotated[str, Field(..., pattern="^\\d{4}-\\d{2}-\\d{2}$")] ) """ -Version identifier in YYYY-MM-DD format. +UCP version in YYYY-MM-DD format. """ @@ -63,7 +62,7 @@ class Requires(BaseModel): ) protocol: VersionConstraint | None = None """ - Required range for the selected `ucp.version`. + Required protocol version. """ capabilities: ( dict[ @@ -77,12 +76,6 @@ class Requires(BaseModel): """ -MapOrder = TypeAliasType("MapOrder", dict[str, list[str]]) -""" -Preferred key order for map-valued fields in the scope annotated by the containing `ucp` member. Each property names a target map, and its array lists target keys in preferred order. Lists may be partial and are not allowlists. -""" - - class Entity(BaseModel): """ Shared foundation for all UCP entities. @@ -113,18 +106,6 @@ class Entity(BaseModel): """ -class Members(BaseModel): - """ - Members defined inside the reserved `ucp` protocol object. The object is open for forward compatibility: consumers MUST ignore unrecognized members. Only UCP core defines members, and every defined member MUST be safe to ignore. - """ - - model_config = ConfigDict( - extra="allow", - ) - map_order: MapOrder | None = None - request_constraints: request_constraints_1.RequestConstraints | None = None - - class Base(BaseModel): """ Base UCP metadata with shared properties for all schema types. @@ -134,10 +115,6 @@ class Base(BaseModel): extra="allow", ) version: Version - map_order: MapOrder | None = None - """ - Preferred key-traversal order for sibling registry fields inside the root `ucp` envelope (`services`, `capabilities`, and `payment_handlers`). - """ status: Literal["success", "error"] | None = "success" """ Application-level status of the UCP operation. @@ -212,7 +189,7 @@ class PlatformSchema(Base): ) services: dict[ reverse_domain_name_create_request.ReverseDomainNameCreateRequest, - list[service.PlatformSchema6], + list[service.PlatformSchema5], ] """ Service registry keyed by reverse-domain name. @@ -250,7 +227,7 @@ class BusinessSchema(Base): """ services: dict[ reverse_domain_name_create_request.ReverseDomainNameCreateRequest, - list[service.BusinessSchema3], + list[service.BusinessSchema2], ] """ Service registry keyed by reverse-domain name. diff --git a/src/ucp_sdk/models/schemas/ucp_update_request.py b/src/ucp_sdk/models/schemas/ucp_update_request.py index 6653e6f..698fc4e 100644 --- a/src/ucp_sdk/models/schemas/ucp_update_request.py +++ b/src/ucp_sdk/models/schemas/ucp_update_request.py @@ -24,14 +24,13 @@ from typing_extensions import TypeAliasType from . import capability, payment_handler, service -from .common.types import request_constraints as request_constraints_1 -from .common.types import reverse_domain_name_update_request +from .shopping.types import reverse_domain_name_update_request Version = TypeAliasType( "Version", Annotated[str, Field(..., pattern="^\\d{4}-\\d{2}-\\d{2}$")] ) """ -Version identifier in YYYY-MM-DD format. +UCP version in YYYY-MM-DD format. """ @@ -63,7 +62,7 @@ class Requires(BaseModel): ) protocol: VersionConstraint | None = None """ - Required range for the selected `ucp.version`. + Required protocol version. """ capabilities: ( dict[ @@ -77,12 +76,6 @@ class Requires(BaseModel): """ -MapOrder = TypeAliasType("MapOrder", dict[str, list[str]]) -""" -Preferred key order for map-valued fields in the scope annotated by the containing `ucp` member. Each property names a target map, and its array lists target keys in preferred order. Lists may be partial and are not allowlists. -""" - - class Entity(BaseModel): """ Shared foundation for all UCP entities. @@ -113,18 +106,6 @@ class Entity(BaseModel): """ -class Members(BaseModel): - """ - Members defined inside the reserved `ucp` protocol object. The object is open for forward compatibility: consumers MUST ignore unrecognized members. Only UCP core defines members, and every defined member MUST be safe to ignore. - """ - - model_config = ConfigDict( - extra="allow", - ) - map_order: MapOrder | None = None - request_constraints: request_constraints_1.RequestConstraints | None = None - - class Base(BaseModel): """ Base UCP metadata with shared properties for all schema types. @@ -134,10 +115,6 @@ class Base(BaseModel): extra="allow", ) version: Version - map_order: MapOrder | None = None - """ - Preferred key-traversal order for sibling registry fields inside the root `ucp` envelope (`services`, `capabilities`, and `payment_handlers`). - """ status: Literal["success", "error"] | None = "success" """ Application-level status of the UCP operation. @@ -212,7 +189,7 @@ class PlatformSchema(Base): ) services: dict[ reverse_domain_name_update_request.ReverseDomainNameUpdateRequest, - list[service.PlatformSchema6], + list[service.PlatformSchema5], ] """ Service registry keyed by reverse-domain name. @@ -250,7 +227,7 @@ class BusinessSchema(Base): """ services: dict[ reverse_domain_name_update_request.ReverseDomainNameUpdateRequest, - list[service.BusinessSchema3], + list[service.BusinessSchema2], ] """ Service registry keyed by reverse-domain name. diff --git a/tests/test_codegen_pipeline.py b/tests/test_codegen_pipeline.py index da00eb7..eba1f0c 100644 --- a/tests/test_codegen_pipeline.py +++ b/tests/test_codegen_pipeline.py @@ -1686,7 +1686,8 @@ def test_injects_cleanly_when_annotated_is_line_wrapped(self): wrap the annotation onto multiple lines with a trailing comma; a naive "insert before the closing bracket" splice then lands after that comma and produces "Field(...),\\n, AfterValidator(...)]" - - two commas with nothing between them, a SyntaxError).""" + two commas with nothing between them, a SyntaxError). + """ out = postprocess_models.inject_array_contains( self.MODULE_LINE_WRAPPED, "TotalsCreateRequest", self.GROUPS ) From 2a1876fc4574f6a1e1a913035d341abff7002bd1 Mon Sep 17 00:00:00 2001 From: Ryan Conigliaro Date: Tue, 25 Aug 2026 17:12:22 -0400 Subject: [PATCH 4/6] running uv run ruff format --- src/ucp_sdk/models/schemas/__init__.py | 1 - src/ucp_sdk/models/schemas/common/__init__.py | 1 - src/ucp_sdk/models/schemas/shopping/__init__.py | 1 - src/ucp_sdk/models/schemas/shopping/types/__init__.py | 1 - src/ucp_sdk/models/schemas/transports/__init__.py | 1 - 5 files changed, 5 deletions(-) diff --git a/src/ucp_sdk/models/schemas/__init__.py b/src/ucp_sdk/models/schemas/__init__.py index 421dc21..1252d6b 100644 --- a/src/ucp_sdk/models/schemas/__init__.py +++ b/src/ucp_sdk/models/schemas/__init__.py @@ -15,4 +15,3 @@ # generated by datamodel-codegen # pylint: disable=all # pyformat: disable - diff --git a/src/ucp_sdk/models/schemas/common/__init__.py b/src/ucp_sdk/models/schemas/common/__init__.py index 421dc21..1252d6b 100644 --- a/src/ucp_sdk/models/schemas/common/__init__.py +++ b/src/ucp_sdk/models/schemas/common/__init__.py @@ -15,4 +15,3 @@ # generated by datamodel-codegen # pylint: disable=all # pyformat: disable - diff --git a/src/ucp_sdk/models/schemas/shopping/__init__.py b/src/ucp_sdk/models/schemas/shopping/__init__.py index 421dc21..1252d6b 100644 --- a/src/ucp_sdk/models/schemas/shopping/__init__.py +++ b/src/ucp_sdk/models/schemas/shopping/__init__.py @@ -15,4 +15,3 @@ # generated by datamodel-codegen # pylint: disable=all # pyformat: disable - diff --git a/src/ucp_sdk/models/schemas/shopping/types/__init__.py b/src/ucp_sdk/models/schemas/shopping/types/__init__.py index 421dc21..1252d6b 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/__init__.py +++ b/src/ucp_sdk/models/schemas/shopping/types/__init__.py @@ -15,4 +15,3 @@ # generated by datamodel-codegen # pylint: disable=all # pyformat: disable - diff --git a/src/ucp_sdk/models/schemas/transports/__init__.py b/src/ucp_sdk/models/schemas/transports/__init__.py index 421dc21..1252d6b 100644 --- a/src/ucp_sdk/models/schemas/transports/__init__.py +++ b/src/ucp_sdk/models/schemas/transports/__init__.py @@ -15,4 +15,3 @@ # generated by datamodel-codegen # pylint: disable=all # pyformat: disable - From e1d7f58551c817ee50d3737101474af1abc96306 Mon Sep 17 00:00:00 2001 From: Ryan Conigliaro Date: Tue, 25 Aug 2026 22:18:30 -0400 Subject: [PATCH 5/6] fix end of files --- src/ucp_sdk/models/schemas/__init__.py | 1 + src/ucp_sdk/models/schemas/common/__init__.py | 1 + src/ucp_sdk/models/schemas/shopping/__init__.py | 1 + src/ucp_sdk/models/schemas/shopping/types/__init__.py | 1 + src/ucp_sdk/models/schemas/transports/__init__.py | 1 + 5 files changed, 5 insertions(+) diff --git a/src/ucp_sdk/models/schemas/__init__.py b/src/ucp_sdk/models/schemas/__init__.py index 1252d6b..421dc21 100644 --- a/src/ucp_sdk/models/schemas/__init__.py +++ b/src/ucp_sdk/models/schemas/__init__.py @@ -15,3 +15,4 @@ # generated by datamodel-codegen # pylint: disable=all # pyformat: disable + diff --git a/src/ucp_sdk/models/schemas/common/__init__.py b/src/ucp_sdk/models/schemas/common/__init__.py index 1252d6b..421dc21 100644 --- a/src/ucp_sdk/models/schemas/common/__init__.py +++ b/src/ucp_sdk/models/schemas/common/__init__.py @@ -15,3 +15,4 @@ # generated by datamodel-codegen # pylint: disable=all # pyformat: disable + diff --git a/src/ucp_sdk/models/schemas/shopping/__init__.py b/src/ucp_sdk/models/schemas/shopping/__init__.py index 1252d6b..421dc21 100644 --- a/src/ucp_sdk/models/schemas/shopping/__init__.py +++ b/src/ucp_sdk/models/schemas/shopping/__init__.py @@ -15,3 +15,4 @@ # generated by datamodel-codegen # pylint: disable=all # pyformat: disable + diff --git a/src/ucp_sdk/models/schemas/shopping/types/__init__.py b/src/ucp_sdk/models/schemas/shopping/types/__init__.py index 1252d6b..421dc21 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/__init__.py +++ b/src/ucp_sdk/models/schemas/shopping/types/__init__.py @@ -15,3 +15,4 @@ # generated by datamodel-codegen # pylint: disable=all # pyformat: disable + diff --git a/src/ucp_sdk/models/schemas/transports/__init__.py b/src/ucp_sdk/models/schemas/transports/__init__.py index 1252d6b..421dc21 100644 --- a/src/ucp_sdk/models/schemas/transports/__init__.py +++ b/src/ucp_sdk/models/schemas/transports/__init__.py @@ -15,3 +15,4 @@ # generated by datamodel-codegen # pylint: disable=all # pyformat: disable + From 355fb5c69ee692458d55209d5843451b58514d78 Mon Sep 17 00:00:00 2001 From: Ryan Conigliaro Date: Wed, 26 Aug 2026 10:01:48 -0400 Subject: [PATCH 6/6] fix precomit lint failure --- src/ucp_sdk/models/schemas/__init__.py | 1 - src/ucp_sdk/models/schemas/common/__init__.py | 1 - src/ucp_sdk/models/schemas/shopping/__init__.py | 1 - src/ucp_sdk/models/schemas/shopping/types/__init__.py | 1 - src/ucp_sdk/models/schemas/transports/__init__.py | 1 - 5 files changed, 5 deletions(-) diff --git a/src/ucp_sdk/models/schemas/__init__.py b/src/ucp_sdk/models/schemas/__init__.py index 421dc21..1252d6b 100644 --- a/src/ucp_sdk/models/schemas/__init__.py +++ b/src/ucp_sdk/models/schemas/__init__.py @@ -15,4 +15,3 @@ # generated by datamodel-codegen # pylint: disable=all # pyformat: disable - diff --git a/src/ucp_sdk/models/schemas/common/__init__.py b/src/ucp_sdk/models/schemas/common/__init__.py index 421dc21..1252d6b 100644 --- a/src/ucp_sdk/models/schemas/common/__init__.py +++ b/src/ucp_sdk/models/schemas/common/__init__.py @@ -15,4 +15,3 @@ # generated by datamodel-codegen # pylint: disable=all # pyformat: disable - diff --git a/src/ucp_sdk/models/schemas/shopping/__init__.py b/src/ucp_sdk/models/schemas/shopping/__init__.py index 421dc21..1252d6b 100644 --- a/src/ucp_sdk/models/schemas/shopping/__init__.py +++ b/src/ucp_sdk/models/schemas/shopping/__init__.py @@ -15,4 +15,3 @@ # generated by datamodel-codegen # pylint: disable=all # pyformat: disable - diff --git a/src/ucp_sdk/models/schemas/shopping/types/__init__.py b/src/ucp_sdk/models/schemas/shopping/types/__init__.py index 421dc21..1252d6b 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/__init__.py +++ b/src/ucp_sdk/models/schemas/shopping/types/__init__.py @@ -15,4 +15,3 @@ # generated by datamodel-codegen # pylint: disable=all # pyformat: disable - diff --git a/src/ucp_sdk/models/schemas/transports/__init__.py b/src/ucp_sdk/models/schemas/transports/__init__.py index 421dc21..1252d6b 100644 --- a/src/ucp_sdk/models/schemas/transports/__init__.py +++ b/src/ucp_sdk/models/schemas/transports/__init__.py @@ -15,4 +15,3 @@ # generated by datamodel-codegen # pylint: disable=all # pyformat: disable -