# Agentic Commerce Protocols - UCP and AP2

Author: [Mete Atamel](https://atamel.dev/) | Published: 2026-11-04 | Topics: GenAI, Agents, UCP, AP2, ADK | Canonical: https://atamel.dev/posts/2026/11-04_agentic_commerce_protocols_ucp_ap2/


![Agent Protocols: MCP, A2A, UCP, AP2, A2UI, AG-UI](https://raw.githubusercontent.com/meteatamel/genai-beyond-basics/main/samples/protocols/images/mcp-a2a-ucp-ap2-a2ui-agui.png)

In my [Agent Protocols - MCP, A2A, A2UI, AG-UI](https://atamel.dev/posts/2026/03-17_agent_protocols_mcp_a2a_a2ui_agui/)
post back in March, I provided a high-level overview of the main agent protocols for tool use (MCP), agent-to-agent
communication (A2A), and agent-to-UI interactions (AG-UI and A2UI).

Recently, I had a chance to explore two newer protocols focused on **agentic commerce** and **payments**: the
[Universal Commerce Protocol (UCP)](https://ucp.dev/) and the [Agent Payments Protocol (AP2)](https://ap2-protocol.org/).
Traditional e-commerce and payment flows assume a human is directly browsing a website and clicking "Buy" on a trusted
checkout screen. When an AI agent shops and pays on your behalf, both the commerce workflow and the cryptographic proof
of user authorization need a standard language.

In this post, I'll share an update on the agent protocol landscape by introducing **UCP** and **AP2**, explaining how
they work together, and walking through the new Python and ADK samples I added to my
[genai-beyond-basics repository](https://github.com/meteatamel/genai-beyond-basics/tree/main/samples/protocols).

## TLDR

With UCP and AP2 added to the mix, here's how the six agent protocols in my repository fit together:

| Protocol | Description |
|:---------|:----------|
| [Model Context Protocol (MCP)](https://github.com/meteatamel/genai-beyond-basics/tree/main/samples/protocols/mcp) | An open protocol, from Anthropic, that standardizes how models and agents access external tools and resources |
| [Agent2Agent Protocol (A2A)](https://github.com/meteatamel/genai-beyond-basics/tree/main/samples/protocols/a2a) | An open protocol, from Google, that standardizes how agents running on diverse frameworks and platforms communicate |
| [Agent-User Interaction Protocol (AG-UI)](https://github.com/meteatamel/genai-beyond-basics/tree/main/samples/protocols/ag-ui) | An open protocol, from CopilotKit, that standardizes how agents communicate with user interfaces |
| [Agent to UI Protocol (A2UI)](https://github.com/meteatamel/genai-beyond-basics/tree/main/samples/protocols/a2ui) | A generative UI protocol, from Google, that enables AI agents to generate rich, interactive user interfaces across web, mobile, and desktop |
| [Universal Commerce Protocol (UCP)](https://github.com/meteatamel/genai-beyond-basics/tree/main/samples/protocols/ucp) | An open standard, co-developed by Google, Shopify, and industry partners, that standardizes merchant discovery, capability negotiation, and checkout sessions for agentic commerce |
| [Agent Payments Protocol (AP2)](https://github.com/meteatamel/genai-beyond-basics/tree/main/samples/protocols/ap2) | An open protocol, from Google, that secures agent-initiated payments using cryptographically signed mandates and verifiable credentials |

Let's look into **UCP** and **AP2** in more detail.

## Universal Commerce Protocol (UCP)

**Universal Commerce Protocol (UCP)** is an open standard, co-developed by Google, Shopify, and industry partners
(including Target, Walmart, Wayfair, Etsy, and Stripe), that defines functional primitives for agentic commerce. It
allows AI agents, consumer platforms, businesses (who remain the Merchant of Record), credential providers, and payment
service providers to interoperate without bespoke one-off integrations.

![UCP Overview](https://raw.githubusercontent.com/meteatamel/genai-beyond-basics/main/samples/protocols/ucp/images/ucp.png)

### Architecture, Discovery, and Capability Negotiation

UCP is structured around four layers:

* **Services**: Domain groupings such as `dev.ucp.shopping`, `dev.ucp.common`, and `dev.ucp.lodging`.
* **Capabilities**: Versioned features ("verbs") within a service, such as `dev.ucp.shopping.checkout`,
  `dev.ucp.shopping.cart`, and `dev.ucp.shopping.catalog.search`.
* **Extensions**: Optional schemas that augment a parent capability via `extends` (e.g., `dev.ucp.shopping.fulfillment`,
  `dev.ucp.shopping.discount`, and `dev.ucp.common.payment.ap2_mandate`).
* **Transports**: Transport-agnostic bindings supporting **REST** (OpenAPI 3.1), **MCP** (OpenRPC), **A2A** (Agent
  Card), and **Embedded** (OpenRPC).

Every UCP merchant publishes an unauthenticated JSON profile at `GET /.well-known/ucp` advertising its protocol version,
capabilities, payment handlers (`com.google.pay`, `dev.shopify.shop_pay`), and JWK signing keys (`ES256` as the mandatory
baseline, plus optional `Ed25519` for Web Bot Auth interop). Permissionless request authentication across HTTP transports
uses **HTTP Message Signatures (RFC 9421)** resolved directly against the public keys in each party's profile. When an
agent calls a merchant, UCP uses a **server-selects** negotiation model:

<img src="https://raw.githubusercontent.com/meteatamel/genai-beyond-basics/main/samples/protocols/ucp/images/ucp-discovery-negotiation.png" alt="UCP Discovery and Capability Negotiation" width="75%" />

The merchant computes the intersection between its declared capabilities and the agent's profile, selects the latest
mutually supported `YYYY-MM-DD` version, and prunes any orphaned extensions whose parent capability isn't active.

Once a checkout session starts, `dev.ucp.shopping.checkout` progresses through six explicit states so an AI agent always
knows whether it can finish the purchase autonomously or must hand off to the user:

* `incomplete`: Missing required details (such as buyer email or shipping method).
* `requires_escalation`: Requires direct buyer input via a `continue_url` handoff (e.g., custom configuration or 3DS challenge).
* `ready_for_complete`: All line items, totals, and fulfillment details are finalized; ready for payment submission.
* `complete_in_progress`: Checkout completion is currently executing (new `PUT` updates are rejected while in progress).
* `completed`: Payment processed and `OrderConfirmation` (`order.id`, `order.permalink_url`) generated.
* `canceled`: Checkout session was canceled (`POST /checkout-sessions/{id}/cancel`) or expired.

<img src="https://raw.githubusercontent.com/meteatamel/genai-beyond-basics/main/samples/protocols/ucp/images/ucp-checkout-flow.png" alt="UCP Checkout and Payment Flow" width="75%" />

> [!note]
> All monetary amounts in UCP (and AP2) are expressed in **minor currency units (cents)** — for example, `2500` for
> `$25.00`, and negative integers like `-400` for a `-$4.00` discount.

### UCP Samples: Python SDK & Google ADK

In my [UCP samples](https://github.com/meteatamel/genai-beyond-basics/tree/main/samples/protocols/ucp) folder, I created
two samples using the official [UCP Python SDK](https://github.com/Universal-Commerce-Protocol/python-sdk) (`ucp-sdk`):

1. **[UCP Hello World (Python SDK & FastAPI)](https://github.com/meteatamel/genai-beyond-basics/tree/main/samples/protocols/ucp/hello-world)**:
   A self-contained FastAPI merchant server ([`server.py`](https://github.com/meteatamel/genai-beyond-basics/blob/main/samples/protocols/ucp/hello-world/server.py))
   and client script ([`client.py`](https://github.com/meteatamel/genai-beyond-basics/blob/main/samples/protocols/ucp/hello-world/client.py))
   that validates payloads against `BusinessSchema` and `Checkout` models from `ucp_sdk`. Because `client.py` mounts
   `server.py` in-process via `httpx.ASGITransport` by default, you can run the entire 4-step UCP lifecycle in a single
   command:

   ```sh
   uv run --with ucp-sdk --with fastapi --with httpx python client.py
   ```

   ```text
   === 1. UCP Discovery (GET /.well-known/ucp) ===
   Protocol Version:  2026-08-25
   Services:          ['dev.ucp.shopping']
   Capabilities:      ['dev.ucp.shopping.checkout', 'dev.ucp.shopping.fulfillment', 'dev.ucp.shopping.discount']
   Payment Handlers:  ['com.google.pay', 'dev.shopify.shop_pay']
   Signing Key (kid): merchant_key_2026

   === 2. Create Checkout Session (POST /checkout-sessions) ===
   Checkout ID:       chk_9c35e04f
   Checkout Status:   incomplete
   Negotiated Caps:   ['dev.ucp.shopping.checkout', 'dev.ucp.shopping.fulfillment', 'dev.ucp.shopping.discount']
     - 1x Red Roses Bouquet (sku_roses): $25.00
     - 1x Ceramic Vase (sku_vase): $15.00

   === 3. Update Checkout: Fulfillment & Discount (PUT /checkout-sessions/chk_9c35e04f) ===
   Checkout Status:   ready_for_complete
   Totals Breakdown:
     - Subtotal                : $40.00
     - 10% Promo (SAVE10)      : -$4.00
     - Shipping (Express Delivery): $5.00
     - Total                   : $41.00

   === 4. Complete Checkout (POST /checkout-sessions/chk_9c35e04f/complete) ===
   Checkout Status:   completed
   Order Created:     Order #ORD_EF9FCC12 (id=ord_ef9fcc12)
   Order Permalink:   https://flowershop.example.com/orders/ord_ef9fcc12
   ```

2. **[UCP Shopping Agent with Google ADK](https://github.com/meteatamel/genai-beyond-basics/tree/main/samples/protocols/ucp/adk)**:
   An interactive [Agent Development Kit (ADK)](https://google.github.io/adk-docs/) agent
   ([`shopping_agent/agent.py`](https://github.com/meteatamel/genai-beyond-basics/blob/main/samples/protocols/ucp/adk/shopping_agent/agent.py))
   equipped with UCP discovery and checkout tools:

   ```python
   root_agent = Agent(
       name="ucp_shopping_agent",
       model="gemini-2.5-flash",
       description="AI Shopping Agent that discovers merchants and completes purchases using the Universal Commerce Protocol (UCP).",
       instruction=...,
       tools=[
           discover_merchant,
           create_checkout_session,
           update_checkout_session,
           complete_checkout_session,
       ],
   )
   ```

   Start `server.py` in one terminal and `adk web` in another, and you can ask the agent what the merchant supports and
   have it negotiate extensions, apply promo codes, and complete an order conversationally.

## Agent Payments Protocol (AP2)

While UCP standardizes the commerce session, a big question remains: *How does a merchant or payment processor know that
an AI agent actually has the user's permission to spend their money — and didn't hallucinate the item or price?*

That's where the **Agent Payments Protocol (AP2)** comes in. Originated by Google, AP2 is an open security and
authorization protocol that replaces "trusting the LLM's text summary" with **Verifiable Digital Credentials (VDCs)** —
specifically tamper-evident **SD-JWTs (Selective Disclosure JWTs)** and **KB-SD-JWT (Key-Binding SD-JWT) delegation
chains**.

![AP2 Overview](https://raw.githubusercontent.com/meteatamel/genai-beyond-basics/main/samples/protocols/ap2/images/ap2.png)

### Trust Boundary, Mandates (v0.2), and Delegation Chains

A key rule in the [AP2 v0.2 specification](https://github.com/google-agentic-commerce/AP2/blob/main/docs/ap2/specification.md)
is the strict separation between **Agentic** (LLM-driven) and **Non-Agentic** (deterministic) roles:

* The **Shopping Agent** is expected to be agentic.
* The **Trusted Surface** (where the user approves and signs mandates) **MUST** be non-agentic.
* Even if a **Merchant**, **Credential Provider**, or **Payment Processor** exposes an agentic interface, **all mandate
  validation and constraint verification MUST execute in deterministic code**.

In early AP2 overviews (v0.1), mandates were described conceptually as *Intent*, *Cart*, and *Payment* mandates. In
**AP2 v0.2** (and the official `ap2.sdk` Python package), this is formalized into two linked mandate families —
**Checkout Mandates** (securing *what* is purchased) and **Payment Mandates** (securing *how* it is paid) — each with an
**Open** and **Closed** state, supporting two modes:

1. **Human Present (`Direct` Flow)**: The user reviews the assembled cart on a Trusted Surface and directly signs the
   **Closed Checkout Mandate** (`mandate.checkout.1`) and **Closed Payment Mandate** (`mandate.payment.1`), bound to the
   merchant-signed UCP `checkout_jwt` via `checkout_hash`.
2. **Human Not Present (`Autonomous` Flow)**: The user pre-authorizes an **Open Checkout Mandate**
   (`mandate.checkout.open.1`) and **Open Payment Mandate** (`mandate.payment.open.1`) with deterministic constraints
   (e.g., allowed merchants, acceptable SKUs, and a maximum budget) and binds the Shopping Agent's public key in the
   `cnf` claim. Later, when the condition is met (such as a price drop), the Shopping Agent signs the **Closed
   Mandates** with its own private key and chains them onto the user's open mandates (`open_sd_jwt~~closed_kb_sd_jwt~`):

<img src="https://raw.githubusercontent.com/meteatamel/genai-beyond-basics/main/samples/protocols/ap2/images/mandate_chain_example.svg" alt="AP2 Mandate Delegation Chain" width="85%" />

AP2 supports two trust models for issuing the root Mandate on the **Trusted Surface** (**User Credential Model** via
OpenID4VP and the browser Digital Credentials API, or **Trusted Agent Provider Model** signed by the agent provider's key)
and enforces two normative presentation rules on the Shopping Agent: **Selective Disclosure Minimization** (revealing only
the disclosures required to evaluate the Closed Mandate) and **Sequential Presentation** (preventing concurrent reuse of
an Open Mandate across multiple checkouts without a prior rejection receipt).

### AP2 Sample: Mandate Delegation & Guardrails in Python

The official [`google-agentic-commerce/AP2`](https://github.com/google-agentic-commerce/AP2) repository includes full
multi-server A2A and MCP scenarios (using Cards or `x402` stablecoins), which I documented in my
[AP2 README](https://github.com/meteatamel/genai-beyond-basics/tree/main/samples/protocols/ap2).

However, spinning up four separate servers just to see how AP2 mandates work under the hood can be heavy. So I also built
a self-contained [AP2 Hello World (`mandate_demo.py`)](https://github.com/meteatamel/genai-beyond-basics/tree/main/samples/protocols/ap2/hello-world)
sample using the official `ap2.sdk` package that runs an entire **Autonomous (Human Not Present)** flow in a single
script with no API keys required.

Let's take a quick look at what's happening under the hood in
[`mandate_demo.py`](https://github.com/meteatamel/genai-beyond-basics/blob/main/samples/protocols/ap2/hello-world/mandate_demo.py).
First, the user (on a Trusted Surface) signs an `OpenCheckoutMandate` and an `OpenPaymentMandate` capping the spend at
`$150.00` (`15000` cents), linking to the open checkout mandate hash via `PaymentReference`, and binding the agent's
public key via `cnf`:

```python
open_checkout_hash = compute_sha256_b64url(open_checkout_token)

open_payment_token = client.create(
    payloads=[
        OpenPaymentMandate(
            constraints=[
                AmountRange(currency="USD", min=0, max=15000),
                AllowedPayees(allowed=[merchant]),
                PaymentReference(conditional_transaction_id=open_checkout_hash),
            ],
            cnf={"jwk": agent_pub_dict},
            iat=now,
            exp=now + 3600,
        )
    ],
    issuer_key=user_jwk,
)
```

When the merchant returns a signed UCP `Checkout` JWT for `$120.00`, the Shopping Agent autonomously signs and chains the
closed mandates using `MandateClient.present()`, and the Merchant and Payment Processor deterministically verify the
chain (`CheckoutMandateChain` and `PaymentMandateChain`):

```python
payment_chain_token = client.present(
    holder_key=agent_jwk,
    mandate_token=open_payment_token,
    payloads=[closed_payment],
    aud="credential-provider",
    nonce="nonce_pay_98765",
)

payment_payloads = client.verify(
    token=payment_chain_token,
    key_or_provider=lambda _tok: user_pub_jwk,
    expected_aud="credential-provider",
    expected_nonce="nonce_pay_98765",
)
payment_chain = PaymentMandateChain.parse(payment_payloads)
payment_violations = payment_chain.verify(
    expected_transaction_id=checkout_hash,
    expected_open_checkout_hash=open_checkout_hash,
)
```

You can run the sample with a single `uv` command:

```sh
uv run --with "ap2 @ git+https://github.com/google-agentic-commerce/AP2.git" python mandate_demo.py
```

Notice in step 6 how deterministic verification immediately catches and rejects an agent that tries to spend `$250.00`
against the user's `$150.00` open mandate:

```text
=== 1. Generating Keys for User (Trusted Surface), Agent, and Merchant ===

=== 2. User Signs Open Mandates on Trusted Surface (SD-JWT) ===
Intent: 'Buy white running shoes (SKU-SHOE-WHITE) from RunFast Store for at most $150.00'
Open Checkout Mandate (SD-JWT): eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImV4YW1wbGUrc2Qtand0IiwgImtpZCI6I...
Open Payment Mandate  (SD-JWT): eyJhbGciOiAiRVMyNTYiLCAidHlwIjogImV4YW1wbGUrc2Qtand0IiwgImtpZCI6I...

=== 3. Merchant Creates Signed UCP Checkout ($120.00) ===
Merchant Checkout JWT Hash: MBOOU7B8tmrp1fickmNKbaLJ74iQRtvSnO2HQ01ILU0

=== 4. Shopping Agent Signs Closed Mandates (KB-SD-JWT Delegation Chain) ===
Agent appended closed KB-SD-JWT hop to both open mandates.

=== 5. Deterministic Verification & Receipt Issuance ===
[Merchant] Checkout Mandate Chain verified! Constraints satisfied (0 violations).
[Payment Processor] Payment Mandate Chain verified! Amount $120.00 <= $150.00 max.
[Shopping Agent] Checkout Receipt verified: {'verified': True}
[Shopping Agent] Payment Receipt verified:  {'verified': True}

=== 6. Guardrail Demo: Agent Tries to Exceed Budget ($250.00 > $150.00) ===
[Payment Processor] Rejected over-budget payment! Violations: ['Amount 25000 exceeds maximum 15000']
```

## UCP vs. AP2: How They Work Together

Rather than competing, **UCP** and **AP2** are complementary layers in the agentic commerce stack:

* **UCP is the commerce layer**: It standardizes how agents discover stores (`/.well-known/ucp`), negotiate
  capabilities, calculate shipping and discounts, and manage checkout sessions.
* **AP2 is the cryptographic trust and payment authorization layer**: When UCP's `dev.ucp.common.payment.ap2_mandate`
  extension is negotiated, the session is **Security Locked** (preventing any downgrade to an unsigned checkout). The
  merchant signs the canonicalized (RFC 8785 JCS) `Checkout` payload and embeds a detached JWS at
  `checkout.ap2.merchant_authorization`, and on `POST /checkout-sessions/{id}/complete`, the agent submits
  cryptographically signed AP2 `CheckoutMandate` (`ap2.checkout_mandate`) and `PaymentMandate`
  (`payment.instruments[*].credential.token`) credentials bound to that checkout.

<img src="https://raw.githubusercontent.com/meteatamel/genai-beyond-basics/main/samples/protocols/ucp/images/ucp-ap2-checkout-flow.png" alt="UCP and AP2 Checkout Flow" width="85%" />

## Wrapping up

As AI agents move from answering questions to taking real-world actions like shopping and paying, **UCP** provides the
standardized commerce primitives while **AP2** provides the cryptographic guardrails to prove user intent.

Here are some resources to learn more:

* [Docs: Universal Commerce Protocol (ucp.dev)](https://ucp.dev/)
* [Docs: Agent Payments Protocol (ap2-protocol.org)](https://ap2-protocol.org/)
* [Docs: UCP and AP2 Integration](https://ucp.dev/latest/documentation/ucp-and-ap2/)
* [Blog: Under the Hood: Universal Commerce Protocol (UCP)](https://developers.googleblog.com/under-the-hood-universal-commerce-protocol-ucp/)
* [Blog: Announcing Agent Payments Protocol (AP2)](https://cloud.google.com/blog/products/ai-machine-learning/announcing-agents-to-payments-ap2-protocol)
* [Blog: Developer’s Guide to AI Agent Protocols](https://developers.googleblog.com/developers-guide-to-ai-agent-protocols/)
* [Codelab: Secure Agent Commerce with AP2 and UCP](https://codelabs.developers.google.com/next26/adk-agent-commerce)
* [Sample: My UCP and AP2 Samples in genai-beyond-basics](https://github.com/meteatamel/genai-beyond-basics/tree/main/samples/protocols)

