Sitemap

Intent Is Data: Why Document-Based Architecture Is the Foundation for Verifiable, Compliant Commerce

11 min readMar 18, 2026

--

Press enter or click to view image in full size

On March 5, 2026, Mastercard and Google open-sourced Verifiable Intent — a cryptographic framework that proves an AI agent’s transaction matches the original authorized intent. The spec is built entirely on SD-JWT: JSON credentials with selective disclosure. Three cryptographic layers. Each one a JSON document. Each hash-bound to the one before it.

Most teams will read this spec and ask: “Which API endpoint do I call?” That’s the wrong question.

The right question: “How do I model intent in my database so that Selective Disclosure actually works?”

This article breaks down why document-based architecture isn’t just helpful for implementing Verifiable Intent — it’s foundational. And why India’s massive digital public infrastructure already proves the pattern at nation-scale.

The Problem: Autonomous Agents Break the Trust Model

Press enter or click to view image in full size

When you tap a card at a terminal, intent is self-evident. You’re there. You see the amount. You authorize the payment. The entire payment infrastructure — from PCI DSS to PSD2’s Strong Customer Authentication — assumes a human is present at the point of transaction.

AI agents break that assumption.

When an agent books travel on your behalf 48 hours after you gave the instruction, or reorders groceries based on constraints you set last week, no party in the chain can verify that the agent’s actions actually reflect your wishes. The agent might overspend. It might transact with an unapproved merchant. It might select the wrong product entirely.

Every stakeholder carries unquantifiable risk: the user faces unauthorized purchases, the merchant faces chargebacks with no proof of authorization, and the payment network can’t determine who actually authorized the transaction.

Mastercard’s Pablo Fourez framed the problem directly: when autonomy increases, trust cannot be implied — it must be proven.

This is the gap Verifiable Intent closes.

How Verifiable Intent Actually Works

Verifiable Intent defines a layered SD-JWT credential format — standardized in RFC 9901 (November 2025) — that creates a tamper-evident chain from credential provider to user to agent. Each layer binds the next through key confirmation claims (RFC 7800), and selective disclosure ensures each party sees only the claims relevant to its role.

Press enter or click to view image in full size

Three layers. Each one is a JSON document. Each cryptographically hash-bound to the previous.

Layer 1: Identity Credential (SD-JWT)

The credential provider (e.g., a bank or card issuer) issues an SD-JWT to the user. The payload is JSON containing identity claims, and critically, a cnf (confirmation) claim binding the user's device key.

json

{
"iss": "https://credential-provider.example.com",
"iat": 1709654400,
"exp": 1741190400,
"sub": "user_8f3a9b2c",
"_sd": [
"Hk3dK8...hashed_email_disclosure",
"Jf8sLp...hashed_pan_last_four_disclosure"
],
"_sd_alg": "sha-256",
"scheme": "mastercard",
"cnf": {
"jwk": {
"kty": "EC",
"crv": "P-256",
"x": "52aDI_ur05n1f_p3jiYGUU82oKZr3m4LsAErM536crQ",
"y": "ckhZ-KQ5aXNL91R8Eufg1aOf8Z5pZJnIvuCzNGfdnzo"
}
}
}

The _sd array contains hashed disclosures — the actual values (email, last four digits of card) are not embedded directly. They exist as separate base64-encoded disclosure strings that can be selectively revealed. The cnf.jwk is the user's device public key. Layer 2 must be signed by the corresponding private key.

Lifetime: approximately 1 year.

Layer 2: User Intent (KB-SD-JWT)

The user signs a Key-Binding SD-JWT expressing their intent. This is where it gets architecturally interesting. In Autonomous mode — where the agent acts independently — L2 contains constraint-based mandates, not final values.

{
"sd_hash": "dBfK7...hash_of_L1",
"iat": 1709740800,
"exp": 1709827200,
"mode": "autonomous",
"mandates": [
{
"type": "checkout.open",
"constraints": {
"allowed_merchants": [
{
"merchant_id": "TENNIS_WH_001",
"name": "Tennis Warehouse",
"_sd": ["R3pXk...hashed_merchant_detail"]
},
{
"merchant_id": "RACQUET_DEP_042",
"name": "Racquet Depot",
"_sd": ["Lm9Qa...hashed_merchant_detail"]
}
],
"line_items": [
{
"category": "tennis_rackets",
"max_quantity": 1,
"price_range": { "min": 50.00, "max": 250.00, "currency": "USD" }
},
{
"category": "tennis_balls",
"max_quantity": 2,
"price_range": { "min": 3.00, "max": 15.00, "currency": "USD" }
}
],
"amount_range": {
"max": 300.00,
"currency": "USD"
}
},
"cnf": {
"jwk": { "kty": "EC", "crv": "P-256", "x": "agent_key_x...", "y": "agent_key_y..." }
}
},
{
"type": "payment.open",
"constraints": {
"amount_range": { "max": 300.00, "currency": "USD" },
"payment_instrument": "card_ending_4242"
},
"cnf": {
"jwk": { "kty": "EC", "crv": "P-256", "x": "agent_key_x...", "y": "agent_key_y..." }
}
}
]
}

Look at the structure. Each mandate is a JSON object. allowed_merchants is a JSON array of objects — each one selectively disclosable. line_items is an array of constraint objects with nested price_range sub-objects. The cnf.jwk in each mandate binds the agent's key — both the checkout and payment mandates must reference the identical agent key.

This is not a flat row. It’s a deeply nested, selectively disclosable JSON document.

Lifetime: 24 hours to 30 days.

Layer 3: Agent Execution (Split KB-SD-JWTs)

The agent executes within the constraints and produces two linked SD-JWTs:

L3a (Payment → Network):

json

{
"sd_hash": "Kf9mN...hash_of_L2",
"mandate_type": "payment.open",
"final_amount": 267.50,
"currency": "USD",
"transaction_id": "txn_a8f3c9d2e1",
"payment_instrument": "card_ending_4242"
}

L3b (Checkout → Merchant):

json

{
"sd_hash": "Kf9mN...hash_of_L2",
"mandate_type": "checkout.open",
"checkout_hash": "txn_a8f3c9d2e1",
"selected_merchant": "TENNIS_WH_001",
"line_items": [
{ "product": "Wilson Blade 98 v9", "quantity": 1, "price": 249.00 },
{ "product": "Penn Championship Balls (3-pack)", "quantity": 2, "price": 9.25 }
]
}

The cross-reference (L3a.transaction_id == L3b.checkout_hash) cryptographically binds the payment to the specific checkout, proving the agent paid for exactly what it selected — and that the selection was within the user's original constraints.

Lifetime: approximately 5 minutes.

Why the JSON Structure Is the Architecture

Press enter or click to view image in full size

The entire verification chain depends on the ability to query, disclose, and validate JSON structures at each layer. Let that sink in.

Selective disclosure means a merchant sees only that it was an approved merchant for this transaction — not the full list of allowed merchants, not the payment details, not the user’s email. The payment network sees the amount and instrument — not the checkout details. Each party gets a cryptographically verifiable subset of the original intent document.

This requires three capabilities from your data layer:

  1. Nested JSON structures must be natively queryable. You need to ask: “For this L2 mandate, what merchants were allowed?” and get back an array of objects — not a join across three tables.
  2. Individual fields within nested structures must be independently disclosable. Selective disclosure operates at the claim level. If allowed_merchants[0].name is disclosed but allowed_merchants[1] is not, your data model must support that granularity.
  3. Entire documents must be hashable in their serialized form. The sd_hash in each layer is a hash of the previous layer's serialized JSON. Your storage format must preserve the structure that was hashed.
Press enter or click to view image in full size

The Schema Problem: Why Relational Models Break

Consider how most teams would model purchase intent today in a relational database:

Get Sangram Mohite’s stories in your inbox

Join Medium for free to get updates from this writer.

SQL

CREATE TABLE mandates (
id UUID PRIMARY KEY,
user_id UUID NOT NULL,
amount DECIMAL(10,2),
merchant VARCHAR(255),
created_at TIMESTAMP DEFAULT NOW()
);

This works for a world where one user authorizes one payment to one merchant for one amount. It doesn’t survive contact with Verifiable Intent.

Multi-merchant constraints?

You need a join table. mandate_allowed_merchants with foreign keys. Now your "intent" is scattered across two tables, and reconstructing the original constraint requires a join — which doesn't hash to the same thing as the JSON document the user signed.

Nested line-item constraints? Another join table. mandate_line_items with columns for category, max_quantity, min_price, max_price, currency. Five columns to represent what is a single nested JSON object in the spec.

Selective disclosure at the field level? There’s no relational primitive for “show this row’s merchant name but not that row’s merchant name within the same result set.” You’d need a disclosure metadata table tracking which fields are disclosed to which party for which mandate at which layer. The complexity compounds.

Dynamic constraint types? The Verifiable Intent spec defines five constraint types: amount, payee, merchant, line_items, and currency. Each has a different structure. In a relational model, you'd need either a union of all possible columns (sparse, hard to validate) or separate tables per constraint type (fragmented, hard to query holistically). And when new constraint types emerge — which the spec explicitly anticipates — you're running ALTER TABLE statements in production.

Checkout-payment integrity binding? Both the checkout mandate and the payment mandate must reference the same agent key. Verifying this requires loading both mandates as complete JSON objects and comparing their cnf.jwk values. In a relational model, those keys might be stored in a separate mandate_keys table, requiring yet another join — and the serialized form used for hashing is lost entirely.

The Document-Based Alternative

Now model the same intent as a document:

javascript

// MongoDB document representing an L2 Autonomous mandate
{
_id: ObjectId("6602a1f3..."),
sd_hash: "dBfK7...hash_of_L1",
iat: 1709740800,
exp: 1709827200,
mode: "autonomous",
user_id: "user_8f3a9b2c",
mandates: [
{
type: "checkout.open",
constraints: {
allowed_merchants: [
{ merchant_id: "TENNIS_WH_001", name: "Tennis Warehouse" },
{ merchant_id: "RACQUET_DEP_042", name: "Racquet Depot" }
],
line_items: [
{
category: "tennis_rackets",
max_quantity: 1,
price_range: { min: 50.00, max: 250.00, currency: "USD" }
},
{
category: "tennis_balls",
max_quantity: 2,
price_range: { min: 3.00, max: 15.00, currency: "USD" }
}
],
amount_range: { max: 300.00, currency: "USD" }
},
cnf: {
jwk: { kty: "EC", crv: "P-256", x: "agent_key_x...", y: "agent_key_y..." }
}
},
{
type: "payment.open",
constraints: {
amount_range: { max: 300.00, currency: "USD" },
payment_instrument: "card_ending_4242"
},
cnf: {
jwk: { kty: "EC", crv: "P-256", x: "agent_key_x...", y: "agent_key_y..." }
}
}
],
// Metadata for disclosure tracking
disclosure_log: [
{
party: "merchant",
disclosed_paths: [
"mandates.0.constraints.allowed_merchants.0",
"mandates.0.constraints.line_items"
],
timestamp: 1709741400
}
]
}

This maps 1:1 to the SD-JWT payload structure. There’s no impedance mismatch.

Now query it:

javascript

// Find all active mandates for a user with a specific merchant in constraints
db.mandates.find({
user_id: "user_8f3a9b2c",
exp: { $gt: Math.floor(Date.now() / 1000) },
"mandates.constraints.allowed_merchants.merchant_id": "TENNIS_WH_001"
});
// Verify agent key consistency across checkout and payment mandates
db.mandates.aggregate([
{ $match: { _id: ObjectId("6602a1f3...") } },
{ $project: {
checkout_key: {
$filter: {
input: "$mandates",
cond: { $eq: ["$$this.type", "checkout.open"] }
}
},
payment_key: {
$filter: {
input: "$mandates",
cond: { $eq: ["$$this.type", "payment.open"] }
}
}
}},
{ $project: {
keys_match: {
$eq: [
{ $arrayElemAt: ["$checkout_key.cnf.jwk.x", 0] },
{ $arrayElemAt: ["$payment_key.cnf.jwk.x", 0] }
]
}
}}
]);
// Selective disclosure: project only what the merchant should see
db.mandates.aggregate([
{ $match: { _id: ObjectId("6602a1f3...") } },
{ $project: {
_id: 0,
mandate_type: { $arrayElemAt: ["$mandates.type", 0] },
selected_merchant: {
$arrayElemAt: ["$mandates.constraints.allowed_merchants", 0]
},
line_items: { $arrayElemAt: ["$mandates.constraints.line_items", 0] }
// Payment details, other merchants, user identity: all excluded
}}
]);

The selective disclosure is a query projection — a native database operation. The constraint verification is an aggregation pipeline. The checkout-payment integrity check is a comparison within a single document. No joins. No reconstruction. No impedance mismatch.

Press enter or click to view image in full size

India’s Digital Infrastructure: The Pattern at Scale

This isn’t theoretical. India’s digital public infrastructure — the world’s largest — already operates on patterns that are architecturally identical to what Verifiable Intent requires.

UPI processed 21.70 billion transactions worth ₹28.33 lakh crore in January 2026 alone. It connects 691 banks on a single platform. Every UPI transaction is a structured data object: payer, payee, amount, timestamp, and metadata — flowing through APIs in JSON, processed in real time.

GSTN (GST Network) has processed over ₹102.91 lakh crore in payments. It handles B2B electronic invoicing for over a crore of taxpayers. Every invoice is a structured document with nested line items, tax breakdowns, and party details — exactly the kind of nested JSON structure that Verifiable Intent mandates.

The National Single Window System has integrated approvals across 32 Central Departments and 32 State Governments, granting over 8.29 lakh approvals through a single digital gateway. Each approval is a structured document flowing through APIs, with different departments seeing different subsets of the application data — which is functionally selective disclosure.

API Setu provides a unified platform for government departments, organizations, and developers to discover, access, and integrate APIs. It’s the plumbing that makes structured data flow between systems at national scale.

The pattern is consistent: structured, queryable, JSON-native data flowing through API-driven architectures where different parties see different subsets of the same underlying document. India built this for regulatory compliance. Verifiable Intent formalizes it cryptographically.

Press enter or click to view image in full size

The Regulatory Convergence: DPDPA Meets Verifiable Intent

India’s Digital Personal Data Protection Act (DPDPA), enacted in August 2023 with rules notified in November 2025, creates a regulatory framework that architecturally converges with Verifiable Intent in ways most teams haven’t recognized.

The DPDPA mandates consent that is “free, specific, informed, unconditional and unambiguous” — and organizations must maintain records demonstrating compliance. The law requires purpose limitation (data collected for a specific purpose cannot be used for other purposes), data minimization (collect only what’s necessary), and the ability for data principals to obtain a summary of their processed data.

These aren’t just legal requirements. They’re data modeling requirements.

Consent as a queryable document. Under DPDPA, you need to know: What did the user consent to? When? For what purpose? Which specific data fields? This is structurally identical to a Verifiable Intent L2 mandate — a document expressing the user’s authorized scope, with constraints on what can be done with their data.

Selective disclosure as data minimization. DPDPA’s data minimization principle says: share only what’s necessary for the specific purpose. Verifiable Intent’s selective disclosure says: each party sees only the claims relevant to its role. Same principle. Same architectural requirement. Different regulatory framing.

Purpose limitation as constraint enforcement. Under DPDPA, personal data processed for one purpose (e.g., identity verification) cannot be repurposed (e.g., marketing). Under Verifiable Intent, an agent authorized for checkout cannot exceed its mandate’s constraint boundaries. Both require the ability to query the original authorized scope and verify that current usage falls within it.

The teams that model consent, intent, and authorization as queryable documents — not as metadata flags on relational rows — will satisfy both the DPDPA’s compliance requirements and Verifiable Intent’s cryptographic requirements with the same underlying architecture.

The phased DPDPA enforcement timeline (consent manager registration by November 2026, full operational provisions by May 2027) gives teams a window to get this right. But the architectural decision needs to be made now.

Schema Design First. Payment Integration Second.

Most teams will encounter Verifiable Intent and immediately ask about API endpoints, SDK integration, and protocol compatibility. Those are implementation details. The foundational question is upstream of all of them:

Can your data model represent nested, selectively-disclosable claims as queryable, hashable documents?

Press enter or click to view image in full size

If yes, Verifiable Intent integration is a natural extension of your existing architecture. You model mandates as documents with nested constraint arrays. You implement selective disclosure as query projections. You verify cryptographic binding by hashing the serialized document.

If no — if intent lives in flat relational tables, or in unstructured comments, or in PDFs attached to approval workflows — you’ll be retrofitting. You’ll build translation layers between your internal data model and the SD-JWT JSON structures. You’ll maintain parallel representations. And every translation is a potential point of failure in a cryptographic verification chain where a single bit flip invalidates the hash.

The spec is on GitHub at agent-intent/verifiable-intent. Google, IBM, Fiserv, Checkout.com, and Worldpay have all signed on. The agentic commerce protocols are already live — OpenAI's Agentic Commerce Protocol since September 2025, Google's Universal Commerce Protocol since January 2026.

The trust layer just arrived. The teams that started with schema design — modeling intent as first-class, queryable, document-structured state — will own intent-driven transactions.

Everyone else will rebuild.

I would love to hear your thoughts and insights on this evolving avenue of regulatory compliance and disassociated authorisations.

--

--

Sangram Mohite
Sangram Mohite

Written by Sangram Mohite

Cloud Solution Architecture | AI/ML | UX | Product Management | Polymath | 🏳️‍🌈 Singer 🎤 Cat dad 🐈♥️ Movies and TV 🎥📺 Wildlife and Travel 🦁✈️