-
Notifications
You must be signed in to change notification settings - Fork 425
Expand file tree
/
Copy pathmandate.py
More file actions
200 lines (175 loc) · 7.28 KB
/
mandate.py
File metadata and controls
200 lines (175 loc) · 7.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# 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...",
)