AP2 Human-Present: CartMandate ↔ PaymentMandate Binding and Verification Gap
Description
Hi team, we find a binding and verification gap between CartMandate and PaymentMandate in the AP2 human-present flow.
In the current design, the merchant commits to the cart, the Shopping Agent generates the PaymentMandate, the user approves the {cart, payment} pair, and the main payment execution path primarily consumes the PaymentMandate. If the {cart, payment} pair is already inconsistent at the time of final confirmation (for example, the amount differs) and the user does not notice, the sample payment path can continue based on the PaymentMandate, because the current public spec and sample do not clearly require an executing party to fetch the referenced cart, compare the relevant fields, and reject on mismatch.1234
For example, the merchant-authorized cart says “red jacket, size M, total USD 120,” but a buggy or compromised Shopping-Agent-side component constructs a PaymentMandate whose payment_details_total is USD 160. If the user misses that discrepancy on the trusted surface, the current sample path can still proceed.
The current system lacks a rule-enforced cart↔payment consistency gate. A more robust system should not rely only on the user visually spotting discrepancies on the trusted surface. Instead, before releasing tokens, initiating payment, and generating a receipt, the executing parties should automatically verify that the current PaymentMandate is a valid payment projection of the merchant-authorized cart. The public specification says that PaymentMandate is “bound to Cart/Intent mandate” and that the “payment subset of the Cart Mandate must be conveyed,” but it does not define sufficiently clear rules for field consistency, interoperability, verifiability, and reject-on-mismatch behavior.
At the code level, even if the placeholder comments (for example, hashes and signatures) were implemented, the current object model and workflow would still be insufficient to provide strong binding, strong verification, and a complete consent / audit / dispute closure. 156 A payment could still be executed for an amount that is inconsistent with the cart.
As a result, in the human-present flow, there is no strong consistency verification chain jointly enforced by both the specification and the code across the merchant-authorized cart, the user-confirmed cart/payment pair, and the executed payment. 15
Design Intent Already Expressed by the Protocol
Our understanding: AP2 is not trying to make the cart and the payment two unrelated objects. Instead, it treats them as two views of the same checkout transaction. 1
- The
Cart Mandate is the merchant-side transaction object used for fulfillment; the specification requires the merchant to commit to the cart and, in the human-present flow, to have the user confirm it. 1
- The
PaymentMandate is generated by the Shopping Agent and is described as “bound to Cart/Intent mandate but containing separate information”. Its purpose is to provide additional visibility into the agentic transaction to the payments ecosystem. 1
- In the human-present flow, the trusted device surface presents
CartMandate + PaymentMandate to the user, after which the user confirms and an attestation is created. 1
Protocol-Level Gaps
1. The specification says they are “bound,” but does not define what exactly is bound
The specification states that PaymentMandate is "bound to the Cart/Intent mandate", and it also says that the “payment subset of the Cart Mandate must be conveyed.” However, it does not turn the following into sufficiently clear normative rules: 1
- what the minimum field set of the
payment subset is;
- which fields between
CartMandate and PaymentMandate must match;
- which differences are allowed and which differences must trigger renewed confirmation;
- who must reject the transaction when an inconsistency is found.
2. The protocol does not normatively require strong binding validation
The public specification does not clearly state that the Credential Provider, Merchant, and Merchant Payment Processor must recompute and verify the cart↔payment binding before credential release or payment execution, and that any mismatch must be rejected. 1
This weakens the certainty with which the protocol’s goals can be achieved.
AP2 aims to support trust, audit trail, and dispute handling through a cryptographic chain of evidence. However, without clearly defined binding fields, verifier responsibilities, and reject rules, those goals depend more on individual implementations than on guarantees provided by the protocol itself. 1
Code-Level Gaps
1. PaymentMandateContents lacks an explicit cart reference
In the current data model, PaymentMandateContents includes payment_mandate_id, payment_details_id, payment_details_total, payment_response, merchant_agent, and timestamp, but it does not include explicit cart_mandate_id / cart_mandate_hash fields. Although the description of user_authorization says that it signs the hashes of CartMandate and PaymentMandateContents, the binding is primarily embedded in authorization semantics rather than exposed as a first-class field. 5
2. PaymentMandateContents still does not expose the cart reference explicitly
The currently exposed fields of PaymentMandateContents are only:
payment_mandate_id
payment_details_id
payment_details_total
payment_response
merchant_agent
timestamp
There is no explicit cart_mandate_id / cart_mandate_hash field. 5
This means that even if the signature semantics in user_authorization are intended to cover the hashes of CartMandate and PaymentMandateContents, the cart↔payment relationship still remains mostly hidden inside the internal authorization semantics, rather than being surfaced as an explicit, stable, interoperable field-level interface. 5
3. Performing only “signature verification” does not imply “strong binding”
validate_payment_mandate_signature(payment_mandate) currently accepts only a payment_mandate. Even if the commented “full validation logic” were implemented, this function could at most:
- verify that
user_authorization is cryptographically valid;
- verify that it covers some
PaymentMandateContents hash;
- if the authorization encodes a cart hash, verify that it covers some cart hash. 65
However, because the function signature does not include an explicit cart input, the data model does not expose an explicit cart reference, and the protocol still does not clearly define the equality set, this still would not be enough to:
- verify that the executing path has retrieved the exact merchant-authorized cart;
- verify that the cart and payment satisfy a clearly defined set of protocol-level equality rules;
- verify that the downstream payment object being executed is the same one the user saw at confirmation time. 561
4. The human-present sample workflow lacks a consistency gate
In the human-present sample workflow:
- the Shopping Agent creates and passes along the
PaymentMandate; 7
- the Merchant continues forwarding the
PaymentMandate; 2
- the MPP continues processing payment based on the payment data inside the
PaymentMandate; 4
- on the CP side, the token is primarily bound to
payment_mandate_id. 3
Even if signature verification were added to these steps, without an additional rule requiring them to retrieve the same cart, recompute according to the same field set, compare, and reject on mismatch before execution, the workflow could still remain at the level of “a signed pair of objects” rather than “a strongly enforced guarantee that this pair of objects is fully consistent with what is ultimately executed.” 7243
Impact of the code-level gaps
Therefore, the code-level gaps mean:
- the cart↔payment binding is not exposed as an explicit object relationship;
- this binding is not elevated into a mandatory gate enforced by all executing parties;
- the
user-confirmed pair, the merchant-committed cart, and the final executed payment are not forcibly closed into one verification chain within the workflow. 51
This weakens consent integrity, audit trail quality, and dispute handling, because in a dispute there may be multiple signed objects, but not necessarily one protocol-defined, consistently enforced comparison path across them. 1
Recommendations
1. Protocol recommendations
The protocol revisions should focus on object relationships and verifier obligations:
-
In §4.1.3 Payment Mandate, explicitly require:
PaymentMandateContents MUST include cart_mandate_id and cart_mandate_hash;
- the object over which
cart_mandate_hash is computed, and the canonicalization method;
- the minimum field set of the
payment subset;
- the equality set for cart↔payment consistency. 1
-
In §5.1 Human Present / Payment Execution, explicitly require:
- the Credential Provider, Merchant, and Merchant Payment Processor MUST verify the
CartMandate referenced by the PaymentMandate before credential release or payment execution;
- any mismatch MUST be rejected;
- any change to a chargeable field MUST trigger a new cart and fresh user confirmation. 1
Suggested normative text:
For Human-Present transactions, a PaymentMandate MUST reference exactly one merchant-authorized CartMandate approved by the user. PaymentMandateContents MUST include cart_mandate_id and cart_mandate_hash. Credential Provider, Merchant, and Merchant Payment Processor MUST retrieve, recompute, and verify the referenced CartMandate and the PaymentMandateContents before credential release or payment execution. Any mismatch MUST cause the transaction to be rejected.
2. Code recommendations
Code improvements should focus on the object model and workflow gates:
- Add
cart_mandate_id / cart_mandate_hash to PaymentMandateContents; 5
- Make validation logic explicitly receive or retrieve the corresponding
CartMandate, rather than only receiving payment_mandate; 65
- Add mandatory verification gates in the CP / Merchant / MPP execution paths;
- Make receipt generation, credential release, and payment execution depend on a successful cart↔payment consistency check, rather than depending only on
payment_mandate_id or the mere presence of authorization. 324
Summary
Our view is that both the protocol and the code comments already express an intent to bind cart and payment. However, even if the commented logic were implemented, the current object model and workflow still would not automatically produce protocol-grade strong binding, strong verification, and a complete consent / audit / dispute closure.
We therefore recommend formally defining the cart↔payment object relationship, field consistency requirements, verifier obligations, and reject-on-mismatch rules in the protocol, and enforcing them in the workflow. 15
Please let us know how you think about it. Thank you for the work on AP2.
References
AP2 Human-Present: CartMandate ↔ PaymentMandate Binding and Verification Gap
Description
Hi team, we find a binding and verification gap between
CartMandateandPaymentMandatein the AP2 human-present flow.In the current design, the merchant commits to the cart, the Shopping Agent generates the
PaymentMandate, the user approves the{cart, payment}pair, and the main payment execution path primarily consumes thePaymentMandate. If the{cart, payment}pair is already inconsistent at the time of final confirmation (for example, the amount differs) and the user does not notice, the sample payment path can continue based on thePaymentMandate, because the current public spec and sample do not clearly require an executing party to fetch the referenced cart, compare the relevant fields, and reject on mismatch.1234For example, the merchant-authorized cart says “red jacket, size M, total USD 120,” but a buggy or compromised Shopping-Agent-side component constructs a PaymentMandate whose payment_details_total is USD 160. If the user misses that discrepancy on the trusted surface, the current sample path can still proceed.
The current system lacks a rule-enforced cart↔payment consistency gate. A more robust system should not rely only on the user visually spotting discrepancies on the trusted surface. Instead, before releasing tokens, initiating payment, and generating a receipt, the executing parties should automatically verify that the current
PaymentMandateis a valid payment projection of the merchant-authorized cart. The public specification says thatPaymentMandateis “bound to Cart/Intent mandate” and that the “payment subset of the Cart Mandate must be conveyed,” but it does not define sufficiently clear rules for field consistency, interoperability, verifiability, and reject-on-mismatch behavior.At the code level, even if the placeholder comments (for example, hashes and signatures) were implemented, the current object model and workflow would still be insufficient to provide strong binding, strong verification, and a complete consent / audit / dispute closure. 156 A payment could still be executed for an amount that is inconsistent with the cart.
As a result, in the human-present flow, there is no strong consistency verification chain jointly enforced by both the specification and the code across the
merchant-authorized cart, theuser-confirmed cart/payment pair, and theexecuted payment. 15Design Intent Already Expressed by the Protocol
Our understanding: AP2 is not trying to make the cart and the payment two unrelated objects. Instead, it treats them as two views of the same checkout transaction. 1
Cart Mandateis the merchant-side transaction object used for fulfillment; the specification requires the merchant to commit to the cart and, in the human-present flow, to have the user confirm it. 1PaymentMandateis generated by the Shopping Agent and is described as “bound to Cart/Intent mandate but containing separate information”. Its purpose is to provide additional visibility into the agentic transaction to the payments ecosystem. 1CartMandate + PaymentMandateto the user, after which the user confirms and an attestation is created. 1Protocol-Level Gaps
1. The specification says they are “bound,” but does not define what exactly is bound
The specification states that
PaymentMandateis "bound to theCart/Intent mandate", and it also says that the “payment subset of the Cart Mandate must be conveyed.” However, it does not turn the following into sufficiently clear normative rules: 1payment subsetis;CartMandateandPaymentMandatemust match;2. The protocol does not normatively require strong binding validation
The public specification does not clearly state that the Credential Provider, Merchant, and Merchant Payment Processor must recompute and verify the cart↔payment binding before credential release or payment execution, and that any mismatch must be rejected. 1
This weakens the certainty with which the protocol’s goals can be achieved.
AP2 aims to support trust, audit trail, and dispute handling through a cryptographic chain of evidence. However, without clearly defined binding fields, verifier responsibilities, and reject rules, those goals depend more on individual implementations than on guarantees provided by the protocol itself. 1
Code-Level Gaps
1.
PaymentMandateContentslacks an explicit cart referenceIn the current data model,
PaymentMandateContentsincludespayment_mandate_id,payment_details_id,payment_details_total,payment_response,merchant_agent, andtimestamp, but it does not include explicitcart_mandate_id/cart_mandate_hashfields. Although the description ofuser_authorizationsays that it signs the hashes ofCartMandateandPaymentMandateContents, the binding is primarily embedded in authorization semantics rather than exposed as a first-class field. 52.
PaymentMandateContentsstill does not expose the cart reference explicitlyThe currently exposed fields of
PaymentMandateContentsare only:payment_mandate_idpayment_details_idpayment_details_totalpayment_responsemerchant_agenttimestampThere is no explicit
cart_mandate_id/cart_mandate_hashfield. 5This means that even if the signature semantics in
user_authorizationare intended to cover the hashes ofCartMandateandPaymentMandateContents, the cart↔payment relationship still remains mostly hidden inside the internal authorization semantics, rather than being surfaced as an explicit, stable, interoperable field-level interface. 53. Performing only “signature verification” does not imply “strong binding”
validate_payment_mandate_signature(payment_mandate)currently accepts only apayment_mandate. Even if the commented “full validation logic” were implemented, this function could at most:user_authorizationis cryptographically valid;PaymentMandateContentshash;However, because the function signature does not include an explicit cart input, the data model does not expose an explicit cart reference, and the protocol still does not clearly define the equality set, this still would not be enough to:
4. The human-present sample workflow lacks a consistency gate
In the human-present sample workflow:
PaymentMandate; 7PaymentMandate; 2PaymentMandate; 4payment_mandate_id. 3Even if signature verification were added to these steps, without an additional rule requiring them to retrieve the same cart, recompute according to the same field set, compare, and reject on mismatch before execution, the workflow could still remain at the level of “a signed pair of objects” rather than “a strongly enforced guarantee that this pair of objects is fully consistent with what is ultimately executed.” 7243
Impact of the code-level gaps
Therefore, the code-level gaps mean:
user-confirmed pair, themerchant-committed cart, and thefinal executed paymentare not forcibly closed into one verification chain within the workflow. 51This weakens consent integrity, audit trail quality, and dispute handling, because in a dispute there may be multiple signed objects, but not necessarily one protocol-defined, consistently enforced comparison path across them. 1
Recommendations
1. Protocol recommendations
The protocol revisions should focus on object relationships and verifier obligations:
In §4.1.3 Payment Mandate, explicitly require:
PaymentMandateContentsMUST includecart_mandate_idandcart_mandate_hash;cart_mandate_hashis computed, and the canonicalization method;payment subset;In §5.1 Human Present / Payment Execution, explicitly require:
CartMandatereferenced by thePaymentMandatebefore credential release or payment execution;Suggested normative text:
2. Code recommendations
Code improvements should focus on the object model and workflow gates:
cart_mandate_id/cart_mandate_hashtoPaymentMandateContents; 5CartMandate, rather than only receivingpayment_mandate; 65payment_mandate_idor the mere presence of authorization. 324Summary
Our view is that both the protocol and the code comments already express an intent to bind cart and payment. However, even if the commented logic were implemented, the current object model and workflow still would not automatically produce protocol-grade strong binding, strong verification, and a complete consent / audit / dispute closure.
We therefore recommend formally defining the cart↔payment object relationship, field consistency requirements, verifier obligations, and reject-on-mismatch rules in the protocol, and enforcing them in the workflow. 15
Please let us know how you think about it. Thank you for the work on AP2.
References
Footnotes
AP2 Specification, https://ap2-protocol.org/specification/ ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12 ↩13 ↩14 ↩15 ↩16
samples/python/src/roles/merchant_agent/tools.py, https://raw.githubusercontent.com/google-agentic-commerce/AP2/main/samples/python/src/roles/merchant_agent/tools.py ↩ ↩2 ↩3 ↩4samples/python/src/roles/credentials_provider_agent/tools.py, https://raw.githubusercontent.com/google-agentic-commerce/AP2/main/samples/python/src/roles/credentials_provider_agent/tools.py ↩ ↩2 ↩3 ↩4samples/python/src/roles/merchant_payment_processor_agent/tools.py, https://raw.githubusercontent.com/google-agentic-commerce/AP2/main/samples/python/src/roles/merchant_payment_processor_agent/tools.py ↩ ↩2 ↩3 ↩4src/ap2/types/mandate.py, https://raw.githubusercontent.com/google-agentic-commerce/AP2/main/src/ap2/types/mandate.py ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11samples/python/src/common/validation.py, https://raw.githubusercontent.com/google-agentic-commerce/AP2/main/samples/python/src/common/validation.py ↩ ↩2 ↩3 ↩4samples/python/src/roles/shopping_agent/tools.py, https://raw.githubusercontent.com/google-agentic-commerce/AP2/main/samples/python/src/roles/shopping_agent/tools.py ↩ ↩2