For AI agents: a documentation index is available at https://www.mongodb.com/docs/llms.txt — markdown versions of all pages are available by appending .md to any URL path.
Docs Menu

Mandate Ledger for Trusted Agentic Commerce on MongoDB

Learn how to build an immutable Mandate Ledger on MongoDB Atlas to create a trust layer for agentic commerce and guarantee accountability.

Use cases: Artificial Intelligence, Payments

Industries: Retail

Products: MongoDB Atlas

Partners: Google Cloud

AI agents transform digital commerce by autonomously managing tasks from product discovery to final checkout. However, when an AI agent initiates a payment on behalf of a customer, it breaks the core assumptions of traditional commerce and creates a crisis of trust.

Existing payment systems cannot verify an agent's authority, authenticate a customer's true intent, or define clear transaction accountability. This creates key challenges:

  • Authorization: Verifying that a customer authorized the agent for a particular purchase.

  • Authenticity: Verifying that an agent's request accurately reflects the customer's true intent, without errors or hallucinations.

  • Accountability: Determining who is responsible if a transaction fails—the customer, the agent's developer, the merchant, or the issuer.

Addressing these challenges requires a shared standard that every participant, including customers, merchants, and financial institutions, can trust.

Google's Agent Payments Protocol (AP2) provides an open, secure, and interoperable protocol that builds a trusted ecosystem for merchants, financial institutions, and everyday customers.

The trust layer

Figure 1. The trust layer

AP2 secures transactions through Verifiable Digital Credentials (VDCs)—tamper-evident, cryptographically signed JSON payloads that agents create and exchange. AP2 categorizes these VDCs into three core mandates:

  • The Intent Mandate: Outlines what the customer requires and defines the conditions under which an AI agent can make a purchase on the customer's behalf.

  • The Cart Mandate: Provides a digital receipt signed by both the merchant and the customer to authorize human-present purchases.

  • The Payment Mandate: Creates a visibility layer shared directly with the payment network to securely signal AI agent involvement.

VDCs act as permanent digital contracts. Agents cryptographically sign these payloads to capture customer intent. This process creates a non-repudiable audit trail for every step of the shopping experience.

A contractual conversation with verifiable proof at every step

Figure 2. A contractual conversation with verifiable proof at every step

Intent visualization in the user interface, showing how each intent is represented within the conversation

Figure 3. Intent visualization in the user interface, showing how each intent is represented within the conversation

For these cryptographic VDCs to remain trustworthy, systems must store them in a secure, verifiable environment. The Mandate Ledger Service acts as the protective middleware between AI agents and the database. Behind this middleware is MongoDB Atlas.

Atlas provides the enterprise-grade security designed to support a tamper-proof audit trail. Build this architecture to create the immutable trust layer, the Mandate Ledger Service, required to scale secure agentic commerce.

Picture a customer asking an AI assistant to shop for a new smartphone. The Shopping Agent autonomously negotiates with merchants to find the perfect deal. The Mandate Ledger Service records this entire journey by packaging every request, approval, and checkout step into cryptographically signed JSON mandates. MongoDB Atlas stores each mandate as an immutable document. This process transforms a simple chat into a permanent, non-repudiable proof of intent.

This solution shows how to build the Mandate Ledger Service on top of an architecture that uses the AP2 protocol.

AP2 uses a role-based architecture designed to provide security and clear transaction accountability. Each actor in this ecosystem carries distinct responsibilities to simplify integration and protect customer privacy.

MongoDB Mandate Ledger Service architecture

Figure 4. MongoDB Mandate Ledger Service architecture

Review the key roles defined in this architecture:

  • The customer: Interacts directly with the Shopping Agent to initiate product discovery and purchase requests.

  • The Shopping Agent: Interacts directly with the customer to discover products, negotiate the cart, and sign mandates.

  • The Merchant Agent: Represents the seller to showcase inventory, negotiate offers, and sign mandates to guarantee order fulfillment.

  • The Credentials Provider: Manages the customer's payment methods securely and selects the appropriate payment tokens for the transaction.

  • The Merchant Payment Processor: Constructs and routes the transaction authorization message directly to the payment network and issuer.

  • The Auditor Agent: Inspects the immutable audit trail after a transaction to verify payments and signatures using read-only access.

  • The Mandate Ledger Service: Acts as the protective middleware between the AI agents and MongoDB Atlas to store the cryptographically signed mandates natively as JSON documents. MongoDB Atlas serves as the central, immutable ledger.

This solution uses a multi-agent architecture where agents communicate using the Agent-to-Agent (A2A) protocol. AP2 also supports the Universal Commerce Protocol (UCP) to execute transactions.

The Mandate Ledger Service acts as a protective middleware that connects the Merchant Agent to the database. Build this service using FastAPI or gRPC.

Mandate Ledger Service detailed architecture

Figure 5. Mandate Ledger Service detailed architecture

Process all agent requests through three distinct, secure layers:

  • The Authentication Layer: Validates API keys to securely identify agents. It applies Role-Based Access Control (RBAC) by agent type to enforce strict agent permissions.

  • The Business Logic Layer: Executes core request validation and concurrency control. It enforces idempotency for safe network retries and supports strict mandate immutability.

  • The Data Access Layer: Uses the MongoDB client and optimized indexing to execute database operations. This layer defines the _id field as immutable and blocks all update and delete operations through schema validation.

Every AP2 transaction progresses through a structured sequence of cryptographically signed mandates. Each step produces an immutable record in MongoDB Atlas, creating a complete audit trail from intent to payment.

Data flow

Figure 6. Data flow

To move a transaction from intent to payment, AP2 agents complete the following transaction sequence:

  1. Capture the customer's intent. The Shopping Agent translates the customer's request, such as a natural language description of "running shoes", into a structured Intent Mandate. The Intent Mandate captures the target merchant, refundability requirements, cart confirmation preferences, and an expiry window. The Shopping Agent signs the mandate using EdDSA on the customer's behalf and sends it to the Merchant Agent with a status of signed and a version hash locking its contents.

  2. Store the Intent Mandate. The Merchant Agent writes the Intent Mandate to Atlas through the Mandate Ledger Service. The ledger service validates the request, applies RBAC, and appends the record immutably.

  3. Create the Cart Mandate. The Merchant Agent builds a cart offer containing the full product details: item name, price, currency, accepted payment methods, and expiry. The Merchant Agent then stores it in Atlas through the Mandate Ledger Service, where the record receives a status of proposed and a version hash to ensure integrity.

  4. Offer the Cart to the customer. The Merchant Agent returns the proposed Cart Mandate to the Shopping Agent, which presents the available product options to the customer.

  5. Accept the Cart Mandate. The customer selects an option. The Shopping Agent co-signs the Cart Mandate on the customer's behalf using a hardware-backed device key and sends the accepted mandate back to the Merchant Agent.

  6. Countersign and finalize the Cart Mandate. The Merchant Agent adds its cryptographic signature to the accepted cart and stores the fully dual-signed Cart Mandate in Atlas, locking the agreed terms with a signed status.

  7. Create the Payment Mandate. The Shopping Agent queries the Credentials Provider to retrieve the appropriate payment token. The Shopping Agent then creates and signs the Payment Mandate on the customer's behalf and sends it to the Merchant Agent. The Credentials Provider never returns full credit card numbers, which ensures the Shopping Agent never accesses raw data.

  8. Store the Payment Mandate. The Merchant Agent writes the signed Payment Mandate to Atlas through the Mandate Ledger Service. The ledger service shares this mandate directly with financial institutions to flag AI agent involvement, and the Payment Processor uses this mandate to route the authorization to the payment network.

Agents cannot modify or delete existing records. MongoDB Atlas enforces append-only writes, so the complete mandate chain—Intent, Cart, and Payment—remains intact and independently verifiable by the Auditor Agent at any time.

Structure the MongoDB database using five core collections to support e-commerce at scale:

  • mandate_ledger: Stores immutable mandate versions safely.

  • payments: Stores ultra-lean payment completion records.

  • api_keys: Manages API keys to identify agents securely.

  • audit_log: Maintains a complete operation audit trail.

  • idempotency_records: Caches request data to deduplicate operations.

The mandate_ledger collection stores all three mandate types in a single collection. Use the entity_type field to distinguish them at query time, which eliminates the need for joins or separate collections per mandate type.

All documents share a common envelope structure:

{
"entity_id": "IntentMandate_955181ea-11c3-4379-92c4-3e27c5f278d3",
"entity_type": "IntentMandate",
"version": 1,
"status": "signed",
"transaction_id": "txn_fca7db66-c769-4206-b891-7140af37f8f4",
"user_id": "hunter-d53910cf-b9e2-4876-8668-8251c990e203",
"created_by_agent": "merchant_agent_dev",
"created_by_agent_type": "merchant-agent",
"current_version_hash": "4a822a01468a27dfd...",
"signatures": [...],
"mandate_data": { ... }
}

The mandate_data field carries the type-specific payload, where each mandate type stores a different data structure:

The IntentMandate document captures the customer's purchase intent as structured data. This data includes a natural language description, target merchants, specific SKUs, refundability requirements, and an expiry window:

IntentMandate document
"mandate_data": {
"natural_language_description": "cheapest french press coffee maker",
"merchants": [],
"skus": [],
"requires_refundability": true,
"user_cart_confirmation_required": true,
"intent_expiry": "2026-04-18T20:00:03.651746+00:00"
}

The Shopping Agent signs this document using EdDSA before sending it to the Merchant Agent. The document enters the ledger with a "status": "signed" payload and a current_version_hash value that locks its contents.

The CartMandate document carries the full commercial offer, including line items with prices and currencies, shipping costs, taxes, accepted payment methods, and a cart expiry window:

CartMandate document
"mandate_data": {
"contents": {
"payment_request": {
"method_data": [{ "supported_methods": "CARD", "data": { "network": ["mastercard", "paypal", "amex"] }}],
"details": {
"display_items": [
{ "label": "Standard Laptop", "amount": { "currency": "USD", "value": 1203.50 }, "refund_period": 30 },
{ "label": "Shipping", "amount": { "currency": "USD", "value": 2.00 }},
{ "label": "Tax", "amount": { "currency": "USD", "value": 1.50 }}
],
"total": { "label": "Total", "amount": { "currency": "USD", "value": 1203.50 }}
}
},
"shipping_address": { "recipient": "Bugs Bunny", "address_line": ["123 Main St"], "city": "Sample City", "country": "US" },
"cart_expiry": "2026-04-17T20:29:05.197984+00:00"
},
"merchant_authorization": "eyJhbGciOiJSUzI1NiIs..."
}

This document enters the ledger with a "status": "proposed" designation. When the customer accepts the offer, the Shopping Agent co-signs it. The Merchant Agent then writes a new document to the ledger with the same transaction_id, an incremented version, and a "status": "signed" field. Including both signatures in the array makes the agreed terms bilaterally binding:

"signatures": [
{ "signer_type": "shopping-agent", "algorithm": "EdDSA", "signed_at": "2026-04-17T19:59:49Z" },
{ "signer_type": "merchant-agent", "algorithm": "JWT", "signed_at": "2026-04-17T19:59:50Z" }
]

The PaymentMandate document binds the agreed cart to a specific payment token retrieved from the Credentials Provider, and includes the payer's shipping and contact details:

PaymentMandate document
"mandate_data": {
"payment_mandate_contents": {
"payment_details_total": { "label": "Total", "amount": { "currency": "USD", "value": 1203.50 }},
"payment_response": {
"method_name": "CARD",
"details": { "token": { "value": "fake_payment_credential_token_5" }},
"shipping_address": { "recipient": "Bugs Bunny", "address_line": ["123 Main St"], "city": "Sample City" },
"payer_email": "bugsbunny@gmail.com"
},
"merchant_agent": "Generic Merchant",
"timestamp": "2026-04-17T20:00:22.603453+00:00"
},
"user_authorization": "fake_cart_mandate_hash_cart_fb1b4c86..._fake_payment_mandate_hash_812843b2..."
}

The user_authorization hash cryptographically links this PaymentMandate to the accepted CartMandate, which prevents the payment token from being replayed against another transaction.

Create an index on the transaction_id and entity_type fields to retrieve the full mandate chain for any transaction in a single query.

The payments collection stores one document per completed transaction. This collection applies the Extended Reference pattern.

Rather than embedding the full mandate contents, each document stores only the mandate ID and the authorizing signature for each of the three mandates. This design keeps the payment record small and fast to read, while preserving a direct pointer to the complete data in the mandate_ledger collection when a full audit trace is required.

{
"payment_id": "pay_123c25ac-7b56-4e45-8dd1-30cdcda944c7",
"transaction_id": "txn_6fbab918-2b5d-4ddd-89d8-fdb96e5648d9",
"user_id": "hunter-263b752e-92be-4001-ab9d-38847811c663",
"intent_mandate": { "mandate_id": "IntentMandate_41bbeacf-...", "signature": "0x_shopping_agent_sig_...", "timestamp": "2026-04-15T19:50:57Z" },
"cart_mandate": { "mandate_id": "CartMandate_c0e8f369-...", "signature": "eyJhbGciOiJSUzI1NiIs...", "timestamp": "2026-04-15T19:52:07Z" },
"payment_mandate": { "mandate_id": "PaymentMandate_33c39b8c-...", "signature": "fake_cart_mandate_hash_...", "timestamp": "2026-04-15T19:53:53Z" },
"amount": 28,
"currency": "USD",
"status": "SUCCESS",
"payment_method_type": "CARD",
"merchant_agent": "merchant_agent_dev",
"payment_processor_agent": "payment_processor",
"processed_at": "2026-04-15T19:54:14Z"
}

This design intentionally keeps the document small. The full terms, line items, and cryptographic proofs reside in the mandate_ledger collection. The payment record exists only to confirm that the transaction is complete and to provide the three pointers required to reconstruct the full audit chain. Use the transaction_id field to join across both collections when a full trace is required.

The api_keys collection manages API keys to securely identify agents. Use this collection to store the keys associated with each agent that calls the service.

The audit_log collection stores all API operations for compliance and debugging. Use this collection to record service-level events, such as mandate creation, access attempts, and validation outcomes. This approach prevents expanding the immutable mandate ledger itself. Add a TTL index to automatically remove records after 90 days. This preserves a useful operational trail while keeping the collection bounded.

The collection includes the following key fields:

  • event_type: Identifies the operation type, such as mandate.created.

  • entity_id: References the related mandate.

  • actor_agent_id: Captures which agent performed the action.

  • event_timestamp: Records when the event occurred and supports the TTL policy.

  • expires_at: Defines when MongoDB automatically deletes the record.

The idempotency_records collection stores idempotency keys to prevent duplicate operations. Use this collection to retain the client-supplied key, the agent that made the request, and the ledger entry created for that operation. Add a TTL index to automatically remove records after 24 hours.

The collection includes the following key fields:

  • idempotency_key: Stores the unique client-supplied key and requires an index.

  • agent_id: Identifies the agent that made the request.

  • ledger_entry_id: References the mandate created for the original request.

  • expires_at: Defines when MongoDB automatically deletes the record.

Before you begin, ensure you install and configure the following:

  • MongoDB Atlas or self-managed MongoDB 7.0 or later

  • Python 3.13 (version 3.13.x)

  • uv for dependency management

  • A Google API Key or Vertex AI access

  • Docker to run services as containers

  • Node.js and npm for the frontend application

1
  1. Clone the repository and install the Mandate Ledger Service:

    git clone https://github.com/mongodb-industry-solutions/retail-agent-shopping-ap2-ucp.git
    cd retail-agent-shopping-ap2-ucp/mandate_ledger_service
    python3.13 -m venv .venv
    source .venv/bin/activate
    pip install -e .
  2. Create a .env file in the mandate_ledger_service/ directory:

    MONGODB_URI= # Your connection string
    MONGODB_DATABASE=mandate_ledger
    SERVICE_NAME=mandate-ledger-service
    ENVIRONMENT=development
    # Bootstrap Auth (dev only — set to false after Step 2)
    BOOTSTRAP_ADMIN_KEY=**** # Generate: openssl rand -hex 32
    ENABLE_BOOTSTRAP_AUTH=true
    ALLOWED_CORS_ORIGINS=*
    DEFAULT_RATE_LIMIT_PER_MINUTE=60
  3. Start the service:

    uvicorn src.main:app --reload --port 5000
  4. To run the service with Docker instead:

    docker build -t mandate-ledger .
    docker run --rm \
    -p 5000:5000 \
    --env-file .env \
    mandate-ledger
2
  1. Open a new terminal and run:

    cd mandate_ledger_service
    source .venv/bin/activate
    PYTHONPATH=. python3 scripts/setup_agent_keys.py
  2. Copy the Merchant Agent API Key from the output. Set ENABLE_BOOTSTRAP_AUTH=false in your .env file and restart the service.

Production Note: Use a secrets manager such as Google Secret Manager or AWS Secrets Manager and implement key rotation.

3

The /backend service interacts with the Mandate Ledger Service and pushes new mandates into the ledger. This service is adapted from Google's AP2 repository using the AP2 + A2A sample.

  1. Create a .env file in /backend. Set MANDATE_LEDGER_API_KEY to the mlsk_merchant_key value generated in Step 2:

    GOOGLE_API_KEY=
    MANDATE_LEDGER_SERVICE_URL=http://localhost:5000
    MANDATE_LEDGER_API_KEY=
  2. For Vertex AI, replace the first line with:

    GOOGLE_GENAI_USE_VERTEXAI=true
    GOOGLE_CLOUD_PROJECT=your-project-id
    GOOGLE_CLOUD_LOCATION=us-central1
  3. Build and run the backend container:

    docker build -f backend/Dockerfile -t retail-backend ./backend
    docker run --rm \
    -p 8000:8000 \
    -p 8001:8001 \
    -p 8002:8002 \
    -p 8003:8003 \
    -p 8004:8004 \
    --env-file backend/.env \
    retail-backend
  4. The backend API starts on http://localhost:8000 and automatically launches the following AP2 agents:

    Agent
    Port

    Shopping Agent (integrated into main backend)

    8000

    Merchant Agent

    8001

    Credentials Provider Agent

    8002

    Merchant Payment Processor Agent

    8003

    Auditor Agent

    8004

4

The frontend is a Next.js application that interacts with the /backend service.

  1. Copy the example .env file and set the backend and assistant endpoints:

    cd frontend
    cp EXAMPLE.env .env.local
  2. Update frontend/.env.local with your values:

    MONGODB_URI=<your-mongodb-string>
    MONGODB_DATABASE=<your-database-name>
    NEXT_PUBLIC_BACKEND_ENDPOINT=http://localhost:8000
    ASSISTANT_ENDPOINT=http://localhost:3333
  3. Install dependencies and run the frontend:

    npm install
    npm run dev
  4. To run the frontend as a container, use the root Dockerfile.

Enable suggested replies in the chat UI

The chat interface generates suggested replies through an external assistant microservice. To enable this feature, set up and run the Assistant Microservice before starting the demo. Without this service, the app loads but does not generate suggested replies.

5
  1. Start all three services in separate terminals, then open the app at http://localhost:8080.

  2. The backend API remains available at http://localhost:8000.

  3. Follow the User Guide for full instructions on navigating the application.

Establish trust in agentic commerce. Overcome the crisis of trust by anchoring AI transactions to deterministic, non-repudiable proof of customer intent:

  • Ensure transaction immutability: Enforce append-only rules in your Mandate Ledger Service to create a tamper-proof audit trail.

  • Preserve cryptographic signatures: Use the MongoDB document model to natively store deeply nested JSON mandates exactly as agents generate them.

  • Control agent access: Implement Role-Based Access Control to ensure AI agents only perform authorized actions based on their specific roles.

  • Prevent duplicate charges: Enforce idempotency keys in your service layer to safely handle network retries without double-charging the customer.

  • Angelica Guemes, MongoDB

  • Florencia Arin, MongoDB

  • Sakshi Garg, MongoDB

  • Genevive Broadhead, MongoDB

  • Antonio Membrides, MongoDB

  • Daniel Jamir, MongoDB