diff --git a/README.md b/README.md index 6a04f4b..0a11848 100644 --- a/README.md +++ b/README.md @@ -38,10 +38,7 @@ For now, you can install the SDK using the following commands: mkdir sdk # Clone the repository -git clone https://github.com/Universal-Commerce-Protocol/python-sdk.git sdk/python - -# Navigate to the directory -cd sdk/python +git clone https://github.com/Universal-Commerce-Protocol/python-sdk.git # Install dependencies uv sync @@ -62,9 +59,13 @@ To regenerate the models: ```bash uv sync -./generate_models.sh +./generate_models.sh ``` +Where `` is the version of the UCP specification to use (for example, "2026-01-23"). + +If no version is specified, the `main` branch of the [UCP repo](https://github.com/Universal-Commerce-Protocol/ucp) will be used. + The generated code is automatically formatted using `ruff`. ## Contributing diff --git a/generate_models.sh b/generate_models.sh index 26afb35..273030a 100755 --- a/generate_models.sh +++ b/generate_models.sh @@ -4,13 +4,38 @@ # Ensure we are in the script's directory cd "$(dirname "$0")" || exit +# Add ~/.local/bin to PATH for uv +export PATH="$HOME/.local/bin:$PATH" + +# Check if git is installed +if ! command -v git &> /dev/null; then + echo "Error: git not found. Please install git." + exit 1 +fi + +# UCP Version to use (if provided, use release/$1 branch; otherwise, use main) +if [ -z "$1" ]; then + BRANCH="main" + echo "No version specified, cloning main branch..." +else + BRANCH="release/$1" + echo "Cloning version $1 (branch: $BRANCH)..." +fi + +# Ensure ucp directory is clean before cloning +rm -rf ucp +git clone -b "$BRANCH" --depth 1 https://github.com/Universal-Commerce-Protocol/ucp ucp + # Output directory OUTPUT_DIR="src/ucp_sdk/models" # Schema directory (relative to this script) -SCHEMA_DIR="../../spec/" +SCHEMA_DIR="ucp/source" + +echo "Preprocessing schemas..." +uv run python preprocess_schemas.py -echo "Generating Pydantic models from $SCHEMA_DIR..." +echo "Generating Pydantic models from preprocessed schemas..." # Check if uv is installed if ! command -v uv &> /dev/null; then @@ -23,9 +48,11 @@ fi rm -r -f "$OUTPUT_DIR" mkdir -p "$OUTPUT_DIR" + # Run generation using uv # We use --use-schema-description to use descriptions from JSON schema as docstrings # We use --field-constraints to include validation constraints (regex, min/max, etc.) +# Note: Formatting is done as a post-processing step. uv run \ --link-mode=copy \ --extra-index-url https://pypi.org/simple python \ @@ -41,7 +68,11 @@ uv run \ --disable-timestamp \ --use-double-quotes \ --no-use-annotated \ - --allow-extra-fields \ - --formatters ruff-format ruff-check + --allow-extra-fields + +echo "Formatting generated models..." +uv run ruff format +uv run ruff check --fix "$OUTPUT_DIR" 2>&1 | grep -E "^(All checks passed|Fixed|Found)" || echo "Formatting complete" + echo "Done. Models generated in $OUTPUT_DIR" diff --git a/preprocess_schemas.py b/preprocess_schemas.py new file mode 100644 index 0000000..3a84cc7 --- /dev/null +++ b/preprocess_schemas.py @@ -0,0 +1,247 @@ +# 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. + +import json +import copy +from pathlib import Path +import sys + + +def get_explicit_ops(schema): + """Finds ops explicitly mentioned in ucp_request fields.""" + ops = set() + properties = schema.get("properties", {}) + for prop_data in properties.values(): + if not isinstance(prop_data, dict): + continue + ucp_req = prop_data.get("ucp_request") + if isinstance(ucp_req, str): + # Strings like "omit" or "required" only imply standard ops. + # "complete" request should only be generated when it's explicitly defined in a dict. + ops.update(["create", "update"]) + elif isinstance(ucp_req, dict): + for op in ucp_req: + ops.add(op) + return ops + + +def get_props_with_refs(schema, schema_file_path): + """Finds all external schema references associated with their properties.""" + results = [] # list of (prop_name, abs_ref_path) + + def find_refs(obj, prop_name): + if isinstance(obj, dict): + if "$ref" in obj: + ref = obj["$ref"] + if "#" not in ref: + ref_path = (schema_file_path.parent / ref).resolve() + results.append((prop_name, str(ref_path))) + for v in obj.values(): + find_refs(v, prop_name) + elif isinstance(obj, list): + for item in obj: + find_refs(item, prop_name) + + properties = schema.get("properties", {}) + for prop_name, prop_data in properties.items(): + find_refs(prop_data, prop_name) + return results + + +def get_variant_filename(base_path, op): + p = Path(base_path) + return p.parent / f"{p.stem}_{op}_request.json" + + +def generate_variants(schema_file, schema, ops, all_variant_needs): + schema_file_path = Path(schema_file) + for op in ops: + variant_schema = copy.deepcopy(schema) + + # Update title and id + base_title = schema.get("title", schema_file_path.stem) + variant_schema["title"] = f"{base_title} {op.capitalize()} Request" + + # Update $id if present + if "$id" in variant_schema: + old_id = variant_schema["$id"] + if "/" in old_id: + old_id_parts = old_id.split("/") + old_id_filename = old_id_parts[-1] + if "." in old_id_filename: + stem = old_id_filename.split(".")[0] + ext = old_id_filename.split(".")[-1] + new_id_filename = f"{stem}_{op}_request.{ext}" + variant_schema["$id"] = "/".join( + old_id_parts[:-1] + [new_id_filename] + ) + + new_properties = {} + new_required = [] + + for prop_name, prop_data in schema.get("properties", {}).items(): + if not isinstance(prop_data, dict): + new_properties[prop_name] = prop_data + continue + + ucp_req = prop_data.get("ucp_request") + + include = True + is_required = False + + if ucp_req is not None: + if isinstance(ucp_req, str): + if ucp_req == "omit": + include = False + elif ucp_req == "required": + is_required = True + elif isinstance(ucp_req, dict): + op_val = ucp_req.get(op) + if op_val == "omit" or op_val is None: + include = False + elif op_val == "required": + is_required = True + else: + # No ucp_request. Include if it was required in base? + if prop_name in schema.get("required", []): + is_required = True + + if include: + prop_copy = copy.deepcopy(prop_data) + if "ucp_request" in prop_copy: + del prop_copy["ucp_request"] + + # Recursive reference check (deep) + def update_refs(obj): + if isinstance(obj, dict): + if "$ref" in obj: + ref = obj["$ref"] + if "#" not in ref: + ref_path = Path(ref) + target_base_abs = (schema_file_path.parent / ref_path).resolve() + if ( + str(target_base_abs) in all_variant_needs + and op in all_variant_needs[str(target_base_abs)] + ): + variant_ref_filename = f"{ref_path.stem}_{op}_request.json" + obj["$ref"] = str(ref_path.parent / variant_ref_filename) + for k, v in obj.items(): + update_refs(v) + elif isinstance(obj, list): + for item in obj: + update_refs(item) + + update_refs(prop_copy) + + new_properties[prop_name] = prop_copy + if is_required: + new_required.append(prop_name) + + # Always generate the variant schema to avoid breaking refs in parents + variant_schema["properties"] = new_properties + variant_schema["required"] = new_required + + variant_path = get_variant_filename(schema_file_path, op) + with open(variant_path, "w") as f: + json.dump(variant_schema, f, indent=2) + print(f"Generated {variant_path}") + + +def main(): + schema_dir = "ucp/source" + if len(sys.argv) > 1: + schema_dir = sys.argv[1] + + schema_dir_path = Path(schema_dir) + if not schema_dir_path.exists(): + print(f"Directory {schema_dir} does not exist.") + return + + all_files = list(schema_dir_path.rglob("*.json")) + + schemas_cache = {} + schema_props_refs = {} + all_variant_needs = {} + + # 1. First pass: load all schemas and find properties with refs + for f in all_files: + if "_request.json" in f.name: + continue + try: + with open(f, "r") as open_f: + schema = json.load(open_f) + if ( + not isinstance(schema, dict) + or schema.get("type") != "object" + or "properties" not in schema + ): + continue + + abs_path = str(f.resolve()) + schemas_cache[abs_path] = schema + schema_props_refs[abs_path] = get_props_with_refs(schema, f) + + # 2. Get explicit needs defined in the schema itself + explicit_ops = get_explicit_ops(schema) + if explicit_ops: + all_variant_needs[abs_path] = explicit_ops + except Exception as e: + print(f"Error processing {f}: {e}") + + # 3. Transitive dependency tracking (Parent -> Child): + # If P needs variant OP, and P includes property S (not omitted for OP), + # then S also needs variant OP to ensure ref matching works correctly. + changed = True + while changed: + changed = False + for abs_path, props_refs in schema_props_refs.items(): + if abs_path not in all_variant_needs: + continue + + parent_schema = schemas_cache[abs_path] + parent_ops = all_variant_needs[abs_path] + + for op in list(parent_ops): + for prop_name, ref_path in props_refs: + if ref_path not in schemas_cache: + continue + + # Check if this property is omitted for this op in parent + prop_data = parent_schema["properties"].get(prop_name, {}) + ucp_req = prop_data.get("ucp_request") + + include = True + if ucp_req is not None: + if isinstance(ucp_req, str): + if ucp_req == "omit": + include = False + elif isinstance(ucp_req, dict): + op_val = ucp_req.get(op) + if op_val == "omit" or op_val is None: + include = False + + if include: + # Propagate op from parent to child + child_needs = all_variant_needs.get(ref_path, set()) + if op not in child_needs: + all_variant_needs.setdefault(ref_path, set()).add(op) + changed = True + + # 4. Final pass: generate variants + for f_abs, ops in all_variant_needs.items(): + generate_variants(f_abs, schemas_cache[f_abs], ops, all_variant_needs) + + +if __name__ == "__main__": + main() diff --git a/pyproject.toml b/pyproject.toml index d4d858a..b6f679c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,12 @@ [project] name = "ucp-sdk" -version = "0.1.0" +version = "2026.01.23" description = "UCP Python SDK" readme = "README.md" +license-files = ["LICENSE"] authors = [ - { name = "Florin Iucha", email = "fiucha@google.com" } + { name = "Florin Iucha", email = "fiucha@google.com" }, + { name = "Federico D'Amato", email = "damaz@google.com" }, ] requires-python = ">=3.10" dependencies = [ @@ -62,4 +64,4 @@ select = ["E", "F", "W", "B", "C4", "SIM", "N", "UP", "D", "PTH", "T20"] [tool.ruff.lint.isort] combine-as-imports = true force-sort-within-sections = true -case-sensitive = true +case-sensitive = true \ No newline at end of file diff --git a/src/ucp_sdk/__init__.py b/src/ucp_sdk/__init__.py deleted file mode 100644 index 6762e09..0000000 --- a/src/ucp_sdk/__init__.py +++ /dev/null @@ -1,19 +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. - -"""UCP Python SDK.""" - - -def hello() -> str: - return "Hello from ucp-python-sdk!" diff --git a/src/ucp_sdk/models/__init__.py b/src/ucp_sdk/models/__init__.py index 1252d6b..421dc21 100644 --- a/src/ucp_sdk/models/__init__.py +++ b/src/ucp_sdk/models/__init__.py @@ -15,3 +15,4 @@ # generated by datamodel-codegen # pylint: disable=all # pyformat: disable + diff --git a/src/ucp_sdk/models/_internal.py b/src/ucp_sdk/models/_internal.py deleted file mode 100644 index edad471..0000000 --- a/src/ucp_sdk/models/_internal.py +++ /dev/null @@ -1,227 +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 AnyUrl, BaseModel, ConfigDict, Field, RootModel - - -class UcpCapability(RootModel[Any]): - root: Any = Field(..., title="UCP Capability") - """ - Schema for UCP capabilities and extensions. Extensions are capabilities with an 'extends' field. Uses reverse-domain naming for governance. - """ - - -class Base(BaseModel): - model_config = ConfigDict( - extra="allow", - ) - name: str | None = Field( - None, pattern="^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$" - ) - """ - Stable capability identifier in reverse-domain notation (e.g., dev.ucp.shopping.checkout). Used in capability negotiation. - """ - version: Version | None = None - """ - Capability version in YYYY-MM-DD format. - """ - spec: AnyUrl | None = None - """ - URL to human-readable specification document. - """ - schema_: AnyUrl | None = Field(None, alias="schema") - """ - URL to JSON Schema for this capability's payload. - """ - extends: str | None = Field( - None, pattern="^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$" - ) - """ - Parent capability this extends. Present for extensions, absent for root capabilities. - """ - config: dict[str, Any] | None = None - """ - Capability-specific configuration (structure defined by each capability). - """ - - -class Discovery(Base): - """Full capability declaration for discovery profiles. Includes spec/schema URLs for agent fetching.""" - - model_config = ConfigDict( - extra="allow", - ) - - -class Response(Base): - """Capability reference in responses. Only name/version required to confirm active capabilities.""" - - model_config = ConfigDict( - extra="allow", - ) - - -class UcpMetadata(RootModel[Any]): - root: Any = Field(..., title="UCP Metadata") - """ - Protocol metadata for discovery profiles and responses. Uses slim schema pattern with context-specific required fields. - """ - - -class Version(RootModel[str]): - root: str = Field(..., pattern="^\\d{4}-\\d{2}-\\d{2}$") - """ - UCP protocol version in YYYY-MM-DD format. - """ - - -class Services(RootModel[dict[str, "UcpService"]]): - """Service definitions keyed by reverse-domain service name.""" - - root: dict[str, UcpService] - - -class DiscoveryProfile(BaseModel): - """Full UCP metadata for /.well-known/ucp discovery.""" - - model_config = ConfigDict( - extra="allow", - ) - version: Version - services: Services - capabilities: list[Discovery] - """ - Supported capabilities and extensions. - """ - - -class ResponseCheckout(BaseModel): - """UCP metadata for checkout responses.""" - - model_config = ConfigDict( - extra="allow", - ) - version: Version - capabilities: list[Response] - """ - Active capabilities for this response. - """ - - -class ResponseOrder(BaseModel): - """UCP metadata for order responses. No payment handlers needed post-purchase.""" - - model_config = ConfigDict( - extra="allow", - ) - version: Version - capabilities: list[Response] - """ - Active capabilities for this response. - """ - - -class Rest(BaseModel): - """REST transport binding.""" - - model_config = ConfigDict( - extra="allow", - ) - schema_: AnyUrl = Field(..., alias="schema") - """ - URL to OpenAPI 3.x specification (JSON format) - """ - endpoint: AnyUrl - """ - Merchant's REST API endpoint - """ - - -class Mcp(BaseModel): - """MCP transport binding.""" - - model_config = ConfigDict( - extra="allow", - ) - schema_: AnyUrl = Field(..., alias="schema") - """ - URL to OpenRPC specification (JSON format) - """ - endpoint: AnyUrl - """ - Merchant's MCP endpoint - """ - - -class A2a(BaseModel): - """A2A transport binding.""" - - model_config = ConfigDict( - extra="allow", - ) - endpoint: AnyUrl - """ - Merchant's Agent Card endpoint - """ - - -class Embedded(BaseModel): - """Embedded transport binding (JSON-RPC 2.0 over postMessage). Unlike REST/MCP, the endpoint is per-capability (i.e. per-checkout via continue_url), not per-service.""" - - model_config = ConfigDict( - extra="allow", - ) - schema_: AnyUrl = Field(..., alias="schema") - """ - URL to OpenRPC specification (JSON format) defining the embedded protocol - """ - - -class UcpService(BaseModel): - """Schema for UCP service definitions. A service defines the API surface for a vertical (shopping, common, etc.) with transport bindings.""" - - model_config = ConfigDict( - extra="allow", - ) - version: Version - """ - Service version in YYYY-MM-DD format. - """ - spec: AnyUrl - """ - URL to service documentation. Origin MUST match namespace authority. - """ - rest: Rest | None = None - """ - REST transport binding - """ - mcp: Mcp | None = None - """ - MCP transport binding - """ - a2a: A2a | None = None - """ - A2A transport binding - """ - embedded: Embedded | None = None - """ - Embedded transport binding (JSON-RPC 2.0 over postMessage). Unlike REST/MCP, the endpoint is per-capability (i.e. per-checkout via continue_url), not per-service. - """ diff --git a/src/ucp_sdk/models/discovery/__init__.py b/src/ucp_sdk/models/discovery/__init__.py index 1252d6b..421dc21 100644 --- a/src/ucp_sdk/models/discovery/__init__.py +++ b/src/ucp_sdk/models/discovery/__init__.py @@ -15,3 +15,4 @@ # generated by datamodel-codegen # pylint: disable=all # pyformat: disable + diff --git a/src/ucp_sdk/models/discovery/profile_schema.py b/src/ucp_sdk/models/discovery/profile_schema.py index bef9040..f9b18c3 100644 --- a/src/ucp_sdk/models/discovery/profile_schema.py +++ b/src/ucp_sdk/models/discovery/profile_schema.py @@ -19,12 +19,16 @@ from __future__ import annotations from typing import Literal -from pydantic import BaseModel, ConfigDict -from ..schemas.shopping.types import payment_handler_resp -from .._internal import DiscoveryProfile + +from pydantic import BaseModel, ConfigDict, Field, RootModel + +from ..schemas._internal import Base_3, BusinessSchema_3, PlatformSchema_3 class SigningKey(BaseModel): + """Public key for signature verification in JWK format. + """ + model_config = ConfigDict( extra="allow", ) @@ -66,30 +70,44 @@ class SigningKey(BaseModel): """ -class Payment(BaseModel): - """Payment configuration containing handlers.""" +class Base(BaseModel): + """Base discovery profile with shared properties for all profile types. + """ model_config = ConfigDict( extra="allow", ) - handlers: list[payment_handler_resp.PaymentHandlerResponse] | None = None + ucp: Base_3 + signing_keys: list[SigningKey] | None = None """ - Payment handler definitions that describe how instruments can be collected + Public keys for signature verification (JWK format). Used to verify signed responses, webhooks, and other authenticated messages from this party. """ -class UcpDiscoveryProfile(BaseModel): - """Schema for UCP discovery profile returned from /.well-known/ucp.""" +class PlatformProfile(Base): + """Full discovery profile for platforms. Exposes complete service, capability, and payment handler registries. + """ model_config = ConfigDict( extra="allow", ) - ucp: DiscoveryProfile - payment: Payment | None = None + ucp: PlatformSchema_3 | None = None + + +class BusinessProfile(Base): + """Discovery profile for businesses/merchants. Subset of platform profile with business-specific configuration. """ - Payment configuration containing handlers - """ - signing_keys: list[SigningKey] | None = None + + model_config = ConfigDict( + extra="allow", + ) + ucp: BusinessSchema_3 | None = None + + +class UcpDiscoveryProfile(RootModel[PlatformProfile | BusinessProfile]): + root: PlatformProfile | BusinessProfile = Field( + ..., title="UCP Discovery Profile" + ) """ - Public keys for signature verification (JWK format). Used to verify signed responses, webhooks, and other authenticated messages from this party. + Schema for UCP discovery profiles. Business profiles are hosted at /.well-known/ucp; platform profiles are hosted at URIs advertised in request headers. """ diff --git a/src/ucp_sdk/models/handlers/__init__.py b/src/ucp_sdk/models/handlers/__init__.py index 1252d6b..421dc21 100644 --- a/src/ucp_sdk/models/handlers/__init__.py +++ b/src/ucp_sdk/models/handlers/__init__.py @@ -15,3 +15,4 @@ # generated by datamodel-codegen # pylint: disable=all # pyformat: disable + diff --git a/src/ucp_sdk/models/handlers/tokenization/__init__.py b/src/ucp_sdk/models/handlers/tokenization/__init__.py index 1252d6b..421dc21 100644 --- a/src/ucp_sdk/models/handlers/tokenization/__init__.py +++ b/src/ucp_sdk/models/handlers/tokenization/__init__.py @@ -15,3 +15,4 @@ # generated by datamodel-codegen # pylint: disable=all # pyformat: disable + diff --git a/src/ucp_sdk/models/handlers/tokenization/openapi.py b/src/ucp_sdk/models/handlers/tokenization/openapi.py index e8b3b8c..0f53946 100644 --- a/src/ucp_sdk/models/handlers/tokenization/openapi.py +++ b/src/ucp_sdk/models/handlers/tokenization/openapi.py @@ -19,6 +19,7 @@ from __future__ import annotations from typing import Any + from pydantic import RootModel 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/_internal.py b/src/ucp_sdk/models/schemas/_internal.py new file mode 100644 index 0000000..e8a126b --- /dev/null +++ b/src/ucp_sdk/models/schemas/_internal.py @@ -0,0 +1,549 @@ +# 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, Literal + +from pydantic import AnyUrl, BaseModel, ConfigDict, Field, RootModel + +from .transports import embedded_config + + +class UcpCapability(RootModel[Any]): + root: Any = Field(..., title="UCP Capability") + """ + Schema for UCP capabilities and extensions. Extensions are capabilities with an 'extends' field. Uses reverse-domain naming for governance. + """ + + +class Base(Entity): + model_config = ConfigDict( + extra="allow", + ) + extends: str | None = Field( + None, pattern="^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$" + ) + """ + Parent capability this extends. Present for extensions, absent for root capabilities. + """ + + +class PlatformSchema(Base): + """Full capability declaration for platform-level discovery. Includes spec/schema URLs for agent fetching. + """ + + model_config = ConfigDict( + extra="allow", + ) + + +class BusinessSchema(Base): + """Capability configuration for business/merchant level. May include business-specific config overrides. + """ + + model_config = ConfigDict( + extra="allow", + ) + + +class ResponseSchema(Base): + """Capability reference in responses. Only name/version required to confirm active capabilities. + """ + + model_config = ConfigDict( + extra="allow", + ) + + +class PaymentHandler(RootModel[Any]): + root: Any = Field(..., title="Payment Handler") + """ + Schema for UCP payment handlers. Handlers define how payment instruments are processed. + """ + + +class Base_1(Entity): + model_config = ConfigDict( + extra="allow", + ) + + +class PlatformSchema_1(Base_1): + """Platform declaration for discovery profiles. May include partial config state required for discovery. + """ + + model_config = ConfigDict( + extra="allow", + ) + + +class BusinessSchema_1(Base_1): + """Business declaration for discovery profiles. May include partial config state required for discovery. + """ + + model_config = ConfigDict( + extra="allow", + ) + + +class ResponseSchema_1(Base_1): + """Handler reference in responses. May include full config state for runtime usage of the handler. + """ + + model_config = ConfigDict( + extra="allow", + ) + + +class UcpService(RootModel[Any]): + root: Any = Field(..., title="UCP Service") + """ + Service binding for a specific transport. Each transport binding is a separate entry in the service array. + """ + + +class PlatformSchema_2(BaseModel): + model_config = ConfigDict( + extra="allow", + ) + transport: Literal["rest"] = "rest" + + +class PlatformSchema5(BaseModel): + model_config = ConfigDict( + extra="allow", + ) + transport: Literal["mcp"] = "mcp" + + +class PlatformSchema6(BaseModel): + model_config = ConfigDict( + extra="allow", + ) + transport: Literal["a2a"] = "a2a" + + +class PlatformSchema7(BaseModel): + model_config = ConfigDict( + extra="allow", + ) + transport: Literal["embedded"] = "embedded" + + +class BusinessSchema_2(BaseModel): + model_config = ConfigDict( + extra="allow", + ) + transport: Literal["rest"] = "rest" + + +class BusinessSchema4(BaseModel): + model_config = ConfigDict( + extra="allow", + ) + transport: Literal["mcp"] = "mcp" + + +class BusinessSchema5(BaseModel): + model_config = ConfigDict( + extra="allow", + ) + transport: Literal["a2a"] = "a2a" + + +class BusinessSchema6(BaseModel): + model_config = ConfigDict( + extra="allow", + ) + transport: Literal["embedded"] = "embedded" + config: embedded_config.EmbeddedTransportConfig | None = None + + +class ResponseSchema_2(BaseModel): + model_config = ConfigDict( + extra="allow", + ) + transport: Literal["rest"] = "rest" + + +class ResponseSchema4(BaseModel): + model_config = ConfigDict( + extra="allow", + ) + transport: Literal["mcp"] = "mcp" + + +class ResponseSchema5(BaseModel): + model_config = ConfigDict( + extra="allow", + ) + transport: Literal["a2a"] = "a2a" + + +class ResponseSchema6(BaseModel): + model_config = ConfigDict( + extra="allow", + ) + transport: Literal["embedded"] = "embedded" + config: embedded_config.EmbeddedTransportConfig | None = None + + +class Base_2(Entity): + model_config = ConfigDict( + extra="allow", + ) + transport: Literal["rest", "mcp", "a2a", "embedded"] + """ + Transport protocol for this service binding. + """ + endpoint: AnyUrl | None = None + """ + Endpoint URL for this transport binding. + """ + + +class PlatformSchema8(Base_2): + """Full service declaration for platform-level discovery. Different transports require different fields. + """ + + model_config = ConfigDict( + extra="allow", + ) + + +class PlatformSchema9(PlatformSchema_2, PlatformSchema8): + """Full service declaration for platform-level discovery. Different transports require different fields. + """ + + model_config = ConfigDict( + extra="allow", + ) + + +class PlatformSchema10(PlatformSchema5, PlatformSchema8): + """Full service declaration for platform-level discovery. Different transports require different fields. + """ + + model_config = ConfigDict( + extra="allow", + ) + + +class PlatformSchema11(PlatformSchema6, PlatformSchema8): + """Full service declaration for platform-level discovery. Different transports require different fields. + """ + + model_config = ConfigDict( + extra="allow", + ) + + +class PlatformSchema12(PlatformSchema7, PlatformSchema8): + """Full service declaration for platform-level discovery. Different transports require different fields. + """ + + model_config = ConfigDict( + extra="allow", + ) + + +class PlatformSchema3( + RootModel[ + PlatformSchema9 | PlatformSchema10 | PlatformSchema11 | PlatformSchema12 + ] +): + """Full service declaration for platform-level discovery. Different transports require different fields. + """ + + root: ( + PlatformSchema9 | PlatformSchema10 | PlatformSchema11 | PlatformSchema12 + ) = Field(..., title="Service (Platform Schema)") + """ + Full service declaration for platform-level discovery. Different transports require different fields. + """ + + +class BusinessSchema7(Base_2): + """Service binding for business/merchant configuration. May override platform endpoints. + """ + + model_config = ConfigDict( + extra="allow", + ) + + +class BusinessSchema8(BusinessSchema_2, BusinessSchema7): + """Service binding for business/merchant configuration. May override platform endpoints. + """ + + model_config = ConfigDict( + extra="allow", + ) + + +class BusinessSchema9(BusinessSchema4, BusinessSchema7): + """Service binding for business/merchant configuration. May override platform endpoints. + """ + + model_config = ConfigDict( + extra="allow", + ) + + +class BusinessSchema10(BusinessSchema5, BusinessSchema7): + """Service binding for business/merchant configuration. May override platform endpoints. + """ + + model_config = ConfigDict( + extra="allow", + ) + + +class BusinessSchema11(BusinessSchema6, BusinessSchema7): + """Service binding for business/merchant configuration. May override platform endpoints. + """ + + model_config = ConfigDict( + extra="allow", + ) + + +class BusinessSchema2( + RootModel[ + BusinessSchema8 | BusinessSchema9 | BusinessSchema10 | BusinessSchema11 + ] +): + """Service binding for business/merchant configuration. May override platform endpoints. + """ + + root: ( + BusinessSchema8 | BusinessSchema9 | BusinessSchema10 | BusinessSchema11 + ) = Field(..., title="Service (Business Schema)") + """ + Service binding for business/merchant configuration. May override platform endpoints. + """ + + +class ResponseSchema7(Base_2): + """Service binding in API responses. Includes per-resource transport configuration via typed config. + """ + + model_config = ConfigDict( + extra="allow", + ) + + +class ResponseSchema8(ResponseSchema_2, ResponseSchema7): + """Service binding in API responses. Includes per-resource transport configuration via typed config. + """ + + model_config = ConfigDict( + extra="allow", + ) + + +class ResponseSchema9(ResponseSchema4, ResponseSchema7): + """Service binding in API responses. Includes per-resource transport configuration via typed config. + """ + + model_config = ConfigDict( + extra="allow", + ) + + +class ResponseSchema10(ResponseSchema5, ResponseSchema7): + """Service binding in API responses. Includes per-resource transport configuration via typed config. + """ + + model_config = ConfigDict( + extra="allow", + ) + + +class ResponseSchema11(ResponseSchema6, ResponseSchema7): + """Service binding in API responses. Includes per-resource transport configuration via typed config. + """ + + model_config = ConfigDict( + extra="allow", + ) + + +class ResponseSchema2( + RootModel[ + ResponseSchema8 | ResponseSchema9 | ResponseSchema10 | ResponseSchema11 + ] +): + """Service binding in API responses. Includes per-resource transport configuration via typed config. + """ + + root: ( + ResponseSchema8 | ResponseSchema9 | ResponseSchema10 | ResponseSchema11 + ) = Field(..., title="Service (Response Schema)") + """ + Service binding in API responses. Includes per-resource transport configuration via typed config. + """ + + +class UcpMetadata(RootModel[Any]): + root: Any = Field(..., title="UCP Metadata") + """ + Protocol metadata for discovery profiles and responses. Uses slim schema pattern with context-specific required fields. + """ + + +class Version(RootModel[str]): + root: str = Field(..., pattern="^\\d{4}-\\d{2}-\\d{2}$") + """ + UCP version in YYYY-MM-DD format. + """ + + +class ReverseDomainName(RootModel[str]): + root: str = Field(..., pattern="^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$") + """ + Reverse-domain identifier (e.g., com.google.pay, dev.ucp.shopping.checkout) + """ + + +class Entity(BaseModel): + """Shared foundation for all UCP entities. + """ + + model_config = ConfigDict( + extra="allow", + ) + version: Version + """ + Entity version in YYYY-MM-DD format. + """ + spec: AnyUrl | None = None + """ + URL to human-readable specification document. + """ + schema_: AnyUrl | None = Field(None, alias="schema") + """ + URL to JSON Schema defining this entity's structure and payloads. + """ + id: str | None = None + """ + Unique identifier for this entity instance. Used to disambiguate when multiple instances exist. + """ + config: dict[str, Any] | None = None + """ + Entity-specific configuration. Structure defined by each entity's schema. + """ + + +class Base_3(BaseModel): + """Base UCP metadata with shared properties for all schema types. + """ + + model_config = ConfigDict( + extra="allow", + ) + version: Version + services: dict[ReverseDomainName, list[Base_2]] | None = None + """ + Service registry keyed by reverse-domain name. + """ + capabilities: dict[ReverseDomainName, list[Base]] | None = None + """ + Capability registry keyed by reverse-domain name. + """ + payment_handlers: dict[ReverseDomainName, list[Base_1]] | None = None + """ + Payment handler registry keyed by reverse-domain name. + """ + + +class PlatformSchema_3(Base_3): + """Full UCP metadata for platform-level configuration. Hosted at a URI advertised by the platform in request headers. + """ + + model_config = ConfigDict( + extra="allow", + ) + services: dict[ReverseDomainName, list[PlatformSchema3]] + """ + Service registry keyed by reverse-domain name. + """ + capabilities: dict[ReverseDomainName, list[PlatformSchema]] | None = None + """ + Capability registry keyed by reverse-domain name. + """ + payment_handlers: dict[ReverseDomainName, list[PlatformSchema_1]] + """ + Payment handler registry keyed by reverse-domain name. + """ + + +class BusinessSchema_3(Base_3): + """UCP metadata for business/merchant-level configuration. Subset of platform schema with business-specific settings. + """ + + model_config = ConfigDict( + extra="allow", + ) + services: dict[ReverseDomainName, list[BusinessSchema2]] + """ + Service registry keyed by reverse-domain name. + """ + capabilities: dict[ReverseDomainName, list[BusinessSchema]] | None = None + """ + Capability registry keyed by reverse-domain name. + """ + payment_handlers: dict[ReverseDomainName, list[BusinessSchema_1]] + """ + Payment handler registry keyed by reverse-domain name. + """ + + +class ResponseCheckoutSchema(Base_3): + """UCP metadata for checkout responses. + """ + + model_config = ConfigDict( + extra="allow", + ) + services: dict[ReverseDomainName, list[ResponseSchema2]] | None = None + """ + Service registry keyed by reverse-domain name. + """ + capabilities: dict[ReverseDomainName, list[ResponseSchema]] | None = None + """ + Capability registry keyed by reverse-domain name. + """ + payment_handlers: dict[ReverseDomainName, list[ResponseSchema_1]] + """ + Payment handler registry keyed by reverse-domain name. + """ + + +class ResponseOrderSchema(Base_3): + """UCP metadata for order responses. No payment handlers needed post-purchase. + """ + + model_config = ConfigDict( + extra="allow", + ) + capabilities: dict[ReverseDomainName, list[ResponseSchema]] | None = None + """ + Capability registry keyed by reverse-domain name. + """ diff --git a/src/ucp_sdk/models/schemas/capability.py b/src/ucp_sdk/models/schemas/capability.py index 26dc3d7..1dc558f 100644 --- a/src/ucp_sdk/models/schemas/capability.py +++ b/src/ucp_sdk/models/schemas/capability.py @@ -18,6 +18,18 @@ from __future__ import annotations -from .._internal import Base, Discovery, Response, UcpCapability +from ._internal import ( + Base, + BusinessSchema, + PlatformSchema, + ResponseSchema, + UcpCapability, +) -__all__ = ["Base", "Discovery", "Response", "UcpCapability"] +__all__ = [ + "Base", + "BusinessSchema", + "PlatformSchema", + "ResponseSchema", + "UcpCapability", +] diff --git a/src/ucp_sdk/models/schemas/payment_handler.py b/src/ucp_sdk/models/schemas/payment_handler.py new file mode 100644 index 0000000..2f4ed2b --- /dev/null +++ b/src/ucp_sdk/models/schemas/payment_handler.py @@ -0,0 +1,33 @@ +# 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 ._internal import Base_1 as Base +from ._internal import BusinessSchema_1 as BusinessSchema +from ._internal import PaymentHandler +from ._internal import PlatformSchema_1 as PlatformSchema +from ._internal import ResponseSchema_1 as ResponseSchema + +__all__ = [ + "Base", + "BusinessSchema", + "PaymentHandler", + "PlatformSchema", + "ResponseSchema", +] diff --git a/src/ucp_sdk/models/schemas/service.py b/src/ucp_sdk/models/schemas/service.py new file mode 100644 index 0000000..e1c5eb3 --- /dev/null +++ b/src/ucp_sdk/models/schemas/service.py @@ -0,0 +1,93 @@ +# 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 ._internal import Base_2 as Base +from ._internal import ( + BusinessSchema2, + BusinessSchema4, + BusinessSchema5, + BusinessSchema6, + BusinessSchema7, + BusinessSchema8, + BusinessSchema9, + BusinessSchema10, + BusinessSchema11, +) +from ._internal import BusinessSchema_2 as BusinessSchema +from ._internal import ( + PlatformSchema3, + PlatformSchema5, + PlatformSchema6, + PlatformSchema7, + PlatformSchema8, + PlatformSchema9, + PlatformSchema10, + PlatformSchema11, + PlatformSchema12, +) +from ._internal import PlatformSchema_2 as PlatformSchema +from ._internal import ( + ResponseSchema2, + ResponseSchema4, + ResponseSchema5, + ResponseSchema6, + ResponseSchema7, + ResponseSchema8, + ResponseSchema9, + ResponseSchema10, + ResponseSchema11, +) +from ._internal import ResponseSchema_2 as ResponseSchema +from ._internal import UcpService + +__all__ = [ + "Base", + "BusinessSchema", + "BusinessSchema10", + "BusinessSchema11", + "BusinessSchema2", + "BusinessSchema4", + "BusinessSchema5", + "BusinessSchema6", + "BusinessSchema7", + "BusinessSchema8", + "BusinessSchema9", + "PlatformSchema", + "PlatformSchema10", + "PlatformSchema11", + "PlatformSchema12", + "PlatformSchema3", + "PlatformSchema5", + "PlatformSchema6", + "PlatformSchema7", + "PlatformSchema8", + "PlatformSchema9", + "ResponseSchema", + "ResponseSchema10", + "ResponseSchema11", + "ResponseSchema2", + "ResponseSchema4", + "ResponseSchema5", + "ResponseSchema6", + "ResponseSchema7", + "ResponseSchema8", + "ResponseSchema9", + "UcpService", +] 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/ap2_mandate.py b/src/ucp_sdk/models/schemas/shopping/ap2_mandate.py index a41ef4c..7504199 100644 --- a/src/ucp_sdk/models/schemas/shopping/ap2_mandate.py +++ b/src/ucp_sdk/models/schemas/shopping/ap2_mandate.py @@ -19,8 +19,10 @@ from __future__ import annotations from typing import Any, Literal + from pydantic import BaseModel, ConfigDict, Field, RootModel -from .checkout_resp import CheckoutResponse + +from .checkout import Checkout as Checkout_1 class Ap2MandateExtension(RootModel[Any]): @@ -52,30 +54,38 @@ class CheckoutMandate(RootModel[str]): """ -class Ap2CheckoutResponse(BaseModel): - """The ap2 object included in checkout responses when AP2 is negotiated.""" +class Ap2WithMerchantAuthorization(BaseModel): + """AP2 extension data including merchant authorization. + """ model_config = ConfigDict( extra="allow", ) - merchant_authorization: MerchantAuthorization + merchant_authorization: MerchantAuthorization | None = None """ Merchant's signature proving checkout terms are authentic. """ -class Ap2CompleteRequest(BaseModel): - """The ap2 object included in complete_checkout requests when AP2 is negotiated.""" +class Ap2WithCheckoutMandate(BaseModel): + """AP2 extension data including checkout mandate. + """ model_config = ConfigDict( extra="allow", ) - checkout_mandate: CheckoutMandate + checkout_mandate: CheckoutMandate | None = None """ SD-JWT+kb proving user authorized this checkout. """ +class Ap2(Ap2WithMerchantAuthorization, Ap2WithCheckoutMandate): + model_config = ConfigDict( + extra="allow", + ) + + class ErrorCode( RootModel[ Literal[ @@ -103,25 +113,11 @@ class ErrorCode( """ -class CompleteRequestWithAp2(BaseModel): - """Extension fields for complete_checkout when AP2 is negotiated.""" - - model_config = ConfigDict( - extra="allow", - ) - ap2: Ap2CompleteRequest | None = None +class Checkout(Checkout_1): + """Checkout extended with AP2 mandate support. """ - AP2 extension data including checkout mandate. - """ - - -class CheckoutResponseWithAp2(CheckoutResponse): - """Checkout extended with AP2 embedded signature support.""" model_config = ConfigDict( extra="allow", ) - ap2: Ap2CheckoutResponse | None = None - """ - AP2 extension data including merchant authorization. - """ + ap2: Ap2 | None = None diff --git a/src/ucp_sdk/models/schemas/shopping/buyer_consent_resp.py b/src/ucp_sdk/models/schemas/shopping/buyer_consent.py similarity index 82% rename from src/ucp_sdk/models/schemas/shopping/buyer_consent_resp.py rename to src/ucp_sdk/models/schemas/shopping/buyer_consent.py index f2117fb..7bf0623 100644 --- a/src/ucp_sdk/models/schemas/shopping/buyer_consent_resp.py +++ b/src/ucp_sdk/models/schemas/shopping/buyer_consent.py @@ -19,20 +19,23 @@ from __future__ import annotations from typing import Any + from pydantic import BaseModel, ConfigDict, Field, RootModel + +from .checkout import Checkout as Checkout_1 from .types.buyer import Buyer as Buyer_1 -from .checkout_resp import CheckoutResponse -class BuyerConsentExtensionResponse(RootModel[Any]): - root: Any = Field(..., title="Buyer Consent Extension Response") +class BuyerConsentExtension(RootModel[Any]): + root: Any = Field(..., title="Buyer Consent Extension") """ Extends Checkout with buyer consent tracking for privacy compliance via the buyer object. """ class Consent(BaseModel): - """User consent states for data processing.""" + """User consent states for data processing + """ model_config = ConfigDict( extra="allow", @@ -56,7 +59,8 @@ class Consent(BaseModel): class Buyer(Buyer_1): - """Buyer object extended with consent tracking.""" + """Buyer object extended with consent tracking. + """ model_config = ConfigDict( extra="allow", @@ -67,8 +71,9 @@ class Buyer(Buyer_1): """ -class Checkout(CheckoutResponse): - """Checkout extended with consent tracking via buyer object.""" +class Checkout(Checkout_1): + """Checkout extended with consent tracking via buyer object. + """ model_config = ConfigDict( extra="allow", diff --git a/src/ucp_sdk/models/schemas/shopping/buyer_consent_create_req.py b/src/ucp_sdk/models/schemas/shopping/buyer_consent_create_req.py deleted file mode 100644 index f1d2dae..0000000 --- a/src/ucp_sdk/models/schemas/shopping/buyer_consent_create_req.py +++ /dev/null @@ -1,79 +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, RootModel -from .types.buyer import Buyer as Buyer_1 -from .checkout_create_req import CheckoutCreateRequest - - -class BuyerConsentExtensionCreateRequest(RootModel[Any]): - root: Any = Field(..., title="Buyer Consent Extension Create Request") - """ - Extends Checkout with buyer consent tracking for privacy compliance via the buyer object. - """ - - -class Consent(BaseModel): - """User consent states for data processing.""" - - model_config = ConfigDict( - extra="allow", - ) - analytics: bool | None = None - """ - Consent for analytics and performance tracking. - """ - preferences: bool | None = None - """ - Consent for storing user preferences. - """ - marketing: bool | None = None - """ - Consent for marketing communications. - """ - sale_of_data: bool | None = None - """ - Consent for selling data to third parties (CCPA). - """ - - -class Buyer(Buyer_1): - """Buyer object extended with consent tracking.""" - - model_config = ConfigDict( - extra="allow", - ) - consent: Consent | None = None - """ - Consent tracking fields. - """ - - -class Checkout(CheckoutCreateRequest): - """Checkout extended with consent tracking via buyer object.""" - - model_config = ConfigDict( - extra="allow", - ) - buyer: Buyer | None = None - """ - Buyer with consent tracking. - """ diff --git a/src/ucp_sdk/models/schemas/shopping/buyer_consent_update_req.py b/src/ucp_sdk/models/schemas/shopping/buyer_consent_update_req.py deleted file mode 100644 index 33d4e84..0000000 --- a/src/ucp_sdk/models/schemas/shopping/buyer_consent_update_req.py +++ /dev/null @@ -1,79 +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, RootModel -from .types.buyer import Buyer as Buyer_1 -from .checkout_update_req import CheckoutUpdateRequest - - -class BuyerConsentExtensionUpdateRequest(RootModel[Any]): - root: Any = Field(..., title="Buyer Consent Extension Update Request") - """ - Extends Checkout with buyer consent tracking for privacy compliance via the buyer object. - """ - - -class Consent(BaseModel): - """User consent states for data processing.""" - - model_config = ConfigDict( - extra="allow", - ) - analytics: bool | None = None - """ - Consent for analytics and performance tracking. - """ - preferences: bool | None = None - """ - Consent for storing user preferences. - """ - marketing: bool | None = None - """ - Consent for marketing communications. - """ - sale_of_data: bool | None = None - """ - Consent for selling data to third parties (CCPA). - """ - - -class Buyer(Buyer_1): - """Buyer object extended with consent tracking.""" - - model_config = ConfigDict( - extra="allow", - ) - consent: Consent | None = None - """ - Consent tracking fields. - """ - - -class Checkout(CheckoutUpdateRequest): - """Checkout extended with consent tracking via buyer object.""" - - model_config = ConfigDict( - extra="allow", - ) - buyer: Buyer | None = None - """ - Buyer with consent tracking. - """ diff --git a/src/ucp_sdk/models/schemas/shopping/checkout_resp.py b/src/ucp_sdk/models/schemas/shopping/checkout.py similarity index 78% rename from src/ucp_sdk/models/schemas/shopping/checkout_resp.py rename to src/ucp_sdk/models/schemas/shopping/checkout.py index 46085e3..f3abfc8 100644 --- a/src/ucp_sdk/models/schemas/shopping/checkout_resp.py +++ b/src/ucp_sdk/models/schemas/shopping/checkout.py @@ -19,31 +19,29 @@ from __future__ import annotations from typing import Literal + from pydantic import AnyUrl, AwareDatetime, BaseModel, ConfigDict -from ..._internal import ResponseCheckout -from .types import ( - buyer as buyer_1, - line_item_resp, - link, - message, - order_confirmation, - total_resp, -) -from . import payment_resp + +from .._internal import ResponseCheckoutSchema +from . import payment as payment_1 +from .types import buyer as buyer_1 +from .types import context as context_1 +from .types import line_item, link, message, order_confirmation, total -class CheckoutResponse(BaseModel): - """Base checkout schema. Extensions compose onto this using allOf.""" +class Checkout(BaseModel): + """Base checkout schema. Extensions compose onto this using allOf. + """ model_config = ConfigDict( extra="allow", ) - ucp: ResponseCheckout + ucp: ResponseCheckoutSchema id: str """ Unique identifier of the checkout session. """ - line_items: list[line_item_resp.LineItemResponse] + line_items: list[line_item.LineItem] """ List of line items being checked out. """ @@ -51,6 +49,7 @@ class CheckoutResponse(BaseModel): """ Representation of the buyer. """ + context: context_1.Context | None = None status: Literal[ "incomplete", "requires_escalation", @@ -64,9 +63,9 @@ class CheckoutResponse(BaseModel): """ currency: str """ - ISO 4217 currency code. + ISO 4217 currency code reflecting the merchant's market determination. Derived from address, context, and geo IP—buyers provide signals, merchants determine currency. """ - totals: list[total_resp.TotalResponse] + totals: list[total.Total] """ Different cart totals. """ @@ -86,7 +85,7 @@ class CheckoutResponse(BaseModel): """ URL for checkout handoff and session recovery. MUST be provided when status is requires_escalation. See specification for format and availability requirements. """ - payment: payment_resp.PaymentResponse + payment: payment_1.Payment | None = None order: order_confirmation.OrderConfirmation | None = None """ Details about an order created for this checkout session. diff --git a/src/ucp_sdk/models/schemas/shopping/payment_data.py b/src/ucp_sdk/models/schemas/shopping/checkout_complete_request.py similarity index 78% rename from src/ucp_sdk/models/schemas/shopping/payment_data.py rename to src/ucp_sdk/models/schemas/shopping/checkout_complete_request.py index 5a8a03d..3c8c487 100644 --- a/src/ucp_sdk/models/schemas/shopping/payment_data.py +++ b/src/ucp_sdk/models/schemas/shopping/checkout_complete_request.py @@ -19,13 +19,15 @@ from __future__ import annotations from pydantic import BaseModel, ConfigDict -from .types import payment_instrument +from . import payment_complete_request -class PaymentData(BaseModel): - """The data that will used to submit payment to the merchant.""" + +class CheckoutCompleteRequest(BaseModel): + """Base checkout schema. Extensions compose onto this using allOf. + """ model_config = ConfigDict( extra="allow", ) - payment_data: payment_instrument.PaymentInstrument + payment: payment_complete_request.PaymentCompleteRequest diff --git a/src/ucp_sdk/models/schemas/shopping/checkout_create_req.py b/src/ucp_sdk/models/schemas/shopping/checkout_create_request.py similarity index 70% rename from src/ucp_sdk/models/schemas/shopping/checkout_create_req.py rename to src/ucp_sdk/models/schemas/shopping/checkout_create_request.py index ad53d1f..7a0ec30 100644 --- a/src/ucp_sdk/models/schemas/shopping/checkout_create_req.py +++ b/src/ucp_sdk/models/schemas/shopping/checkout_create_request.py @@ -19,26 +19,29 @@ from __future__ import annotations from pydantic import BaseModel, ConfigDict -from .types import buyer as buyer_1, line_item_create_req -from . import payment_create_req + +from . import payment_create_request +from .types import ( + buyer_create_request, + context_create_request, + line_item_create_request, +) class CheckoutCreateRequest(BaseModel): - """Base checkout schema. Extensions compose onto this using allOf.""" + """Base checkout schema. Extensions compose onto this using allOf. + """ model_config = ConfigDict( extra="allow", ) - line_items: list[line_item_create_req.LineItemCreateRequest] + line_items: list[line_item_create_request.LineItemCreateRequest] """ List of line items being checked out. """ - buyer: buyer_1.Buyer | None = None + buyer: buyer_create_request.BuyerCreateRequest | None = None """ Representation of the buyer. """ - currency: str - """ - ISO 4217 currency code. - """ - payment: payment_create_req.PaymentCreateRequest + context: context_create_request.ContextCreateRequest | None = None + payment: payment_create_request.PaymentCreateRequest | None = None diff --git a/src/ucp_sdk/models/schemas/shopping/checkout_update_req.py b/src/ucp_sdk/models/schemas/shopping/checkout_update_request.py similarity index 72% rename from src/ucp_sdk/models/schemas/shopping/checkout_update_req.py rename to src/ucp_sdk/models/schemas/shopping/checkout_update_request.py index 6234448..bedba40 100644 --- a/src/ucp_sdk/models/schemas/shopping/checkout_update_req.py +++ b/src/ucp_sdk/models/schemas/shopping/checkout_update_request.py @@ -19,12 +19,18 @@ from __future__ import annotations from pydantic import BaseModel, ConfigDict -from .types import buyer as buyer_1, line_item_update_req -from . import payment_update_req + +from . import payment_update_request +from .types import ( + buyer_update_request, + context_update_request, + line_item_update_request, +) class CheckoutUpdateRequest(BaseModel): - """Base checkout schema. Extensions compose onto this using allOf.""" + """Base checkout schema. Extensions compose onto this using allOf. + """ model_config = ConfigDict( extra="allow", @@ -33,16 +39,13 @@ class CheckoutUpdateRequest(BaseModel): """ Unique identifier of the checkout session. """ - line_items: list[line_item_update_req.LineItemUpdateRequest] + line_items: list[line_item_update_request.LineItemUpdateRequest] """ List of line items being checked out. """ - buyer: buyer_1.Buyer | None = None + buyer: buyer_update_request.BuyerUpdateRequest | None = None """ Representation of the buyer. """ - currency: str - """ - ISO 4217 currency code. - """ - payment: payment_update_req.PaymentUpdateRequest + context: context_update_request.ContextUpdateRequest | None = None + payment: payment_update_request.PaymentUpdateRequest | None = None diff --git a/src/ucp_sdk/models/schemas/shopping/discount_resp.py b/src/ucp_sdk/models/schemas/shopping/discount.py similarity index 88% rename from src/ucp_sdk/models/schemas/shopping/discount_resp.py rename to src/ucp_sdk/models/schemas/shopping/discount.py index 86fd012..d44f3e2 100644 --- a/src/ucp_sdk/models/schemas/shopping/discount_resp.py +++ b/src/ucp_sdk/models/schemas/shopping/discount.py @@ -19,19 +19,22 @@ from __future__ import annotations from typing import Any, Literal + from pydantic import BaseModel, ConfigDict, Field, RootModel -from .checkout_resp import CheckoutResponse + +from .checkout import Checkout as Checkout_1 -class DiscountExtensionResponse(RootModel[Any]): - root: Any = Field(..., title="Discount Extension Response") +class DiscountExtension(RootModel[Any]): + root: Any = Field(..., title="Discount Extension") """ Extends Checkout with discount code support, enabling agents to apply promotional, loyalty, referral, and other discount codes. """ class Allocation(BaseModel): - """Breakdown of how a discount amount was allocated to a specific target.""" + """Breakdown of how a discount amount was allocated to a specific target. + """ model_config = ConfigDict( extra="allow", @@ -47,7 +50,8 @@ class Allocation(BaseModel): class AppliedDiscount(BaseModel): - """A discount that was successfully applied.""" + """A discount that was successfully applied. + """ model_config = ConfigDict( extra="allow", @@ -83,7 +87,8 @@ class AppliedDiscount(BaseModel): class DiscountsObject(BaseModel): - """Discount codes input and applied discounts output.""" + """Discount codes input and applied discounts output. + """ model_config = ConfigDict( extra="allow", @@ -98,8 +103,9 @@ class DiscountsObject(BaseModel): """ -class Checkout(CheckoutResponse): - """Checkout extended with discount capability.""" +class Checkout(Checkout_1): + """Checkout extended with discount capability. + """ model_config = ConfigDict( extra="allow", diff --git a/src/ucp_sdk/models/schemas/shopping/discount_create_req.py b/src/ucp_sdk/models/schemas/shopping/discount_create_req.py deleted file mode 100644 index 7595bb1..0000000 --- a/src/ucp_sdk/models/schemas/shopping/discount_create_req.py +++ /dev/null @@ -1,107 +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, Literal -from pydantic import BaseModel, ConfigDict, Field, RootModel -from .checkout_create_req import CheckoutCreateRequest - - -class DiscountExtensionCreateRequest(RootModel[Any]): - root: Any = Field(..., title="Discount Extension Create Request") - """ - Extends Checkout with discount code support, enabling agents to apply promotional, loyalty, referral, and other discount codes. - """ - - -class Allocation(BaseModel): - """Breakdown of how a discount amount was allocated to a specific target.""" - - model_config = ConfigDict( - extra="allow", - ) - path: str - """ - JSONPath to the allocation target (e.g., '$.line_items[0]', '$.totals.shipping'). - """ - amount: int = Field(..., ge=0) - """ - Amount allocated to this target in minor (cents) currency units. - """ - - -class AppliedDiscount(BaseModel): - """A discount that was successfully applied.""" - - model_config = ConfigDict( - extra="allow", - ) - code: str | None = None - """ - The discount code. Omitted for automatic discounts. - """ - title: str - """ - Human-readable discount name (e.g., 'Summer Sale 20% Off'). - """ - amount: int = Field(..., ge=0) - """ - Total discount amount in minor (cents) currency units. - """ - automatic: bool | None = False - """ - True if applied automatically by merchant rules (no code required). - """ - method: Literal["each", "across"] | None = None - """ - Allocation method. 'each' = applied independently per item. 'across' = split proportionally by value. - """ - priority: int | None = Field(None, ge=1) - """ - Stacking order for discount calculation. Lower numbers applied first (1 = first). - """ - allocations: list[Allocation] | None = None - """ - Breakdown of where this discount was allocated. Sum of allocation amounts equals total amount. - """ - - -class DiscountsObject(BaseModel): - """Discount codes input and applied discounts output.""" - - model_config = ConfigDict( - extra="allow", - ) - codes: list[str] | None = None - """ - Discount codes to apply. Case-insensitive. Replaces previously submitted codes. Send empty array to clear. - """ - applied: list[AppliedDiscount] | None = None - """ - Discounts successfully applied (code-based and automatic). - """ - - -class Checkout(CheckoutCreateRequest): - """Checkout extended with discount capability.""" - - model_config = ConfigDict( - extra="allow", - ) - discounts: DiscountsObject | None = None diff --git a/src/ucp_sdk/models/schemas/shopping/discount_update_req.py b/src/ucp_sdk/models/schemas/shopping/discount_update_req.py deleted file mode 100644 index a724dc2..0000000 --- a/src/ucp_sdk/models/schemas/shopping/discount_update_req.py +++ /dev/null @@ -1,107 +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, Literal -from pydantic import BaseModel, ConfigDict, Field, RootModel -from .checkout_update_req import CheckoutUpdateRequest - - -class DiscountExtensionUpdateRequest(RootModel[Any]): - root: Any = Field(..., title="Discount Extension Update Request") - """ - Extends Checkout with discount code support, enabling agents to apply promotional, loyalty, referral, and other discount codes. - """ - - -class Allocation(BaseModel): - """Breakdown of how a discount amount was allocated to a specific target.""" - - model_config = ConfigDict( - extra="allow", - ) - path: str - """ - JSONPath to the allocation target (e.g., '$.line_items[0]', '$.totals.shipping'). - """ - amount: int = Field(..., ge=0) - """ - Amount allocated to this target in minor (cents) currency units. - """ - - -class AppliedDiscount(BaseModel): - """A discount that was successfully applied.""" - - model_config = ConfigDict( - extra="allow", - ) - code: str | None = None - """ - The discount code. Omitted for automatic discounts. - """ - title: str - """ - Human-readable discount name (e.g., 'Summer Sale 20% Off'). - """ - amount: int = Field(..., ge=0) - """ - Total discount amount in minor (cents) currency units. - """ - automatic: bool | None = False - """ - True if applied automatically by merchant rules (no code required). - """ - method: Literal["each", "across"] | None = None - """ - Allocation method. 'each' = applied independently per item. 'across' = split proportionally by value. - """ - priority: int | None = Field(None, ge=1) - """ - Stacking order for discount calculation. Lower numbers applied first (1 = first). - """ - allocations: list[Allocation] | None = None - """ - Breakdown of where this discount was allocated. Sum of allocation amounts equals total amount. - """ - - -class DiscountsObject(BaseModel): - """Discount codes input and applied discounts output.""" - - model_config = ConfigDict( - extra="allow", - ) - codes: list[str] | None = None - """ - Discount codes to apply. Case-insensitive. Replaces previously submitted codes. Send empty array to clear. - """ - applied: list[AppliedDiscount] | None = None - """ - Discounts successfully applied (code-based and automatic). - """ - - -class Checkout(CheckoutUpdateRequest): - """Checkout extended with discount capability.""" - - model_config = ConfigDict( - extra="allow", - ) - discounts: DiscountsObject | None = None diff --git a/src/ucp_sdk/models/schemas/shopping/fulfillment/__init__.py b/src/ucp_sdk/models/schemas/shopping/fulfillment/__init__.py new file mode 100644 index 0000000..c966542 --- /dev/null +++ b/src/ucp_sdk/models/schemas/shopping/fulfillment/__init__.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 ConfigDict, Field, RootModel + +from ..checkout import Checkout as Checkout_1 +from ..types import fulfillment as fulfillment_1 +from ..types import ( + fulfillment_available_method, + fulfillment_group, + fulfillment_method, + fulfillment_option, +) + + +class FulfillmentExtension(RootModel[Any]): + root: Any = Field(..., title="Fulfillment Extension") + """ + Extends Checkout with fulfillment support using methods, destinations, and groups. + """ + + +class FulfillmentAvailableMethod( + RootModel[fulfillment_available_method.FulfillmentAvailableMethod] +): + root: fulfillment_available_method.FulfillmentAvailableMethod + + +class FulfillmentOption(RootModel[fulfillment_option.FulfillmentOption]): + root: fulfillment_option.FulfillmentOption + + +class FulfillmentGroup(RootModel[fulfillment_group.FulfillmentGroup]): + root: fulfillment_group.FulfillmentGroup + + +class FulfillmentMethod(RootModel[fulfillment_method.FulfillmentMethod]): + root: fulfillment_method.FulfillmentMethod + + +class Fulfillment(RootModel[fulfillment_1.Fulfillment]): + root: fulfillment_1.Fulfillment + + +class Checkout(Checkout_1): + """Checkout extended with hierarchical fulfillment. + """ + + model_config = ConfigDict( + extra="allow", + ) + fulfillment: Fulfillment | None = None + """ + Fulfillment details. + """ diff --git a/src/ucp_sdk/models/services/service_schema.py b/src/ucp_sdk/models/schemas/shopping/fulfillment/dev/__init__.py similarity index 80% rename from src/ucp_sdk/models/services/service_schema.py rename to src/ucp_sdk/models/schemas/shopping/fulfillment/dev/__init__.py index 3272570..421dc21 100644 --- a/src/ucp_sdk/models/services/service_schema.py +++ b/src/ucp_sdk/models/schemas/shopping/fulfillment/dev/__init__.py @@ -16,8 +16,3 @@ # pylint: disable=all # pyformat: disable -from __future__ import annotations - -from .._internal import A2a, Embedded, Mcp, Rest, UcpService - -__all__ = ["A2a", "Embedded", "Mcp", "Rest", "UcpService"] diff --git a/src/ucp_sdk/models/schemas/shopping/fulfillment/dev/ucp/__init__.py b/src/ucp_sdk/models/schemas/shopping/fulfillment/dev/ucp/__init__.py new file mode 100644 index 0000000..421dc21 --- /dev/null +++ b/src/ucp_sdk/models/schemas/shopping/fulfillment/dev/ucp/__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/services/shopping/embedded_openrpc.py b/src/ucp_sdk/models/schemas/shopping/fulfillment/dev/ucp/shopping.py similarity index 95% rename from src/ucp_sdk/models/services/shopping/embedded_openrpc.py rename to src/ucp_sdk/models/schemas/shopping/fulfillment/dev/ucp/shopping.py index e8b3b8c..7919ae3 100644 --- a/src/ucp_sdk/models/services/shopping/embedded_openrpc.py +++ b/src/ucp_sdk/models/schemas/shopping/fulfillment/dev/ucp/shopping.py @@ -19,8 +19,9 @@ from __future__ import annotations from typing import Any + from pydantic import RootModel -class Model(RootModel[Any]): +class Fulfillment(RootModel[Any]): root: Any diff --git a/src/ucp_sdk/models/schemas/shopping/fulfillment_create_req.py b/src/ucp_sdk/models/schemas/shopping/fulfillment_create_req.py deleted file mode 100644 index 3e1abf8..0000000 --- a/src/ucp_sdk/models/schemas/shopping/fulfillment_create_req.py +++ /dev/null @@ -1,77 +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 ConfigDict, Field, RootModel -from .types import ( - fulfillment_available_method_req, - fulfillment_group_create_req, - fulfillment_method_create_req, - fulfillment_option_req, - fulfillment_req, -) -from .checkout_create_req import CheckoutCreateRequest - - -class FulfillmentExtensionCreateRequest(RootModel[Any]): - root: Any = Field(..., title="Fulfillment Extension Create Request") - """ - Extends Checkout with fulfillment support using methods, destinations, and groups. - """ - - -class FulfillmentOption( - RootModel[fulfillment_option_req.FulfillmentOptionRequest] -): - root: fulfillment_option_req.FulfillmentOptionRequest - - -class FulfillmentGroup( - RootModel[fulfillment_group_create_req.FulfillmentGroupCreateRequest] -): - root: fulfillment_group_create_req.FulfillmentGroupCreateRequest - - -class FulfillmentAvailableMethod( - RootModel[fulfillment_available_method_req.FulfillmentAvailableMethodRequest] -): - root: fulfillment_available_method_req.FulfillmentAvailableMethodRequest - - -class FulfillmentMethod( - RootModel[fulfillment_method_create_req.FulfillmentMethodCreateRequest] -): - root: fulfillment_method_create_req.FulfillmentMethodCreateRequest - - -class Fulfillment(RootModel[fulfillment_req.FulfillmentRequest]): - root: fulfillment_req.FulfillmentRequest - - -class Checkout(CheckoutCreateRequest): - """Checkout extended with hierarchical fulfillment.""" - - model_config = ConfigDict( - extra="allow", - ) - fulfillment: Fulfillment | None = None - """ - Fulfillment details. - """ diff --git a/src/ucp_sdk/models/schemas/shopping/fulfillment_resp.py b/src/ucp_sdk/models/schemas/shopping/fulfillment_resp.py deleted file mode 100644 index ff445dc..0000000 --- a/src/ucp_sdk/models/schemas/shopping/fulfillment_resp.py +++ /dev/null @@ -1,79 +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 ConfigDict, Field, RootModel -from .types import ( - fulfillment_available_method_resp, - fulfillment_group_resp, - fulfillment_method_resp, - fulfillment_option_resp, - fulfillment_resp, -) -from .checkout_resp import CheckoutResponse - - -class FulfillmentExtensionResponse(RootModel[Any]): - root: Any = Field(..., title="Fulfillment Extension Response") - """ - Extends Checkout with fulfillment support using methods, destinations, and groups. - """ - - -class FulfillmentAvailableMethod( - RootModel[ - fulfillment_available_method_resp.FulfillmentAvailableMethodResponse - ] -): - root: fulfillment_available_method_resp.FulfillmentAvailableMethodResponse - - -class FulfillmentOption( - RootModel[fulfillment_option_resp.FulfillmentOptionResponse] -): - root: fulfillment_option_resp.FulfillmentOptionResponse - - -class FulfillmentGroup( - RootModel[fulfillment_group_resp.FulfillmentGroupResponse] -): - root: fulfillment_group_resp.FulfillmentGroupResponse - - -class FulfillmentMethod( - RootModel[fulfillment_method_resp.FulfillmentMethodResponse] -): - root: fulfillment_method_resp.FulfillmentMethodResponse - - -class Fulfillment(RootModel[fulfillment_resp.FulfillmentResponse]): - root: fulfillment_resp.FulfillmentResponse - - -class Checkout(CheckoutResponse): - """Checkout extended with hierarchical fulfillment.""" - - model_config = ConfigDict( - extra="allow", - ) - fulfillment: Fulfillment | None = None - """ - Fulfillment details. - """ diff --git a/src/ucp_sdk/models/schemas/shopping/fulfillment_update_req.py b/src/ucp_sdk/models/schemas/shopping/fulfillment_update_req.py deleted file mode 100644 index 01d1608..0000000 --- a/src/ucp_sdk/models/schemas/shopping/fulfillment_update_req.py +++ /dev/null @@ -1,77 +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 ConfigDict, Field, RootModel -from .types import ( - fulfillment_available_method_req, - fulfillment_group_update_req, - fulfillment_method_update_req, - fulfillment_option_req, - fulfillment_req, -) -from .checkout_update_req import CheckoutUpdateRequest - - -class FulfillmentExtensionUpdateRequest(RootModel[Any]): - root: Any = Field(..., title="Fulfillment Extension Update Request") - """ - Extends Checkout with fulfillment support using methods, destinations, and groups. - """ - - -class FulfillmentOption( - RootModel[fulfillment_option_req.FulfillmentOptionRequest] -): - root: fulfillment_option_req.FulfillmentOptionRequest - - -class FulfillmentGroup( - RootModel[fulfillment_group_update_req.FulfillmentGroupUpdateRequest] -): - root: fulfillment_group_update_req.FulfillmentGroupUpdateRequest - - -class FulfillmentAvailableMethod( - RootModel[fulfillment_available_method_req.FulfillmentAvailableMethodRequest] -): - root: fulfillment_available_method_req.FulfillmentAvailableMethodRequest - - -class FulfillmentMethod( - RootModel[fulfillment_method_update_req.FulfillmentMethodUpdateRequest] -): - root: fulfillment_method_update_req.FulfillmentMethodUpdateRequest - - -class Fulfillment(RootModel[fulfillment_req.FulfillmentRequest]): - root: fulfillment_req.FulfillmentRequest - - -class Checkout(CheckoutUpdateRequest): - """Checkout extended with hierarchical fulfillment.""" - - model_config = ConfigDict( - extra="allow", - ) - fulfillment: Fulfillment | None = None - """ - Fulfillment details. - """ diff --git a/src/ucp_sdk/models/schemas/shopping/order.py b/src/ucp_sdk/models/schemas/shopping/order.py index eeed457..abbbde0 100644 --- a/src/ucp_sdk/models/schemas/shopping/order.py +++ b/src/ucp_sdk/models/schemas/shopping/order.py @@ -19,18 +19,20 @@ from __future__ import annotations from pydantic import AnyUrl, BaseModel, ConfigDict + +from .._internal import ResponseOrderSchema from .types import ( adjustment, expectation, fulfillment_event, order_line_item, - total_resp, + total, ) -from ..._internal import ResponseOrder -class PlatformConfig(BaseModel): - """Platform's order capability configuration.""" +class PlatformSchema(BaseModel): + """Platform's order capability configuration. + """ model_config = ConfigDict( extra="allow", @@ -42,7 +44,8 @@ class PlatformConfig(BaseModel): class Fulfillment(BaseModel): - """Fulfillment data: buyer expectations and what actually happened.""" + """Fulfillment data: buyer expectations and what actually happened. + """ model_config = ConfigDict( extra="allow", @@ -58,12 +61,13 @@ class Fulfillment(BaseModel): class Order(BaseModel): - """Order schema with immutable line items, buyer-facing fulfillment expectations, and append-only event logs.""" + """Order schema with immutable line items, buyer-facing fulfillment expectations, and append-only event logs. + """ model_config = ConfigDict( extra="allow", ) - ucp: ResponseOrder + ucp: ResponseOrderSchema id: str """ Unique order identifier. @@ -88,7 +92,7 @@ class Order(BaseModel): """ Append-only event log of money movements (refunds, returns, credits, disputes, cancellations, etc.) that exist independently of fulfillment. """ - totals: list[total_resp.TotalResponse] + totals: list[total.Total] """ Different totals for the order. """ diff --git a/src/ucp_sdk/models/schemas/shopping/payment.py b/src/ucp_sdk/models/schemas/shopping/payment.py new file mode 100644 index 0000000..b590dfb --- /dev/null +++ b/src/ucp_sdk/models/schemas/shopping/payment.py @@ -0,0 +1,36 @@ +# 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 + +from .types import payment_instrument + + +class Payment(BaseModel): + """Payment configuration containing handlers. + """ + + model_config = ConfigDict( + extra="allow", + ) + instruments: list[payment_instrument.SelectedPaymentInstrument] | None = None + """ + The payment instruments available for this payment. Each instrument is associated with a specific handler via the handler_id field. Handlers can extend the base payment_instrument schema to add handler-specific fields. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/payment_complete_request.py b/src/ucp_sdk/models/schemas/shopping/payment_complete_request.py new file mode 100644 index 0000000..8c157ba --- /dev/null +++ b/src/ucp_sdk/models/schemas/shopping/payment_complete_request.py @@ -0,0 +1,36 @@ +# 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 + +from .types import payment_instrument + + +class PaymentCompleteRequest(BaseModel): + """Payment configuration containing handlers. + """ + + model_config = ConfigDict( + extra="allow", + ) + instruments: list[payment_instrument.SelectedPaymentInstrument] | None = None + """ + The payment instruments available for this payment. Each instrument is associated with a specific handler via the handler_id field. Handlers can extend the base payment_instrument schema to add handler-specific fields. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/payment_create_req.py b/src/ucp_sdk/models/schemas/shopping/payment_create_request.py similarity index 75% rename from src/ucp_sdk/models/schemas/shopping/payment_create_req.py rename to src/ucp_sdk/models/schemas/shopping/payment_create_request.py index 1b5359d..382cd4a 100644 --- a/src/ucp_sdk/models/schemas/shopping/payment_create_req.py +++ b/src/ucp_sdk/models/schemas/shopping/payment_create_request.py @@ -19,20 +19,18 @@ from __future__ import annotations from pydantic import BaseModel, ConfigDict + from .types import payment_instrument class PaymentCreateRequest(BaseModel): - """Payment configuration containing handlers.""" + """Payment configuration containing handlers. + """ model_config = ConfigDict( extra="allow", ) - selected_instrument_id: str | None = None - """ - The id of the currently selected payment instrument from the instruments array. Set by the agent when submitting payment, and echoed back by the merchant in finalized state. - """ - instruments: list[payment_instrument.PaymentInstrument] | None = None + instruments: list[payment_instrument.SelectedPaymentInstrument] | None = None """ The payment instruments available for this payment. Each instrument is associated with a specific handler via the handler_id field. Handlers can extend the base payment_instrument schema to add handler-specific fields. """ diff --git a/src/ucp_sdk/models/schemas/shopping/payment_resp.py b/src/ucp_sdk/models/schemas/shopping/payment_resp.py deleted file mode 100644 index e8dda1d..0000000 --- a/src/ucp_sdk/models/schemas/shopping/payment_resp.py +++ /dev/null @@ -1,42 +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 -from .types import payment_handler_resp, payment_instrument - - -class PaymentResponse(BaseModel): - """Payment configuration containing handlers.""" - - model_config = ConfigDict( - extra="allow", - ) - handlers: list[payment_handler_resp.PaymentHandlerResponse] - """ - Processing configurations that define how payment instruments can be collected. Each handler specifies a tokenization or payment collection strategy. - """ - selected_instrument_id: str | None = None - """ - The id of the currently selected payment instrument from the instruments array. Set by the agent when submitting payment, and echoed back by the merchant in finalized state. - """ - instruments: list[payment_instrument.PaymentInstrument] | None = None - """ - The payment instruments available for this payment. Each instrument is associated with a specific handler via the handler_id field. Handlers can extend the base payment_instrument schema to add handler-specific fields. - """ diff --git a/src/ucp_sdk/models/schemas/shopping/payment_update_req.py b/src/ucp_sdk/models/schemas/shopping/payment_update_request.py similarity index 75% rename from src/ucp_sdk/models/schemas/shopping/payment_update_req.py rename to src/ucp_sdk/models/schemas/shopping/payment_update_request.py index 083d0a7..046cbe3 100644 --- a/src/ucp_sdk/models/schemas/shopping/payment_update_req.py +++ b/src/ucp_sdk/models/schemas/shopping/payment_update_request.py @@ -19,20 +19,18 @@ from __future__ import annotations from pydantic import BaseModel, ConfigDict + from .types import payment_instrument class PaymentUpdateRequest(BaseModel): - """Payment configuration containing handlers.""" + """Payment configuration containing handlers. + """ model_config = ConfigDict( extra="allow", ) - selected_instrument_id: str | None = None - """ - The id of the currently selected payment instrument from the instruments array. Set by the agent when submitting payment, and echoed back by the merchant in finalized state. - """ - instruments: list[payment_instrument.PaymentInstrument] | None = None + instruments: list[payment_instrument.SelectedPaymentInstrument] | None = None """ The payment instruments available for this payment. Each instrument is associated with a specific handler via the handler_id field. Handlers can extend the base payment_instrument schema to add handler-specific fields. """ 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/account_info.py b/src/ucp_sdk/models/schemas/shopping/types/account_info.py index f06f00f..a7d771d 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/account_info.py +++ b/src/ucp_sdk/models/schemas/shopping/types/account_info.py @@ -22,7 +22,8 @@ class PaymentAccountInfo(BaseModel): - """Non-sensitive backend identifiers for linking.""" + """Non-sensitive backend identifiers for linking. + """ model_config = ConfigDict( extra="allow", diff --git a/src/ucp_sdk/models/schemas/shopping/types/adjustment.py b/src/ucp_sdk/models/schemas/shopping/types/adjustment.py index 17719e6..36600ff 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/adjustment.py +++ b/src/ucp_sdk/models/schemas/shopping/types/adjustment.py @@ -18,9 +18,10 @@ from __future__ import annotations -from pydantic import AwareDatetime, BaseModel, ConfigDict, Field from typing import Literal +from pydantic import AwareDatetime, BaseModel, ConfigDict, Field + class LineItem(BaseModel): model_config = ConfigDict( @@ -37,7 +38,8 @@ class LineItem(BaseModel): class Adjustment(BaseModel): - """Append-only event that exists independently of fulfillment. Typically represents money movements but can be any post-order change. Polymorphic type that can optionally reference line items.""" + """Append-only event that exists independently of fulfillment. Typically represents money movements but can be any post-order change. Polymorphic type that can optionally reference line items. + """ model_config = ConfigDict( extra="allow", diff --git a/src/ucp_sdk/models/schemas/shopping/types/binding.py b/src/ucp_sdk/models/schemas/shopping/types/binding.py index c4971ca..1d4ad02 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/binding.py +++ b/src/ucp_sdk/models/schemas/shopping/types/binding.py @@ -19,11 +19,13 @@ from __future__ import annotations from pydantic import BaseModel, ConfigDict + from . import payment_identity class Binding(BaseModel): - """Binds a token to a specific checkout session and participant. Prevents token reuse across different checkouts or participants.""" + """Binds a token to a specific checkout session and participant. Prevents token reuse across different checkouts or participants. + """ model_config = ConfigDict( extra="allow", 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 new file mode 100644 index 0000000..07227b6 --- /dev/null +++ b/src/ucp_sdk/models/schemas/shopping/types/business_fulfillment_config.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 BaseModel, ConfigDict + + +class AllowsMultiDestination(BaseModel): + """Permits multiple destinations per method type. + """ + + model_config = ConfigDict( + extra="allow", + ) + shipping: bool | None = None + """ + Multiple shipping destinations allowed. + """ + pickup: bool | None = None + """ + Multiple pickup locations allowed. + """ + + +class BusinessFulfillmentConfig(BaseModel): + """Business's fulfillment configuration. + """ + + model_config = ConfigDict( + extra="allow", + ) + allows_multi_destination: AllowsMultiDestination | None = None + """ + Permits multiple destinations per method type. + """ + allows_method_combinations: ( + list[list[Literal["shipping", "pickup"]]] | None + ) = None + """ + Allowed method type combinations. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/buyer.py b/src/ucp_sdk/models/schemas/shopping/types/buyer.py index c93c729..c1c09ee 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/buyer.py +++ b/src/ucp_sdk/models/schemas/shopping/types/buyer.py @@ -33,10 +33,6 @@ class Buyer(BaseModel): """ Last name of the buyer. """ - full_name: str | None = None - """ - Optional, buyer's full name (if first_name or last_name fields are present they take precedence). - """ email: str | None = None """ Email of the buyer. diff --git a/src/ucp_sdk/models/schemas/shopping/types/buyer_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/buyer_create_request.py new file mode 100644 index 0000000..34b26f0 --- /dev/null +++ b/src/ucp_sdk/models/schemas/shopping/types/buyer_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 BuyerCreateRequest(BaseModel): + model_config = ConfigDict( + extra="allow", + ) + first_name: str | None = None + """ + First name of the buyer. + """ + last_name: str | None = None + """ + Last name of the buyer. + """ + email: str | None = None + """ + Email of the buyer. + """ + phone_number: str | None = None + """ + E.164 standard. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/buyer_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/buyer_update_request.py new file mode 100644 index 0000000..cacbb99 --- /dev/null +++ b/src/ucp_sdk/models/schemas/shopping/types/buyer_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 BuyerUpdateRequest(BaseModel): + model_config = ConfigDict( + extra="allow", + ) + first_name: str | None = None + """ + First name of the buyer. + """ + last_name: str | None = None + """ + Last name of the buyer. + """ + email: str | None = None + """ + Email of the buyer. + """ + phone_number: str | None = None + """ + E.164 standard. + """ 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 40854dc..614ec6c 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/card_credential.py +++ b/src/ucp_sdk/models/schemas/shopping/types/card_credential.py @@ -19,11 +19,15 @@ from __future__ import annotations from typing import Literal -from pydantic import BaseModel, ConfigDict, Field +from pydantic import ConfigDict, Field -class CardCredential(BaseModel): - """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.""" +from .payment_credential import PaymentCredential + + +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. + """ model_config = ConfigDict( extra="allow", 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 f57d38e..c4b1c14 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 @@ -19,25 +19,24 @@ from __future__ import annotations from typing import Literal -from pydantic import AnyUrl, ConfigDict -from .payment_instrument_base import PaymentInstrumentBase +from pydantic import AnyUrl, BaseModel, ConfigDict -class CardPaymentInstrument(PaymentInstrumentBase): - """A basic card payment instrument with visible card details. Can be inherited by a handler's instrument schema to define handler-specific display details or more complex credential structures.""" +from .payment_instrument import PaymentInstrument + + +class Display(BaseModel): + """Display information for this card payment instrument. + """ model_config = ConfigDict( extra="allow", ) - type: Literal["card"] - """ - Indicates this is a card payment instrument. - """ - brand: str + brand: str | None = None """ The card brand/network (e.g., visa, mastercard, amex). """ - last_digits: str + last_digits: str | None = None """ Last 4 digits of the card number. """ @@ -49,11 +48,28 @@ class CardPaymentInstrument(PaymentInstrumentBase): """ The year of the card's expiration date. """ - rich_text_description: str | None = None + description: str | None = None """ An optional rich text description of the card to display to the user (e.g., 'Visa ending in 1234, expires 12/2025'). """ - rich_card_art: AnyUrl | None = None + card_art: AnyUrl | None = None """ An optional URI to a rich image representing the card (e.g., card art provided by the issuer). """ + + +class CardPaymentInstrument(PaymentInstrument): + """A basic card payment instrument with visible card details. Can be inherited by a handler's instrument schema to define handler-specific display details or more complex credential structures. + """ + + model_config = ConfigDict( + extra="allow", + ) + type: Literal["card"] + """ + Indicates this is a card payment instrument. + """ + display: Display | None = None + """ + Display information for this card payment instrument. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/context.py b/src/ucp_sdk/models/schemas/shopping/types/context.py new file mode 100644 index 0000000..fccb800 --- /dev/null +++ b/src/ucp_sdk/models/schemas/shopping/types/context.py @@ -0,0 +1,42 @@ +# 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 Context(BaseModel): + """Provisional buyer signals for relevance and localization: product availability, pricing, currency, tax, shipping, payment methods, and eligibility (e.g., student or affiliation discounts). Businesses SHOULD use these values when authoritative data (e.g., address) is absent, and MAY ignore unsupported values without returning errors. Context can be disclosed progressively—coarse signals early, finer resolution as the session progresses. Higher-resolution data (shipping address, billing address) supersedes context. Platforms SHOULD progressively enhance context throughout the buyer journey. + """ + + model_config = ConfigDict( + extra="allow", + ) + 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. + """ + 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. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/context_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/context_create_request.py new file mode 100644 index 0000000..0e507e4 --- /dev/null +++ b/src/ucp_sdk/models/schemas/shopping/types/context_create_request.py @@ -0,0 +1,42 @@ +# 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 ContextCreateRequest(BaseModel): + """Provisional buyer signals for relevance and localization: product availability, pricing, currency, tax, shipping, payment methods, and eligibility (e.g., student or affiliation discounts). Businesses SHOULD use these values when authoritative data (e.g., address) is absent, and MAY ignore unsupported values without returning errors. Context can be disclosed progressively—coarse signals early, finer resolution as the session progresses. Higher-resolution data (shipping address, billing address) supersedes context. Platforms SHOULD progressively enhance context throughout the buyer journey. + """ + + model_config = ConfigDict( + extra="allow", + ) + 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. + """ + 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. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/context_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/context_update_request.py new file mode 100644 index 0000000..54c0dc4 --- /dev/null +++ b/src/ucp_sdk/models/schemas/shopping/types/context_update_request.py @@ -0,0 +1,42 @@ +# 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 ContextUpdateRequest(BaseModel): + """Provisional buyer signals for relevance and localization: product availability, pricing, currency, tax, shipping, payment methods, and eligibility (e.g., student or affiliation discounts). Businesses SHOULD use these values when authoritative data (e.g., address) is absent, and MAY ignore unsupported values without returning errors. Context can be disclosed progressively—coarse signals early, finer resolution as the session progresses. Higher-resolution data (shipping address, billing address) supersedes context. Platforms SHOULD progressively enhance context throughout the buyer journey. + """ + + model_config = ConfigDict( + extra="allow", + ) + 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. + """ + 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. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/expectation.py b/src/ucp_sdk/models/schemas/shopping/types/expectation.py index 28b85a5..1b89c5d 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/expectation.py +++ b/src/ucp_sdk/models/schemas/shopping/types/expectation.py @@ -18,8 +18,10 @@ from __future__ import annotations -from pydantic import BaseModel, ConfigDict, Field from typing import Literal + +from pydantic import BaseModel, ConfigDict, Field + from . import postal_address @@ -38,7 +40,8 @@ class LineItem(BaseModel): class Expectation(BaseModel): - """Buyer-facing fulfillment expectation representing logical groupings of items (e.g., 'package'). Can be split, merged, or adjusted post-order to set buyer expectations for when/how items arrive.""" + """Buyer-facing fulfillment expectation representing logical groupings of items (e.g., 'package'). Can be split, merged, or adjusted post-order to set buyer expectations for when/how items arrive. + """ model_config = ConfigDict( extra="allow", diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_resp.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment.py similarity index 72% rename from src/ucp_sdk/models/schemas/shopping/types/fulfillment_resp.py rename to src/ucp_sdk/models/schemas/shopping/types/fulfillment.py index 2c23ea1..9c7fe11 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_resp.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment.py @@ -19,22 +19,23 @@ from __future__ import annotations from pydantic import BaseModel, ConfigDict -from . import fulfillment_available_method_resp, fulfillment_method_resp +from . import fulfillment_available_method, fulfillment_method -class FulfillmentResponse(BaseModel): - """Container for fulfillment methods and availability.""" + +class Fulfillment(BaseModel): + """Container for fulfillment methods and availability. + """ model_config = ConfigDict( extra="allow", ) - methods: list[fulfillment_method_resp.FulfillmentMethodResponse] | None = None + methods: list[fulfillment_method.FulfillmentMethod] | None = None """ Fulfillment methods for cart items. """ available_methods: ( - list[fulfillment_available_method_resp.FulfillmentAvailableMethodResponse] - | None + list[fulfillment_available_method.FulfillmentAvailableMethod] | None ) = None """ Inventory availability hints. diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_available_method_resp.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_available_method.py similarity index 91% rename from src/ucp_sdk/models/schemas/shopping/types/fulfillment_available_method_resp.py rename to src/ucp_sdk/models/schemas/shopping/types/fulfillment_available_method.py index 9181950..1ebd1f6 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_available_method_resp.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_available_method.py @@ -19,11 +19,13 @@ from __future__ import annotations from typing import Literal + from pydantic import BaseModel, ConfigDict -class FulfillmentAvailableMethodResponse(BaseModel): - """Inventory availability hint for a fulfillment method type.""" +class FulfillmentAvailableMethod(BaseModel): + """Inventory availability hint for a fulfillment method type. + """ model_config = ConfigDict( extra="allow", diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_available_method_req.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_available_method_create_request.py similarity index 85% rename from src/ucp_sdk/models/schemas/shopping/types/fulfillment_available_method_req.py rename to src/ucp_sdk/models/schemas/shopping/types/fulfillment_available_method_create_request.py index 6bb4ef5..f105e39 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_available_method_req.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_available_method_create_request.py @@ -21,8 +21,9 @@ from pydantic import BaseModel, ConfigDict -class FulfillmentAvailableMethodRequest(BaseModel): - """Inventory availability hint for a fulfillment method type.""" +class FulfillmentAvailableMethodCreateRequest(BaseModel): + """Inventory availability hint for a fulfillment method type. + """ model_config = ConfigDict( extra="allow", diff --git a/src/ucp_sdk/models/schemas/shopping/types/payment_handler_update_req.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_available_method_update_request.py similarity index 85% rename from src/ucp_sdk/models/schemas/shopping/types/payment_handler_update_req.py rename to src/ucp_sdk/models/schemas/shopping/types/fulfillment_available_method_update_request.py index ce959e0..c768eb8 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/payment_handler_update_req.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_available_method_update_request.py @@ -21,7 +21,10 @@ from pydantic import BaseModel, ConfigDict -class PaymentHandlerUpdateRequest(BaseModel): +class FulfillmentAvailableMethodUpdateRequest(BaseModel): + """Inventory availability hint for a fulfillment method type. + """ + model_config = ConfigDict( extra="allow", ) diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_req.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_create_request.py similarity index 78% rename from src/ucp_sdk/models/schemas/shopping/types/fulfillment_req.py rename to src/ucp_sdk/models/schemas/shopping/types/fulfillment_create_request.py index 560ce75..cf2685c 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_req.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_create_request.py @@ -19,17 +19,20 @@ from __future__ import annotations from pydantic import BaseModel, ConfigDict -from . import fulfillment_method_create_req +from . import fulfillment_method_create_request -class FulfillmentRequest(BaseModel): - """Container for fulfillment methods and availability.""" + +class FulfillmentCreateRequest(BaseModel): + """Container for fulfillment methods and availability. + """ model_config = ConfigDict( extra="allow", ) methods: ( - list[fulfillment_method_create_req.FulfillmentMethodCreateRequest] | None + list[fulfillment_method_create_request.FulfillmentMethodCreateRequest] + | None ) = None """ Fulfillment methods for cart items. diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination_req.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination.py similarity index 68% rename from src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination_req.py rename to src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination.py index e8d45eb..73e4a6c 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination_req.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination.py @@ -19,19 +19,18 @@ from __future__ import annotations from pydantic import Field, RootModel -from . import retail_location_req, shipping_destination_req +from . import retail_location, shipping_destination -class FulfillmentDestinationRequest( + +class FulfillmentDestination( RootModel[ - shipping_destination_req.ShippingDestinationRequest - | retail_location_req.RetailLocationRequest + shipping_destination.ShippingDestination | retail_location.RetailLocation ] ): root: ( - shipping_destination_req.ShippingDestinationRequest - | retail_location_req.RetailLocationRequest - ) = Field(..., title="Fulfillment Destination Request") + 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_resp.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination_resp.py deleted file mode 100644 index 91ae5fb..0000000 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_destination_resp.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 Field, RootModel -from . import retail_location_resp, shipping_destination_resp - - -class FulfillmentDestinationResponse( - RootModel[ - shipping_destination_resp.ShippingDestinationResponse - | retail_location_resp.RetailLocationResponse - ] -): - root: ( - shipping_destination_resp.ShippingDestinationResponse - | retail_location_resp.RetailLocationResponse - ) = Field(..., title="Fulfillment Destination Response") - """ - 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 5711111..4f3fca6 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_event.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_event.py @@ -36,7 +36,8 @@ class LineItem(BaseModel): class FulfillmentEvent(BaseModel): - """Append-only fulfillment event representing an actual shipment. References line items by ID.""" + """Append-only fulfillment event representing an actual shipment. References line items by ID. + """ model_config = ConfigDict( extra="allow", diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_group_resp.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_group.py similarity index 87% rename from src/ucp_sdk/models/schemas/shopping/types/fulfillment_group_resp.py rename to src/ucp_sdk/models/schemas/shopping/types/fulfillment_group.py index cf00987..886f86b 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_group_resp.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_group.py @@ -19,11 +19,13 @@ from __future__ import annotations from pydantic import BaseModel, ConfigDict -from . import fulfillment_option_resp +from . import fulfillment_option -class FulfillmentGroupResponse(BaseModel): - """A merchant-generated package/group of line items with fulfillment options.""" + +class FulfillmentGroup(BaseModel): + """A merchant-generated package/group of line items with fulfillment options. + """ model_config = ConfigDict( extra="allow", @@ -36,7 +38,7 @@ class FulfillmentGroupResponse(BaseModel): """ Line item IDs included in this group/package. """ - options: list[fulfillment_option_resp.FulfillmentOptionResponse] | None = None + options: list[fulfillment_option.FulfillmentOption] | None = None """ Available fulfillment options for this group. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_group_create_req.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_group_create_request.py similarity index 97% rename from src/ucp_sdk/models/schemas/shopping/types/fulfillment_group_create_req.py rename to src/ucp_sdk/models/schemas/shopping/types/fulfillment_group_create_request.py index 171cf2b..a91ea1e 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_group_create_req.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_group_create_request.py @@ -22,7 +22,8 @@ class FulfillmentGroupCreateRequest(BaseModel): - """A merchant-generated package/group of line items with fulfillment options.""" + """A merchant-generated package/group of line items with fulfillment options. + """ model_config = ConfigDict( extra="allow", diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_group_update_req.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_group_update_request.py similarity index 98% rename from src/ucp_sdk/models/schemas/shopping/types/fulfillment_group_update_req.py rename to src/ucp_sdk/models/schemas/shopping/types/fulfillment_group_update_request.py index 6b6893b..270ca8e 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_group_update_req.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_group_update_request.py @@ -22,7 +22,8 @@ class FulfillmentGroupUpdateRequest(BaseModel): - """A merchant-generated package/group of line items with fulfillment options.""" + """A merchant-generated package/group of line items with fulfillment options. + """ model_config = ConfigDict( extra="allow", diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method_resp.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method.py similarity index 82% rename from src/ucp_sdk/models/schemas/shopping/types/fulfillment_method_resp.py rename to src/ucp_sdk/models/schemas/shopping/types/fulfillment_method.py index a593d84..830cec2 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method_resp.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method.py @@ -19,12 +19,15 @@ from __future__ import annotations from typing import Literal + from pydantic import BaseModel, ConfigDict -from . import fulfillment_destination_resp, fulfillment_group_resp + +from . import fulfillment_destination, fulfillment_group -class FulfillmentMethodResponse(BaseModel): - """A fulfillment method (shipping or pickup) with destinations and groups.""" +class FulfillmentMethod(BaseModel): + """A fulfillment method (shipping or pickup) with destinations and groups. + """ model_config = ConfigDict( extra="allow", @@ -41,9 +44,9 @@ class FulfillmentMethodResponse(BaseModel): """ Line item IDs fulfilled via this method. """ - destinations: ( - list[fulfillment_destination_resp.FulfillmentDestinationResponse] | None - ) = None + destinations: list[fulfillment_destination.FulfillmentDestination] | None = ( + None + ) """ Available destinations. For shipping: addresses. For pickup: retail locations. """ @@ -51,7 +54,7 @@ class FulfillmentMethodResponse(BaseModel): """ ID of the selected destination. """ - groups: list[fulfillment_group_resp.FulfillmentGroupResponse] | None = None + groups: list[fulfillment_group.FulfillmentGroup] | None = None """ Fulfillment groups for selecting options. Agent sets selected_option_id on groups to choose shipping method. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method_create_req.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method_create_request.py similarity index 84% rename from src/ucp_sdk/models/schemas/shopping/types/fulfillment_method_create_req.py rename to src/ucp_sdk/models/schemas/shopping/types/fulfillment_method_create_request.py index 3c2e61d..3763339 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method_create_req.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method_create_request.py @@ -19,12 +19,15 @@ from __future__ import annotations from typing import Literal + from pydantic import BaseModel, ConfigDict -from . import fulfillment_destination_req, fulfillment_group_create_req + +from . import fulfillment_destination, fulfillment_group_create_request class FulfillmentMethodCreateRequest(BaseModel): - """A fulfillment method (shipping or pickup) with destinations and groups.""" + """A fulfillment method (shipping or pickup) with destinations and groups. + """ model_config = ConfigDict( extra="allow", @@ -37,9 +40,9 @@ class FulfillmentMethodCreateRequest(BaseModel): """ Line item IDs fulfilled via this method. """ - destinations: ( - list[fulfillment_destination_req.FulfillmentDestinationRequest] | None - ) = None + destinations: list[fulfillment_destination.FulfillmentDestination] | None = ( + None + ) """ Available destinations. For shipping: addresses. For pickup: retail locations. """ @@ -48,7 +51,7 @@ class FulfillmentMethodCreateRequest(BaseModel): ID of the selected destination. """ groups: ( - list[fulfillment_group_create_req.FulfillmentGroupCreateRequest] | None + list[fulfillment_group_create_request.FulfillmentGroupCreateRequest] | None ) = None """ Fulfillment groups for selecting options. Agent sets selected_option_id on groups to choose shipping method. diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method_update_req.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method_update_request.py similarity index 83% rename from src/ucp_sdk/models/schemas/shopping/types/fulfillment_method_update_req.py rename to src/ucp_sdk/models/schemas/shopping/types/fulfillment_method_update_request.py index 253f03f..10e2dae 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method_update_req.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_method_update_request.py @@ -19,11 +19,13 @@ from __future__ import annotations from pydantic import BaseModel, ConfigDict -from . import fulfillment_destination_req, fulfillment_group_update_req + +from . import fulfillment_destination, fulfillment_group_update_request class FulfillmentMethodUpdateRequest(BaseModel): - """A fulfillment method (shipping or pickup) with destinations and groups.""" + """A fulfillment method (shipping or pickup) with destinations and groups. + """ model_config = ConfigDict( extra="allow", @@ -36,9 +38,9 @@ class FulfillmentMethodUpdateRequest(BaseModel): """ Line item IDs fulfilled via this method. """ - destinations: ( - list[fulfillment_destination_req.FulfillmentDestinationRequest] | None - ) = None + destinations: list[fulfillment_destination.FulfillmentDestination] | None = ( + None + ) """ Available destinations. For shipping: addresses. For pickup: retail locations. """ @@ -47,7 +49,7 @@ class FulfillmentMethodUpdateRequest(BaseModel): ID of the selected destination. """ groups: ( - list[fulfillment_group_update_req.FulfillmentGroupUpdateRequest] | None + list[fulfillment_group_update_request.FulfillmentGroupUpdateRequest] | None ) = None """ Fulfillment groups for selecting options. Agent sets selected_option_id on groups to choose shipping method. diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_resp.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option.py similarity index 91% rename from src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_resp.py rename to src/ucp_sdk/models/schemas/shopping/types/fulfillment_option.py index 3ba75eb..83c0d74 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_resp.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option.py @@ -19,11 +19,13 @@ from __future__ import annotations from pydantic import AwareDatetime, BaseModel, ConfigDict -from . import total_resp +from . import total -class FulfillmentOptionResponse(BaseModel): - """A fulfillment option within a group (e.g., Standard Shipping $5, Express $15).""" + +class FulfillmentOption(BaseModel): + """A fulfillment option within a group (e.g., Standard Shipping $5, Express $15). + """ model_config = ConfigDict( extra="allow", @@ -52,7 +54,7 @@ class FulfillmentOptionResponse(BaseModel): """ Latest fulfillment date. """ - totals: list[total_resp.TotalResponse] + totals: list[total.Total] """ Fulfillment option totals breakdown. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_req.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_create_request.py similarity index 91% rename from src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_req.py rename to src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_create_request.py index d33445e..3bf78a5 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_req.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_create_request.py @@ -21,8 +21,9 @@ from pydantic import BaseModel, ConfigDict -class FulfillmentOptionRequest(BaseModel): - """A fulfillment option within a group (e.g., Standard Shipping $5, Express $15).""" +class FulfillmentOptionCreateRequest(BaseModel): + """A fulfillment option within a group (e.g., Standard Shipping $5, Express $15). + """ model_config = ConfigDict( extra="allow", diff --git a/src/ucp_sdk/models/schemas/shopping/types/payment_handler_create_req.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_update_request.py similarity index 84% rename from src/ucp_sdk/models/schemas/shopping/types/payment_handler_create_req.py rename to src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_update_request.py index e8526ef..e37bc04 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/payment_handler_create_req.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_option_update_request.py @@ -21,7 +21,10 @@ from pydantic import BaseModel, ConfigDict -class PaymentHandlerCreateRequest(BaseModel): +class FulfillmentOptionUpdateRequest(BaseModel): + """A fulfillment option within a group (e.g., Standard Shipping $5, Express $15). + """ + model_config = ConfigDict( extra="allow", ) diff --git a/src/ucp_sdk/models/schemas/shopping/types/token_credential_resp.py b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_update_request.py similarity index 72% rename from src/ucp_sdk/models/schemas/shopping/types/token_credential_resp.py rename to src/ucp_sdk/models/schemas/shopping/types/fulfillment_update_request.py index 1cf6844..a97ef41 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/token_credential_resp.py +++ b/src/ucp_sdk/models/schemas/shopping/types/fulfillment_update_request.py @@ -20,14 +20,20 @@ from pydantic import BaseModel, ConfigDict +from . import fulfillment_method_update_request -class TokenCredentialResponse(BaseModel): - """Base token credential schema. Concrete payment handlers may extend this schema with additional fields and define their own constraints.""" + +class FulfillmentUpdateRequest(BaseModel): + """Container for fulfillment methods and availability. + """ model_config = ConfigDict( extra="allow", ) - type: str + methods: ( + list[fulfillment_method_update_request.FulfillmentMethodUpdateRequest] + | None + ) = None """ - The specific type of token produced by the handler (e.g., 'stripe_token'). + Fulfillment methods for cart items. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/item_resp.py b/src/ucp_sdk/models/schemas/shopping/types/item.py similarity index 97% rename from src/ucp_sdk/models/schemas/shopping/types/item_resp.py rename to src/ucp_sdk/models/schemas/shopping/types/item.py index 11b7afc..c1d407a 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/item_resp.py +++ b/src/ucp_sdk/models/schemas/shopping/types/item.py @@ -21,7 +21,7 @@ from pydantic import AnyUrl, BaseModel, ConfigDict, Field -class ItemResponse(BaseModel): +class Item(BaseModel): model_config = ConfigDict( extra="allow", ) diff --git a/src/ucp_sdk/models/schemas/shopping/types/item_create_req.py b/src/ucp_sdk/models/schemas/shopping/types/item_create_request.py similarity index 100% rename from src/ucp_sdk/models/schemas/shopping/types/item_create_req.py rename to src/ucp_sdk/models/schemas/shopping/types/item_create_request.py diff --git a/src/ucp_sdk/models/schemas/shopping/types/item_update_req.py b/src/ucp_sdk/models/schemas/shopping/types/item_update_request.py similarity index 100% rename from src/ucp_sdk/models/schemas/shopping/types/item_update_req.py rename to src/ucp_sdk/models/schemas/shopping/types/item_update_request.py diff --git a/src/ucp_sdk/models/schemas/shopping/types/line_item_resp.py b/src/ucp_sdk/models/schemas/shopping/types/line_item.py similarity index 87% rename from src/ucp_sdk/models/schemas/shopping/types/line_item_resp.py rename to src/ucp_sdk/models/schemas/shopping/types/line_item.py index 963d6e6..38f2f30 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/line_item_resp.py +++ b/src/ucp_sdk/models/schemas/shopping/types/line_item.py @@ -19,22 +19,25 @@ from __future__ import annotations from pydantic import BaseModel, ConfigDict, Field -from . import item_resp, total_resp +from . import item as item_1 +from . import total -class LineItemResponse(BaseModel): - """Line item object. Expected to use the currency of the parent object.""" + +class LineItem(BaseModel): + """Line item object. Expected to use the currency of the parent object. + """ model_config = ConfigDict( extra="allow", ) id: str - item: item_resp.ItemResponse + item: item_1.Item quantity: int = Field(..., ge=1) """ Quantity of the item being purchased. """ - totals: list[total_resp.TotalResponse] + totals: list[total.Total] """ Line item totals breakdown. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/line_item_create_req.py b/src/ucp_sdk/models/schemas/shopping/types/line_item_create_request.py similarity index 91% rename from src/ucp_sdk/models/schemas/shopping/types/line_item_create_req.py rename to src/ucp_sdk/models/schemas/shopping/types/line_item_create_request.py index 310c501..1d4a506 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/line_item_create_req.py +++ b/src/ucp_sdk/models/schemas/shopping/types/line_item_create_request.py @@ -19,16 +19,18 @@ from __future__ import annotations from pydantic import BaseModel, ConfigDict, Field -from . import item_create_req + +from . import item_create_request class LineItemCreateRequest(BaseModel): - """Line item object. Expected to use the currency of the parent object.""" + """Line item object. Expected to use the currency of the parent object. + """ model_config = ConfigDict( extra="allow", ) - item: item_create_req.ItemCreateRequest + item: item_create_request.ItemCreateRequest quantity: int = Field(..., ge=1) """ Quantity of the item being purchased. diff --git a/src/ucp_sdk/models/schemas/shopping/types/line_item_update_req.py b/src/ucp_sdk/models/schemas/shopping/types/line_item_update_request.py similarity index 92% rename from src/ucp_sdk/models/schemas/shopping/types/line_item_update_req.py rename to src/ucp_sdk/models/schemas/shopping/types/line_item_update_request.py index 5322178..9899712 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/line_item_update_req.py +++ b/src/ucp_sdk/models/schemas/shopping/types/line_item_update_request.py @@ -19,17 +19,19 @@ from __future__ import annotations from pydantic import BaseModel, ConfigDict, Field -from . import item_update_req + +from . import item_update_request class LineItemUpdateRequest(BaseModel): - """Line item object. Expected to use the currency of the parent object.""" + """Line item object. Expected to use the currency of the parent object. + """ model_config = ConfigDict( extra="allow", ) id: str | None = None - item: item_update_req.ItemUpdateRequest + item: item_update_request.ItemUpdateRequest quantity: int = Field(..., ge=1) """ Quantity of the item being purchased. diff --git a/src/ucp_sdk/models/schemas/shopping/types/merchant_fulfillment_config.py b/src/ucp_sdk/models/schemas/shopping/types/merchant_fulfillment_config.py index 29456f5..87a6928 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/merchant_fulfillment_config.py +++ b/src/ucp_sdk/models/schemas/shopping/types/merchant_fulfillment_config.py @@ -18,12 +18,14 @@ from __future__ import annotations -from pydantic import BaseModel, ConfigDict from typing import Literal +from pydantic import BaseModel, ConfigDict + class AllowsMultiDestination(BaseModel): - """Permits multiple destinations per method type.""" + """Permits multiple destinations per method type. + """ model_config = ConfigDict( extra="allow", @@ -39,7 +41,8 @@ class AllowsMultiDestination(BaseModel): class MerchantFulfillmentConfig(BaseModel): - """Merchant's fulfillment configuration.""" + """Merchant's fulfillment configuration. + """ model_config = ConfigDict( extra="allow", diff --git a/src/ucp_sdk/models/schemas/shopping/types/message.py b/src/ucp_sdk/models/schemas/shopping/types/message.py index 452fdb7..28c8dbd 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/message.py +++ b/src/ucp_sdk/models/schemas/shopping/types/message.py @@ -19,6 +19,7 @@ from __future__ import annotations from pydantic import Field, RootModel + from . import message_error, message_info, message_warning diff --git a/src/ucp_sdk/models/schemas/shopping/types/message_error.py b/src/ucp_sdk/models/schemas/shopping/types/message_error.py index 2a1dffd..3a1a2a9 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/message_error.py +++ b/src/ucp_sdk/models/schemas/shopping/types/message_error.py @@ -19,6 +19,7 @@ from __future__ import annotations from typing import Literal + from pydantic import BaseModel, ConfigDict diff --git a/src/ucp_sdk/models/schemas/shopping/types/message_info.py b/src/ucp_sdk/models/schemas/shopping/types/message_info.py index 69f70f8..7528d5b 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/message_info.py +++ b/src/ucp_sdk/models/schemas/shopping/types/message_info.py @@ -19,6 +19,7 @@ from __future__ import annotations from typing import Literal + from pydantic import BaseModel, ConfigDict diff --git a/src/ucp_sdk/models/schemas/shopping/types/message_warning.py b/src/ucp_sdk/models/schemas/shopping/types/message_warning.py index 564f391..6b055c9 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/message_warning.py +++ b/src/ucp_sdk/models/schemas/shopping/types/message_warning.py @@ -19,6 +19,7 @@ from __future__ import annotations from typing import Literal + from pydantic import BaseModel, ConfigDict diff --git a/src/ucp_sdk/models/schemas/shopping/types/order_confirmation.py b/src/ucp_sdk/models/schemas/shopping/types/order_confirmation.py index 2ddb26f..17772d2 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/order_confirmation.py +++ b/src/ucp_sdk/models/schemas/shopping/types/order_confirmation.py @@ -22,7 +22,8 @@ class OrderConfirmation(BaseModel): - """Order details available at the time of checkout completion.""" + """Order details available at the time of checkout completion. + """ model_config = ConfigDict( extra="allow", 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 841b19c..06baa80 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 @@ -18,13 +18,17 @@ from __future__ import annotations -from pydantic import BaseModel, ConfigDict, Field from typing import Literal -from . import item_resp, total_resp + +from pydantic import BaseModel, ConfigDict, Field + +from . import item as item_1 +from . import total as total_1 class Quantity(BaseModel): - """Quantity tracking. Both total and fulfilled are derived from events.""" + """Quantity tracking. Both total and fulfilled are derived from events. + """ model_config = ConfigDict( extra="allow", @@ -47,7 +51,7 @@ class OrderLineItem(BaseModel): """ Line item identifier. """ - item: item_resp.ItemResponse + item: item_1.Item """ Product data (id, title, price, image_url). """ @@ -55,7 +59,7 @@ class OrderLineItem(BaseModel): """ Quantity tracking. Both total and fulfilled are derived from events. """ - totals: list[total_resp.TotalResponse] + totals: list[total_1.Total] """ Line item totals breakdown. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/payment_credential.py b/src/ucp_sdk/models/schemas/shopping/types/payment_credential.py index 1e5b2c4..31ec712 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/payment_credential.py +++ b/src/ucp_sdk/models/schemas/shopping/types/payment_credential.py @@ -18,20 +18,17 @@ from __future__ import annotations -from pydantic import Field, RootModel -from . import card_credential, token_credential_resp +from pydantic import BaseModel, ConfigDict -class PaymentCredential( - RootModel[ - token_credential_resp.TokenCredentialResponse - | card_credential.CardCredential - ] -): - root: ( - token_credential_resp.TokenCredentialResponse - | card_credential.CardCredential - ) = Field(..., title="Payment Credential") +class PaymentCredential(BaseModel): + """The base definition for any payment credential. Handlers define specific credential types. """ - Container for sensitive payment data. Use the specific schema matching the 'type' field. + + model_config = ConfigDict( + extra="allow", + ) + type: str + """ + The credential type discriminator. Specific schemas will constrain this to a constant value. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/payment_handler_resp.py b/src/ucp_sdk/models/schemas/shopping/types/payment_handler_resp.py deleted file mode 100644 index c254191..0000000 --- a/src/ucp_sdk/models/schemas/shopping/types/payment_handler_resp.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 AnyUrl, BaseModel, ConfigDict -from typing import Any -from ...._internal import Version - - -class PaymentHandlerResponse(BaseModel): - model_config = ConfigDict( - extra="allow", - ) - id: str - """ - The unique identifier for this handler instance within the payment.handlers. Used by payment instruments to reference which handler produced them. - """ - name: str - """ - The specification name using reverse-DNS format. For example, dev.ucp.delegate_payment. - """ - version: Version - """ - Handler version in YYYY-MM-DD format. - """ - spec: AnyUrl - """ - A URI pointing to the technical specification or schema that defines how this handler operates. - """ - config_schema: AnyUrl - """ - A URI pointing to a JSON Schema used to validate the structure of the config object. - """ - instrument_schemas: list[AnyUrl] - config: dict[str, Any] - """ - A dictionary containing provider-specific configuration details, such as merchant IDs, supported networks, or gateway credentials. - """ 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 c61230f..9baa241 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/payment_identity.py +++ b/src/ucp_sdk/models/schemas/shopping/types/payment_identity.py @@ -22,7 +22,8 @@ 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 who tokens should be bound to. + """ model_config = ConfigDict( extra="allow", 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 449580f..8c06b17 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/payment_instrument.py +++ b/src/ucp_sdk/models/schemas/shopping/types/payment_instrument.py @@ -18,16 +18,51 @@ from __future__ import annotations -from pydantic import Field, RootModel -from . import card_payment_instrument +from typing import Any +from pydantic import BaseModel, ConfigDict -class PaymentInstrument( - RootModel[card_payment_instrument.CardPaymentInstrument] -): - root: card_payment_instrument.CardPaymentInstrument = Field( - ..., title="Payment Instrument" +from . import payment_credential, postal_address + + +class PaymentInstrument(BaseModel): + """The base definition for any payment instrument. It links the instrument to a specific payment handler. + """ + + model_config = ConfigDict( + extra="allow", + ) + id: str + """ + A unique identifier for this instrument instance, assigned by the platform. + """ + handler_id: str + """ + The unique identifier for the handler instance that produced this instrument. This corresponds to the 'id' field in the Payment Handler definition. + """ + type: str + """ + The broad category of the instrument (e.g., 'card', 'tokenized_card'). Specific schemas will constrain this to a constant value. + """ + billing_address: postal_address.PostalAddress | None = None + """ + The billing address associated with this payment method. + """ + credential: payment_credential.PaymentCredential | None = None + display: dict[str, Any] | None = None + """ + Display information for this payment instrument. Each payment instrument schema defines its specific display properties, as outlined by the payment handler. + """ + + +class SelectedPaymentInstrument(PaymentInstrument): + """A payment instrument with selection state. + """ + + model_config = ConfigDict( + extra="allow", ) + selected: bool | None = None """ - Matches a specific instrument type based on validation logic. + Whether this instrument is selected by the user. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/payment_instrument_base.py b/src/ucp_sdk/models/schemas/shopping/types/payment_instrument_base.py deleted file mode 100644 index 1bb01da..0000000 --- a/src/ucp_sdk/models/schemas/shopping/types/payment_instrument_base.py +++ /dev/null @@ -1,47 +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 -from . import payment_credential, postal_address - - -class PaymentInstrumentBase(BaseModel): - """The base definition for any payment instrument. It links the instrument to a specific Merchant configuration (handler_id) and defines common fields like billing address.""" - - model_config = ConfigDict( - extra="allow", - ) - id: str - """ - A unique identifier for this instrument instance, assigned by the Agent. Used to reference this specific instrument in the 'payment.selected_instrument_id' field. - """ - handler_id: str - """ - The unique identifier for the handler instance that produced this instrument. This corresponds to the 'id' field in the Payment Handler definition. - """ - type: str - """ - The broad category of the instrument (e.g., 'card', 'tokenized_card'). Specific schemas will constrain this to a constant value. - """ - billing_address: postal_address.PostalAddress | None = None - """ - The billing address associated with this payment method. - """ - credential: payment_credential.PaymentCredential | None = None diff --git a/src/ucp_sdk/models/schemas/shopping/types/platform_fulfillment_config.py b/src/ucp_sdk/models/schemas/shopping/types/platform_fulfillment_config.py index f3ce34a..74dc8da 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/platform_fulfillment_config.py +++ b/src/ucp_sdk/models/schemas/shopping/types/platform_fulfillment_config.py @@ -22,7 +22,8 @@ class PlatformFulfillmentConfig(BaseModel): - """Platform's fulfillment configuration.""" + """Platform's fulfillment configuration. + """ model_config = ConfigDict( extra="allow", diff --git a/src/ucp_sdk/models/schemas/shopping/types/postal_address.py b/src/ucp_sdk/models/schemas/shopping/types/postal_address.py index 309dfdd..3df5114 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/postal_address.py +++ b/src/ucp_sdk/models/schemas/shopping/types/postal_address.py @@ -57,10 +57,6 @@ class PostalAddress(BaseModel): """ Optional. Last name of the contact associated with the address. """ - full_name: str | None = None - """ - Optional. Full name of the contact associated with the address (if first_name or last_name fields are present they take precedence). - """ phone_number: str | None = None """ Optional. Phone number of the contact associated with the address. diff --git a/src/ucp_sdk/models/schemas/shopping/types/postal_address_create_request.py b/src/ucp_sdk/models/schemas/shopping/types/postal_address_create_request.py new file mode 100644 index 0000000..cbeb315 --- /dev/null +++ b/src/ucp_sdk/models/schemas/shopping/types/postal_address_create_request.py @@ -0,0 +1,63 @@ +# 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 PostalAddressCreateRequest(BaseModel): + model_config = ConfigDict( + extra="allow", + ) + extended_address: str | None = None + """ + An address extension such as an apartment number, C/O or alternative name. + """ + street_address: str | None = None + """ + The street address. + """ + address_locality: str | None = None + """ + The locality in which the street address is, and which is in the region. For example, Mountain View. + """ + address_region: str | None = None + """ + The region in which the locality is, and which is in the country. Required for applicable countries (i.e. state in US, province in CA). For example, California or another appropriate first-level Administrative division. + """ + 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. + """ + postal_code: str | None = None + """ + The postal code. For example, 94043. + """ + first_name: str | None = None + """ + Optional. First name of the contact associated with the address. + """ + last_name: str | None = None + """ + Optional. Last name of the contact associated with the address. + """ + phone_number: str | None = None + """ + Optional. Phone number of the contact associated with the address. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/postal_address_update_request.py b/src/ucp_sdk/models/schemas/shopping/types/postal_address_update_request.py new file mode 100644 index 0000000..e3442ba --- /dev/null +++ b/src/ucp_sdk/models/schemas/shopping/types/postal_address_update_request.py @@ -0,0 +1,63 @@ +# 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 PostalAddressUpdateRequest(BaseModel): + model_config = ConfigDict( + extra="allow", + ) + extended_address: str | None = None + """ + An address extension such as an apartment number, C/O or alternative name. + """ + street_address: str | None = None + """ + The street address. + """ + address_locality: str | None = None + """ + The locality in which the street address is, and which is in the region. For example, Mountain View. + """ + address_region: str | None = None + """ + The region in which the locality is, and which is in the country. Required for applicable countries (i.e. state in US, province in CA). For example, California or another appropriate first-level Administrative division. + """ + 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. + """ + postal_code: str | None = None + """ + The postal code. For example, 94043. + """ + first_name: str | None = None + """ + Optional. First name of the contact associated with the address. + """ + last_name: str | None = None + """ + Optional. Last name of the contact associated with the address. + """ + phone_number: str | None = None + """ + Optional. Phone number of the contact associated with the address. + """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/retail_location_resp.py b/src/ucp_sdk/models/schemas/shopping/types/retail_location.py similarity index 91% rename from src/ucp_sdk/models/schemas/shopping/types/retail_location_resp.py rename to src/ucp_sdk/models/schemas/shopping/types/retail_location.py index 951fe59..a7f9cf7 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/retail_location_resp.py +++ b/src/ucp_sdk/models/schemas/shopping/types/retail_location.py @@ -19,11 +19,13 @@ from __future__ import annotations from pydantic import BaseModel, ConfigDict + from . import postal_address -class RetailLocationResponse(BaseModel): - """A pickup location (retail store, locker, etc.).""" +class RetailLocation(BaseModel): + """A pickup location (retail store, locker, etc.). + """ model_config = ConfigDict( extra="allow", diff --git a/src/ucp_sdk/models/schemas/shopping/types/retail_location_req.py b/src/ucp_sdk/models/schemas/shopping/types/retail_location_create_request.py similarity index 78% rename from src/ucp_sdk/models/schemas/shopping/types/retail_location_req.py rename to src/ucp_sdk/models/schemas/shopping/types/retail_location_create_request.py index 6b1a8e2..87bb6af 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/retail_location_req.py +++ b/src/ucp_sdk/models/schemas/shopping/types/retail_location_create_request.py @@ -19,11 +19,13 @@ from __future__ import annotations from pydantic import BaseModel, ConfigDict -from . import postal_address +from . import postal_address_create_request -class RetailLocationRequest(BaseModel): - """A pickup location (retail store, locker, etc.).""" + +class RetailLocationCreateRequest(BaseModel): + """A pickup location (retail store, locker, etc.). + """ model_config = ConfigDict( extra="allow", @@ -32,7 +34,9 @@ class RetailLocationRequest(BaseModel): """ Location name (e.g., store name). """ - address: postal_address.PostalAddress | None = None + address: postal_address_create_request.PostalAddressCreateRequest | None = ( + None + ) """ Physical address of the location. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/token_credential_create_req.py b/src/ucp_sdk/models/schemas/shopping/types/retail_location_update_request.py similarity index 71% rename from src/ucp_sdk/models/schemas/shopping/types/token_credential_create_req.py rename to src/ucp_sdk/models/schemas/shopping/types/retail_location_update_request.py index ed52d78..602b3a8 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/token_credential_create_req.py +++ b/src/ucp_sdk/models/schemas/shopping/types/retail_location_update_request.py @@ -20,18 +20,23 @@ from pydantic import BaseModel, ConfigDict +from . import postal_address_update_request -class TokenCredentialCreateRequest(BaseModel): - """Base token credential schema. Concrete payment handlers may extend this schema with additional fields and define their own constraints.""" + +class RetailLocationUpdateRequest(BaseModel): + """A pickup location (retail store, locker, etc.). + """ model_config = ConfigDict( extra="allow", ) - type: str + name: str """ - The specific type of token produced by the handler (e.g., 'stripe_token'). + Location name (e.g., store name). """ - token: str + address: postal_address_update_request.PostalAddressUpdateRequest | None = ( + None + ) """ - The token value. + Physical address of the location. """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/shipping_destination_resp.py b/src/ucp_sdk/models/schemas/shopping/types/shipping_destination.py similarity index 91% rename from src/ucp_sdk/models/schemas/shopping/types/shipping_destination_resp.py rename to src/ucp_sdk/models/schemas/shopping/types/shipping_destination.py index 6ba62ae..f3ef9eb 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/shipping_destination_resp.py +++ b/src/ucp_sdk/models/schemas/shopping/types/shipping_destination.py @@ -19,11 +19,13 @@ from __future__ import annotations from pydantic import ConfigDict + from .postal_address import PostalAddress -class ShippingDestinationResponse(PostalAddress): - """Shipping destination.""" +class ShippingDestination(PostalAddress): + """Shipping destination. + """ model_config = ConfigDict( extra="allow", diff --git a/src/ucp_sdk/models/schemas/shopping/types/shipping_destination_req.py b/src/ucp_sdk/models/schemas/shopping/types/shipping_destination_req.py deleted file mode 100644 index 1bba351..0000000 --- a/src/ucp_sdk/models/schemas/shopping/types/shipping_destination_req.py +++ /dev/null @@ -1,34 +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 .postal_address import PostalAddress - - -class ShippingDestinationRequest(PostalAddress): - """Shipping destination.""" - - model_config = ConfigDict( - extra="allow", - ) - id: str | None = None - """ - ID specific to this shipping destination. - """ diff --git a/src/ucp_sdk/models/schemas/shopping/types/token_credential_update_req.py b/src/ucp_sdk/models/schemas/shopping/types/token_credential.py similarity index 87% rename from src/ucp_sdk/models/schemas/shopping/types/token_credential_update_req.py rename to src/ucp_sdk/models/schemas/shopping/types/token_credential.py index ff044f8..8d51dd5 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/token_credential_update_req.py +++ b/src/ucp_sdk/models/schemas/shopping/types/token_credential.py @@ -18,11 +18,14 @@ from __future__ import annotations -from pydantic import BaseModel, ConfigDict +from pydantic import ConfigDict +from .payment_credential import PaymentCredential -class TokenCredentialUpdateRequest(BaseModel): - """Base token credential schema. Concrete payment handlers may extend this schema with additional fields and define their own constraints.""" + +class TokenCredential(PaymentCredential): + """Base token credential schema. Concrete payment handlers may extend this schema with additional fields and define their own constraints. + """ model_config = ConfigDict( extra="allow", diff --git a/src/ucp_sdk/models/schemas/shopping/types/total_resp.py b/src/ucp_sdk/models/schemas/shopping/types/total.py similarity index 97% rename from src/ucp_sdk/models/schemas/shopping/types/total_resp.py rename to src/ucp_sdk/models/schemas/shopping/types/total.py index 8323cfb..1574a17 100644 --- a/src/ucp_sdk/models/schemas/shopping/types/total_resp.py +++ b/src/ucp_sdk/models/schemas/shopping/types/total.py @@ -19,10 +19,11 @@ from __future__ import annotations from typing import Literal + from pydantic import BaseModel, ConfigDict, Field -class TotalResponse(BaseModel): +class Total(BaseModel): model_config = ConfigDict( extra="allow", ) diff --git a/src/ucp_sdk/models/schemas/shopping/types/total_create_req.py b/src/ucp_sdk/models/schemas/shopping/types/total_create_request.py similarity index 100% rename from src/ucp_sdk/models/schemas/shopping/types/total_create_req.py rename to src/ucp_sdk/models/schemas/shopping/types/total_create_request.py diff --git a/src/ucp_sdk/models/schemas/shopping/types/total_update_req.py b/src/ucp_sdk/models/schemas/shopping/types/total_update_request.py similarity index 100% rename from src/ucp_sdk/models/schemas/shopping/types/total_update_req.py rename to src/ucp_sdk/models/schemas/shopping/types/total_update_request.py diff --git a/src/ucp_sdk/models/schemas/transports/__init__.py b/src/ucp_sdk/models/schemas/transports/__init__.py new file mode 100644 index 0000000..421dc21 --- /dev/null +++ b/src/ucp_sdk/models/schemas/transports/__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/transports/embedded_config.py b/src/ucp_sdk/models/schemas/transports/embedded_config.py new file mode 100644 index 0000000..1e5b298 --- /dev/null +++ b/src/ucp_sdk/models/schemas/transports/embedded_config.py @@ -0,0 +1,34 @@ +# 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 EmbeddedTransportConfig(BaseModel): + """Per-checkout configuration for embedded transport binding. Allows businesses to vary ECP availability and delegations based on cart contents, agent authorization, or policy. + """ + + model_config = ConfigDict( + extra="allow", + ) + delegate: list[str] | None = None + """ + Delegations the business allows. At service-level, declares available delegations. In checkout responses, confirms accepted delegations for this session. + """ diff --git a/src/ucp_sdk/models/schemas/ucp.py b/src/ucp_sdk/models/schemas/ucp.py index d64119d..6d1be0c 100644 --- a/src/ucp_sdk/models/schemas/ucp.py +++ b/src/ucp_sdk/models/schemas/ucp.py @@ -18,20 +18,26 @@ from __future__ import annotations -from .._internal import ( - DiscoveryProfile, - ResponseCheckout, - ResponseOrder, - Services, +from ._internal import Base_3 as Base +from ._internal import BusinessSchema_3 as BusinessSchema +from ._internal import Entity +from ._internal import PlatformSchema_3 as PlatformSchema +from ._internal import ( + ResponseCheckoutSchema, + ResponseOrderSchema, + ReverseDomainName, UcpMetadata, Version, ) __all__ = [ - "DiscoveryProfile", - "ResponseCheckout", - "ResponseOrder", - "Services", + "Base", + "BusinessSchema", + "Entity", + "PlatformSchema", + "ResponseCheckoutSchema", + "ResponseOrderSchema", + "ReverseDomainName", "UcpMetadata", "Version", ] diff --git a/src/ucp_sdk/models/services/__init__.py b/src/ucp_sdk/models/services/__init__.py index 1252d6b..421dc21 100644 --- a/src/ucp_sdk/models/services/__init__.py +++ b/src/ucp_sdk/models/services/__init__.py @@ -15,3 +15,4 @@ # generated by datamodel-codegen # pylint: disable=all # pyformat: disable + diff --git a/src/ucp_sdk/models/services/shopping/__init__.py b/src/ucp_sdk/models/services/shopping/__init__.py index 1252d6b..421dc21 100644 --- a/src/ucp_sdk/models/services/shopping/__init__.py +++ b/src/ucp_sdk/models/services/shopping/__init__.py @@ -15,3 +15,4 @@ # generated by datamodel-codegen # pylint: disable=all # pyformat: disable + diff --git a/src/ucp_sdk/models/services/shopping/embedded.py b/src/ucp_sdk/models/services/shopping/embedded.py new file mode 100644 index 0000000..cc5f288 --- /dev/null +++ b/src/ucp_sdk/models/services/shopping/embedded.py @@ -0,0 +1,30 @@ +# 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 Field, RootModel + + +class EmbeddedProtocol(RootModel[Any]): + root: Any = Field(..., title="Embedded Protocol") + """ + Embedded Protocol (EP) methods for UCP capabilities. Methods are sent from Merchant to Host via postMessage/JSON-RPC 2.0. Method prefixes indicate capability scope: ec.* (checkout). Future capabilities may define additional prefixes (e.g., eo.* for order). + """ diff --git a/src/ucp_sdk/models/services/shopping/mcp_openrpc.py b/src/ucp_sdk/models/services/shopping/openapi.py similarity index 99% rename from src/ucp_sdk/models/services/shopping/mcp_openrpc.py rename to src/ucp_sdk/models/services/shopping/openapi.py index e8b3b8c..0f53946 100644 --- a/src/ucp_sdk/models/services/shopping/mcp_openrpc.py +++ b/src/ucp_sdk/models/services/shopping/openapi.py @@ -19,6 +19,7 @@ from __future__ import annotations from typing import Any + from pydantic import RootModel diff --git a/src/ucp_sdk/models/services/shopping/rest_openapi.py b/src/ucp_sdk/models/services/shopping/openrpc.py similarity index 99% rename from src/ucp_sdk/models/services/shopping/rest_openapi.py rename to src/ucp_sdk/models/services/shopping/openrpc.py index e8b3b8c..0f53946 100644 --- a/src/ucp_sdk/models/services/shopping/rest_openapi.py +++ b/src/ucp_sdk/models/services/shopping/openrpc.py @@ -19,6 +19,7 @@ from __future__ import annotations from typing import Any + from pydantic import RootModel diff --git a/src/ucp_sdk/py.typed b/src/ucp_sdk/py.typed deleted file mode 100644 index e69de29..0000000