Extending UCP to Support PII

A Tokenized Approach to Sensitive Data in Agentic Commerce and Services

The Universal Commerce Protocol (UCP) introduced a durable pattern for agentic commerce: an AI agent can orchestrate a structured checkout flow while payment credentials remain outside the model context, represented only by opaque, tokenized instruments issued by a trusted payment handler. UCP also reduces "N×N" bespoke integrations through standardized capability discovery and negotiation.

This paper proposes extending that same pattern to Personally Identifiable Information (PII) including names, addresses, dates of birth, income and employment details, and other sensitive user data required to complete real-world workflows. The objective is simple: enable agents to complete high-friction tasks that require PII without ever exposing raw PII to the model layer.

This matters most for eCommerce and services platforms (for example, point-of-sale, invoicing, booking, commerce, and embedded-finance platforms). Many of the highest-value workflows with end-to-end processes that involve transaction of sensitive data, including HIPAA or other PII data, are not possible today without a secure way to handle this data. Without a standardized tokenized mechanism, platforms face an unacceptable choice: pass raw PII through an LLM context (risk and compliance exposure) or keep the user in repetitive manual loops (abandonment and lost revenue).

Our proposal is conservative and UCP-native: PII stays in a separate trust boundary (a PII vault or credential provider), the agent receives only token references (PII instruments), and service platforms resolve those tokens server-side under strict scope checks. UCP's capability negotiation ensures the extension is additive and non-breaking.

We demonstrate the extension via a reference implementation for agent-driven loan application flow, backed by a real PII vault (VGS — Very Good Security). Currently, the process for applying for and comparing rates from multiple loan providers is a repetitive process. While loan aggregators exist, they often prioritize the underwriters that provide the best economic incentives for the aggregating platform rather than the end customer. Given that most personal loans underwrite using substantially the same set information, we see this as a great opportunity for agentic disruption. TransUnion reports $276B in unsecured personal loan balances in Q4 2025, held across 26.4M consumers, with average debt per borrower of $11,699. Even a 10 bp improvement in interest rate applied across $276B outstanding implies roughly $276M/year in interest cost savings (back-of-the-envelope) for the consumer.

Extending UCP to Support PII

What is the problem we are trying to solve

If we want agents to handle the menial parts of our lives, we need to empower them to take actions on our behalf. Sometimes, this includes dealing with sensitive information that we don't want the model to use outside the exact context we prescribe.

1) The agentic "last mile" breaks on sensitive data

Agents are increasingly capable at planning and orchestrating multi-step action such as search, compare, fill forms, submit requests. However, agents often stall at the point where real workflows require sensitive inputs: identity verification (DOB, address history), underwriting (income, employment), regulated onboarding (KYC/AML), healthcare intake, and other services workflows.

2) The risk is architectural, not just operational

If raw PII is present in the model context, it can leak through prompt injection, accidental logging (traces, retries, analytics), conversation retention, or misrouted tool calls. Policies and redaction help, but the safer architecture is to ensure the agent never receives raw PII in the first place.

3) Existing approaches don't scale across the ecosystem

Without a common protocol, the ecosystem drifts into bespoke "PII vault APIs" per platform and provider, repeated user form entry, inconsistent consent semantics, and uneven security posture and auditability. UCP was created to reduce the "N×N integration bottleneck" through standardized negotiation and primitives; PII is the next bottleneck to solve in the same way.

Proposed Solution

We propose extending the data model used to handle payment information within UCP to handle additional types of sensitive information. UCP already has a proven architecture for payment credentials: the agent orchestrates, the user authorizes, a handler issues tokens, and the business backend completes the transaction. We extend this model for PII by introducing parallel primitives that mirror the payment pattern.

The reference implementation uses VGS (Very Good Security) as the PII vault, demonstrating that the protocol works with real infrastructure — not just mocks. The architecture ensures raw PII never touches the agent's server: it flows from the user's browser to the VGS vault via secure iframes, and from the vault to lender APIs via outbound proxy routes. The backend works exclusively with opaque alias tokens.

Design principles

  • Zero raw PII in the model layer. Agents only see opaque tokens and minimal routing metadata.
  • User-controlled, explicit consent at field-level and recipient-level (who gets what, for what purpose).
  • Capability negotiation and schema composition: if unsupported, nothing changes; if supported, the schema composes via extensions.
  • Auditable and enforceable policy: token issuance and resolution are scoped, time-bounded, and logged.
  • Handler independence: PII providers and domain handlers (lending, insurance, etc.) are separate concerns. The lending handler is PII-agnostic — it never knows how PII is stored or delivered.

Proposed primitives

  • PIIHandler (analogous to PaymentHandler): a trusted credential provider that collects/stores PII and mints tokens. Declared independently in the merchant profile under pii.handlers.
  • PIIInstrument (analogous to PaymentInstrument): an object carrying an opaque token credential plus scope metadata (fields, recipient).
  • PIIConsent: a formal consent record created by the UI layer and submitted to the vault for token minting and audit.
  • LendingHandler: a domain handler that manages lenders and loan applications. References PII handlers only indirectly — PII delivery is delegated entirely to the PII provider.

UCP-native transport semantics

UCP's A2A binding specifies that payment credentials are submitted as a structured DataPart under the attribute name a2a.ucp.checkout.payment_data. We extend this symmetry with a2a.ucp.checkout.pii_data, carrying one or more PIIInstrument objects (tokens only). Vertical-specific non-PII payloads (for example, loan amount or term preferences) are carried separately (for example, a2a.ucp.checkout.loan_application). This makes the extension easy to implement for teams already familiar with UCP checkout flows.

Profile and capability integration (non-breaking)

UCP uses a server-selects architecture and negotiates capabilities from the intersection of platform and business profiles published at /.well-known/ucp. We introduce two independent handler sections — pii.handlers for PII providers and lending.handlers for lending marketplaces — alongside a vertical capability extension (com.viaschema.lending) that extends dev.ucp.shopping.checkout. The PII handler section follows the same pattern as payment.handlers: it declares which providers the merchant supports without embedding implementation details. The lending handler declares loan type support without referencing PII providers — the two compose at runtime through the protocol, not through configuration coupling.

Benefits for platforms (e.g., Square) that adopt this extension

Adoption decisions are cross-functional. Successful adoption requires a story for Product, Engineering, Security, Legal, and the GM.

  • Business upside (GM + Product): enables agents to complete high-friction steps (intake, verification, financing), not just discovery; reduces form repetition and abandonment; unlocks monetization (embedded financing, onboarding services).
  • Risk reduction (Security + Legal): raw PII stays out of LLM context; token scope and audit logs provide enforceable controls and forensic clarity. With a real vault (VGS), PII never touches the merchant's server — it flows directly from browser to vault and from vault to recipient.
  • Low integration cost (Engineering): additive via capability negotiation; reuses UCP patterns (handlers, instruments, DataParts). The PII provider is swappable without touching domain logic.
  • Distribution alignment: UCP is positioned as an open standard for agentic commerce across major agent surfaces.
  • Product fit: many services platforms already offer financing and onboarding workflows, which benefit directly from tokenized PII exchange.

Sample Implementation

Shopping for a loan

Loan comparison is a representative "PII-first" workflow: it involves multiple recipients (many lenders), repeated form entry today, sensitive underwriting inputs, and strict consent and audit requirements.

The reference implementation uses VGS for PII tokenization with three data paths: VGS Collect JS (secure browser iframes for collection), VGS inbound routes (tokenize PII in transit before it reaches the backend), and VGS outbound routes (enrich aliases with real values when delivering to lender APIs). The backend never calls reveal() on aliases — PII delivery to lenders is handled entirely by the VGS outbound proxy.

End-to-end flow (5 phases)

Phase 1 — Discovery: The agent asks for the user's email and searches lenders by loan type; no PII is involved. Lenders are discovered dynamically via an API endpoint, mirroring how payment methods are discovered from payment handlers.

Phase 2 — Checkout initialization: The agent starts the lending flow with the user's email. The backend checks the PII vault for existing data and returns only the delta of missing fields. The checkout is extended with PII handlers, eligible lenders, required fields, and status. If the user has previously provided PII (for another loan type or a prior session), only the incremental fields are requested.

Phase 3 — PII collection + consent (UI ↔ vault, not LLM): The UI renders VGS Collect JS secure iframe fields — including date pickers, dropdowns for country/state, and zip-code validation — directly in the chat interface. PII data flows from the browser to the VGS vault via an inbound route that tokenizes values in transit. The backend receives only opaque VGS aliases. The user then reviews which lenders will receive their data and grants explicit, field-scoped consent. The vault mints platform-scoped tokens — one per lender.

Phase 4 — Token-based submission: The agent submits PII tokens (PIIInstruments) plus non-PII application fields. For each lender, the PII provider's forward_pii() method sends the aliases to the lender's API endpoint through the VGS outbound proxy, which enriches (detokenizes) the aliases in transit. The lender receives real PII; the backend never does. The lending handler is completely PII-agnostic — it just says "send this token's PII to this URL" and gets offers back.

Phase 5 — Comparison: Lenders return offers; the UI sorts and presents offers, with next-step URLs for completion.

Why this proves platform readiness

  • Agents can orchestrate a full workflow requiring PII without raw PII exposure — not just in theory (mocks), but with real vault infrastructure (VGS).
  • Consent is explicit, field-scoped, and recipient-scoped, enabling enforceable policy.
  • Multi-recipient tokenization works (one token per platform_id), enabling safe comparisons across many providers.
  • PII delivery to lenders uses VGS outbound routes — the backend never reveals aliases, ensuring zero PII in the merchant's memory.
  • Incremental collection across loan types works: applying for a car loan after a personal loan only requests the delta fields.
  • The PII provider and lending handler are fully independent — swapping VGS for a different vault requires no changes to lending logic.

Technical Considerations

Security

Security objective: ensure raw PII does not enter the model context and cannot be extracted by the agent, even under adversarial prompting.

Threat model and mitigations (representative)

  • Prompt injection / exfiltration: agent only receives opaque tokens; raw PII is never in-context.
  • Token replay: time-to-live (TTL) plus recommended one-time-use tokens or nonce binding for high-risk flows.
  • Token theft (client or transit): recipient/audience scoping plus authenticated token resolution (mTLS/OAuth) and short TTL.
  • Confused deputy / wrong recipient resolution: vault enforces platform_id match; tokens minted per platform.
  • Over-collection: field-level consent and standardized minimum field sets by use case.
  • Supply-chain attacks on collection scripts: VGS Collect JS loaded with Subresource Integrity (SRI) hash to detect tampering.
  • Backend PII exposure: VGS outbound routes handle lender delivery; the backend never calls reveal(). Raw PII exists only inside VGS infrastructure and in transit to the authorized lender endpoint.

Recommended production controls (beyond the reference implementation)

  • Resolve tokens only from authenticated services (no browser resolution).
  • Emit audit logs for token issuance and every resolution event.
  • Support key rotation and configurable TTL/usage policies.
  • Implement data residency controls for regulated markets.
  • Persist alias mappings in a durable store (the reference implementation uses in-memory storage).
  • Use per-lender VGS access credentials for defense-in-depth isolation.

Privacy

Privacy objective: users control what is shared, with whom, and for what purpose; sharing is reversible and traceable.

  • Explicit consent objects with purpose, field list, recipients, and timestamp.
  • Purpose limitation: tokens should bind to a declared purpose (e.g., "loan comparison").
  • Data minimization: share only required fields, not everything stored.
  • Revocation and retention: users can revoke active consents and request deletion in production deployments.

Extensibility

UCP's extensibility model is built around reverse-domain names and extension schemas. This extension scales across verticals via composable field sets (lending, insurance, healthcare, onboarding), multiple PII handlers per business, and non-breaking evolution using optional fields and new extension capabilities consistent with UCP's compatibility approach. The handler independence principle — PII providers and domain handlers are separate concerns — means a single VGS vault can serve lending, insurance, KYC, and bank account opening simultaneously, with separate consent decisions per domain.

Further possible investments

  • Production PII vault: SOC 2 controls, encryption and key rotation, configurable TTL and one-time tokens, and robust audit pipelines.
  • Consent management UX: dashboards for disclosures, revocation, export and deletion workflows.
  • Selective disclosure and attestations: share facts (e.g., "over 18") without sharing raw attributes.
  • Standardized field sets per vertical to reduce ambiguity and over-collection.
  • Per-lender VGS access credentials or per-lender alias sets for cryptographic isolation beyond application-level token scoping.
  • Conformance suite and interoperability testing (capability negotiation, token scope, A2A DataPart compliance).
  • Governance path: iterate under com.viaschema.* and propose an upstream dev.ucp.* extension once semantics stabilize.

Appendix A — Reference Implementation Highlights (selected excerpts)

The excerpts below illustrate the concrete mechanics behind the proposal. They are provided for implementer clarity and to demonstrate that the extension follows UCP's established patterns (handlers, instruments, negotiated schema composition).

A1) New A2A keys for PII and lending (constants)

# a2a/business_agent/src/business_agent/constants.py
UCP_LENDING_EXTENSION = "com.viaschema.lending"

UCP_CHECKOUT_KEY = "a2a.ucp.checkout"
UCP_PAYMENT_DATA_KEY = "a2a.ucp.checkout.payment_data"
UCP_RISK_SIGNALS_KEY = "a2a.ucp.checkout.risk_signals"

# Lending / PII data keys
ADK_PII_STATE = "__pii_data__"
UCP_PII_DATA_KEY = "a2a.ucp.checkout.pii_data"
UCP_PII_COLLECTION_KEY = "a2a.ucp.checkout.pii_collection"
UCP_LOAN_APPLICATION_KEY = "a2a.ucp.checkout.loan_application"

A2) Merchant profile declares independent PII and lending handlers

// a2a/business_agent/src/business_agent/data/ucp.json
{
  "ucp": {
    "capabilities": [
      {
        "name": "com.viaschema.lending",
        "version": "2026-01-11",
        "spec": "https://viaschema.com/specs/lending",
        "schema": "https://viaschema.com/schemas/lending/lending.json",
        "extends": "dev.ucp.shopping.checkout"
      }
    ]
  },
  "pii": {
    "handlers": [{
      "id": "vgs_pii_provider",
      "name": "vgs.pii.provider",
      "version": "2026-01-11"
    }]
  },
  "lending": {
    "handlers": [{
      "id": "marketplace_lending",
      "name": "marketplace.lending.provider",
      "version": "2026-01-11",
      "supported_loan_types": ["personal", "car"]
    }]
  }
}

The PII handler and lending handler are declared independently. The lending handler does not reference which PII handler is used — this separation is enforced by the architecture, not configuration.

A3) Capability negotiation composes a lending checkout type (non-breaking)

# a2a/business_agent/src/business_agent/helpers/type_generator.py
if UCP_LENDING_EXTENSION in active_capability_names:
    selected_base_models.append(LendingCheckout)

A4) BasePIIProvider: shared token/consent logic, storage-specific subclasses

# a2a/business_agent/src/business_agent/pii_provider.py
class BasePIIProvider(ABC):
    """Shared token issuance, validation, and consent logic."""

    def process_pii(self, pii_instrument): ...   # validate token
    def issue_token(self, user_email, ...): ...   # mint scoped token
    def issue_consent(self, user_email, ...): ... # process consent, mint per-lender tokens

    @abstractmethod
    def store_pii(self, user_email, pii_data): ...   # storage-specific
    @abstractmethod
    def resolve_token(self, token, platform_id): ... # storage-specific
    @abstractmethod
    def forward_pii(self, token, platform_id, url, extra_data): ... # delivery-specific

class MockPIIProvider(BasePIIProvider):
    """In-memory storage for testing."""
    ...

# a2a/business_agent/src/business_agent/vgs_pii_provider.py
class VGSPIIProvider(BasePIIProvider):
    """VGS vault storage. Aliases are tokenized via redact(), delivered via outbound proxy."""
    ...

A5) Formal consent and token instruments

# a2a/business_agent/src/business_agent/models/lending_types.py
class PIIConsent(BaseModel):
    pii_method_id: str
    handler_id: str
    fields_consented: list[str]
    loan_type: str
    platform_ids: list[str]
    consented_at: str

class PIIInstrument(BaseModel):
    id: str
    handler_id: str
    handler_name: str
    credential: PIICredential  # token only
    fields_stored: list[str] = []
    loan_type: str = "all"
    platform_id: str | None = None

A6) Vault issues platform-scoped, field-scoped tokens with TTL

# a2a/business_agent/src/business_agent/pii_provider.py (BasePIIProvider)
TOKEN_TTL_SECONDS = 3600  # 1 hour

def issue_token(self, user_email, platform_id="_default", fields=None) -> str:
    token = f"pii_token_{uuid.uuid4()}"
    allowed = frozenset(fields) if fields else frozenset(self.get_stored_fields(user_email))
    self._tokens[token] = TokenEntry(user_email, platform_id, time.time(), allowed)
    return token

A7) forward_pii: PII-agnostic delivery to lender APIs

# MockPIIProvider: resolves token and POSTs directly
def forward_pii(self, token, platform_id, url, extra_data=None):
    pii_data = self.resolve_token(token, platform_id)
    payload = {**pii_data, **(extra_data or {})}
    response = httpx.post(url, json=payload, timeout=30.0)
    return response.json()

# VGSPIIProvider: sends aliases through VGS outbound proxy (enriched in transit)
def forward_pii(self, token, platform_id, url, extra_data=None):
    aliases = {k: v for k, v in user_aliases.items() if allowed}
    payload = {**_unflatten_pii(aliases), **(extra_data or {})}
    response = self._http_client.post(url, json=payload)  # via VGS proxy
    return response.json()

The lending handler calls forward_pii() without knowing whether PII is stored in memory, VGS, or any other vault. It provides a token, a URL, and extra data; the PII provider handles secure delivery.

A8) Lending handler is PII-agnostic

# a2a/business_agent/src/business_agent/loan_provider.py
class MockLoanProvider:
    def generate_offers(self, pii_token, non_pii_info, loan_type):
        url = f"{self._lender_api_base}/{self.lender.platform_id}/apply"
        result = self._pii_provider.forward_pii(
            token=pii_token,
            platform_id=self.lender.platform_id,
            url=url,
            extra_data={"loan_type": loan_type, **non_pii_info},
        )
        return [LoanOffer(**o) for o in result.get("offers", [])]

A9) VGS Collect JS: secure PII collection in the chat UI

// a2a/chat-client/components/VGSPIICollectionForm.tsx
const form = window.VGSCollect.create(vaultId, environment, callback);

// Date picker for DOB
form.field('#vgs-date_of_birth', { type: 'date', name: 'date_of_birth', min: '1920-01-01' });

// Dropdown for country
form.field('#vgs-address-country', {
  type: 'dropdown', name: 'address_address_country',
  options: [{value: 'US', text: 'United States'}, ...], defaultValue: 'US'
});

// ZIP code with validation
form.field('#vgs-postal_code', { type: 'zip-code', name: 'address_postal_code' });

// Submit through VGS inbound route (tokenizes in transit)
form.submit('/pii/store', { data: (formValues) => ({ email: emailMarker, pii_data: ... }) });

All PII fields render as VGS Collect iframes — the browser JavaScript never accesses raw values. The VGS Collect JS library is loaded with an SRI integrity hash for supply-chain security.

A10) Frontend discovers PII handler dynamically

// a2a/chat-client/App.tsx
// PII handler discovered from checkout.lending.handlers (set from pii.handlers in ucp.json)
const handler = checkout.lending.handlers?.[0];

// VGS Collect config fetched from backend (vault ID stays server-side)
const vgsConfig = await piiProvider.current.getCollectConfig();

// Consent uses discovered handler ID (not hardcoded)
const consent: PIIConsent = {
  handler_id: piiHandler.id,  // dynamic
  fields_consented: lending?.required_pii_fields || [],
  platform_ids: lenders.map((l) => l.platform_id),
  ...
};

A11) Dependency injection: no import-time side effects

# a2a/business_agent/src/business_agent/dependencies.py
def create_lending_dependencies(store):
    """Called from main.py after load_dotenv(). No import-time side effects."""
    if os.environ.get("PII_PROVIDER") == "mock":
        provider = MockPIIProvider(handler_names=handler_names)
    else:
        provider = VGSPIIProvider(vault_id=..., http_client=proxy_client, ...)
    registry = LoanProviderRegistry(provider)
    manager = LendingCheckoutManager(store, provider, registry, ucp_meta)
    return provider, registry, manager