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
Solution Overview
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.
Establish Trust with AP2
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.
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.
Figure 2. A contractual conversation with verifiable proof at every step
Figure 3. Intent visualization in the user interface, showing how each intent is represented within the conversation
Ensure Accountability with MongoDB Atlas
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.
Reference Architectures
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.
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 Ledger Service: A Protective Shield
The Mandate Ledger Service acts as a protective middleware that connects the Merchant Agent to the database. Build this service using FastAPI or gRPC.
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
_idfield as immutable and blocks all update and delete operations through schema validation.
The Mandate Chain: From Intent to Payment
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.
Figure 6. Data flow
To move a transaction from intent to payment, AP2 agents complete the following transaction sequence:
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
signedand a version hash locking its contents.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.
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
proposedand a version hash to ensure integrity.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.
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.
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
signedstatus.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.
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.
Data Model Approach
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: A Polymorphic Document Store
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:
IntentMandate
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:
"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.
CartMandate
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:
"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" } ]
PaymentMandate
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:
"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.
Indexing Requirements
Create an index on the transaction_id and entity_type fields to retrieve the full mandate chain for any transaction in a single query.
Payments: The Ultra-Lean Completion Record
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.
API Keys: Secure Agent Identification
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.
Audit Log: The Operational Trail
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 asmandate.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.
Idempotency Records: Safe Retry Handling
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.
Build the Solution
Prerequisites
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
Procedure
Install the Ledger Service
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 . Create a
.envfile in themandate_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 Start the service:
uvicorn src.main:app --reload --port 5000 To run the service with Docker instead:
docker build -t mandate-ledger . docker run --rm \ -p 5000:5000 \ --env-file .env \ mandate-ledger
Generate Agent API Keys
Open a new terminal and run:
cd mandate_ledger_service source .venv/bin/activate PYTHONPATH=. python3 scripts/setup_agent_keys.py Copy the Merchant Agent API Key from the output. Set
ENABLE_BOOTSTRAP_AUTH=falsein your.envfile and restart the service.
Production Note: Use a secrets manager such as Google Secret Manager or AWS Secrets Manager and implement key rotation.
Configure the Backend
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.
Create a
.envfile in/backend. SetMANDATE_LEDGER_API_KEYto themlsk_merchant_keyvalue generated in Step 2:GOOGLE_API_KEY= MANDATE_LEDGER_SERVICE_URL=http://localhost:5000 MANDATE_LEDGER_API_KEY= For Vertex AI, replace the first line with:
GOOGLE_GENAI_USE_VERTEXAI=true GOOGLE_CLOUD_PROJECT=your-project-id GOOGLE_CLOUD_LOCATION=us-central1 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 The backend API starts on http://localhost:8000 and automatically launches the following AP2 agents:
AgentPortShopping Agent (integrated into main backend)
8000
Merchant Agent
8001
Credentials Provider Agent
8002
Merchant Payment Processor Agent
8003
Auditor Agent
8004
Configure the Frontend
The frontend is a Next.js application that interacts with the /backend service.
Copy the example
.envfile and set the backend and assistant endpoints:cd frontend cp EXAMPLE.env .env.local Update
frontend/.env.localwith your values:MONGODB_URI=<your-mongodb-string> MONGODB_DATABASE=<your-database-name> NEXT_PUBLIC_BACKEND_ENDPOINT=http://localhost:8000 ASSISTANT_ENDPOINT=http://localhost:3333 Install dependencies and run the frontend:
npm install npm run dev 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.
Run the Demo
Start all three services in separate terminals, then open the app at http://localhost:8080.
The backend API remains available at http://localhost:8000.
Follow the User Guide for full instructions on navigating the application.
Key Learnings
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.
Authors
Angelica Guemes, MongoDB
Florencia Arin, MongoDB
Sakshi Garg, MongoDB
Genevive Broadhead, MongoDB
Antonio Membrides, MongoDB
Daniel Jamir, MongoDB