# Copyright 2025 Google LLC # # 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 # # https://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. """Contains the definitions of the Agent Payments Protocol mandates.""" from datetime import datetime from datetime import timezone from typing import Optional from ap2.types.payment_request import PaymentItem from ap2.types.payment_request import PaymentRequest from ap2.types.payment_request import PaymentResponse from pydantic import BaseModel from pydantic import Field CART_MANDATE_DATA_KEY = "ap2.mandates.CartMandate" INTENT_MANDATE_DATA_KEY = "ap2.mandates.IntentMandate" PAYMENT_MANDATE_DATA_KEY = "ap2.mandates.PaymentMandate" class IntentMandate(BaseModel): """Represents the user's purchase intent. These are the initial fields utilized in the human-present flow. For human-not-present flows, additional fields will be added to this mandate. """ user_cart_confirmation_required: bool = Field( True, description=( "If false, the agent can make purchases on the user's behalf once all" " purchase conditions have been satisfied. This must be true if the" " intent mandate is not signed by the user." ), ) natural_language_description: str = Field( ..., description=( "The natural language description of the user's intent. This is" " generated by the shopping agent, and confirmed by the user. The" " goal is to have informed consent by the user." ), example="High top, old school, red basketball shoes", ) merchants: Optional[list[str]] = Field( None, description=( "Merchants allowed to fulfill the intent. If not set, the shopping" " agent is able to work with any suitable merchant." ), ) skus: Optional[list[str]] = Field( None, description=( "A list of specific product SKUs. If not set, any SKU is allowed." ), ) requires_refundability: Optional[bool] = Field( False, description="If true, items must be refundable.", ) intent_expiry: str = Field( ..., description="When the intent mandate expires, in ISO 8601 format.", ) class CartContents(BaseModel): """The detailed contents of a cart. This object is signed by the merchant to create a CartMandate. """ id: str = Field(..., description="A unique identifier for this cart.") user_cart_confirmation_required: bool = Field( ..., description=( "If true, the merchant requires the user to confirm the cart before" " the purchase can be completed." ), ) payment_request: PaymentRequest = Field( ..., description=( "The W3C PaymentRequest object to initiate payment. This contains the" " items being purchased, prices, and the set of payment methods" " accepted by the merchant for this cart." ), ) cart_expiry: str = Field( ..., description="When this cart expires, in ISO 8601 format." ) merchant_name: str = Field(..., description="The name of the merchant.") class CartMandate(BaseModel): """A cart whose contents have been digitally signed by the merchant. This serves as a guarantee of the items and price for a limited time. """ contents: CartContents = Field(..., description="The contents of the cart.") merchant_authorization: Optional[str] = Field( None, description=(""" A base64url-encoded JSON Web Token (JWT) that digitally signs the cart contents, guaranteeing its authenticity and integrity: 1. Header includes the signing algorithm and key ID. 2. Payload includes: - iss, sub, aud: Identifiers for the merchant (issuer) and the intended recipient (audience), like a payment processor. - iat: iat, exp: Timestamps for the token's creation and its short-lived expiration (e.g., 5-15 minutes) to enhance security. - jti: Unique identifier for the JWT to prevent replay attacks. - cart_hash: A secure hash of the CartMandate, ensuring integrity. The hash is computed over the canonical JSON representation of the CartContents object. 3. Signature: A digital signature created with the merchant's private key. It allows anyone with the public key to verify the token's authenticity and confirm that the payload has not been tampered with. The entire JWT is base64url encoded to ensure safe transmission. """), example="eyJhbGciOiJSUzI1NiIsImtpZCI6IjIwMjQwOTA...", # Example JWT ) class PaymentMandateContents(BaseModel): """The data contents of a PaymentMandate.""" payment_mandate_id: str = Field( ..., description="A unique identifier for this payment mandate." ) payment_details_id: str = Field( ..., description="A unique identifier for the payment request." ) payment_details_total: PaymentItem = Field( ..., description="The total payment amount." ) payment_response: PaymentResponse = Field( ..., description=( "The payment response containing details of the payment method chosen" " by the user." ), ) merchant_agent: str = Field(..., description="Identifier for the merchant.") timestamp: str = Field( description=( "The date and time the mandate was created, in ISO 8601 format." ), default_factory=lambda: datetime.now(timezone.utc).isoformat(), ) class PaymentMandate(BaseModel): """Contains the user's instructions & authorization for payment. While the Cart and Intent mandates are required by the merchant to fulfill the order, separately the protocol provides additional visibility into the agentic transaction to the payments ecosystem. For this purpose, the PaymentMandate (bound to Cart/Intent mandate but containing separate information) may be shared with the network/issuer along with the standard transaction authorization messages. The goal of the PaymentMandate is to help the network/issuer build trust into the agentic transaction. """ payment_mandate_contents: PaymentMandateContents = Field( ..., description="The data contents of the payment mandate.", ) user_authorization: Optional[str] = Field( None, description=( """ This is a base64_url-encoded verifiable presentation of a verifiable credential signing over the cart_mandate and payment_mandate_hashes. For example an sd-jwt-vc would contain: - An issuer-signed jwt authorizing a 'cnf' claim - A key-binding jwt with the claims "aud": ... "nonce": ... "sd_hash": hash of the issuer-signed jwt "transaction_data": an array containing the secure hashes of CartMandate and PaymentMandateContents. """ ), example="eyJhbGciOiJFUzI1NksiLCJraWQiOiJkaWQ6ZXhhbXBsZ...", )