Replies: 1 comment
-
|
Co-author here. This accurately reflects our technical discussion in #297 — the JWT structure, conditionHash canonicalization, and two-level gating model are all verified against the working implementation. Happy to answer questions on the attestation provider side. |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Authors: Almin Zolotic ([Zologic](https://zologic.nl) / [UCPReady](#297)) · Douglas Borthwick ([Skye Meta](https://skyemeta.com) / [InsumerAPI](https://insumermodel.com))
Summary
We propose a new UCP capability extension —
dev.ucp.shopping.eligibility— that enables businesses to declare machine-readable product preconditions in their UCP manifest and product catalog. AI agents can discover these conditions, obtain signed attestations autonomously, and satisfy them at checkout without human interaction.Motivation
UCP currently has no mechanism for a business to declare that a product requires proof of eligibility before it can be purchased. This gap affects a wide range of real commerce scenarios:
Today these requirements are enforced by human-interactive flows (a person clicks "Connect Wallet" or "Verify Identity" in a browser). AI agents cannot participate — they can discover the product but cannot obtain or present the required proof autonomously.
The result is that gated commerce is entirely excluded from the agentic commerce ecosystem UCP is building.
Prior Art
This proposal builds on the
attestation_urlpattern contributed to [KCP RFC-0004: Trust, Provenance, and Compliance](https://github.com/Cantara/knowledge-context-protocol/blob/main/RFC-0004-Trust-and-Compliance.md), which defines how AI agents discover and satisfy credential requirements before accessing structured knowledge. The pattern is mechanism-agnostic — on-chain tokens, Verifiable Credentials, OIDC, and SPIFFE all fit. We apply the same principle to commerce: conditions are declared in the manifest, attestations are obtained by the agent, verification happens server-side.Proposed Design
1. Capability declaration in
/.well-known/ucpThe
jwks_uripoints to the public key set used to verify attestation JWTs offline. Theprecondition_fieldtells agents where to include the JWT in their checkout request. The manifest declares the capability exists — the product declares the specific conditions.2. Product-level
eligibilityblock in catalog responses{ "id": "product_123", "title": "Wholesale Bundle", "price": 49900, "in_stock": true, "eligibility": { "gate_level": "purchase", "attestation_provider": "https://api.insumermodel.com/v1/attest", "conditions": [ { "type": "token_balance", "contractAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", "chainId": 1, "threshold": 500, "decimals": 6, "label": "Hold ≥500 USDC on Ethereum" } ] } }gate_levelhas two values:"discovery"— product is hidden from catalog entirely until attestation is presented"purchase"— product is visible with conditions declared, butcreate_checkoutrejects without a valid attestation JWTFor AI agents,
"purchase"is the correct default: the agent needs to see the conditions to know what attestation to obtain.3. Agent flow
No runtime call to the attestation provider at validation time — verification is entirely offline using cached public keys.
4. Attestation JWT structure (InsumerAPI reference implementation)
{ "sub": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "jti": "ATST-7F2A9E3B1C8D4056", "iat": 1742825600, "exp": 1742827400, "conditionHash": "0x3a7f...", "pass": true, "results": [ { "met": true, "chainId": 1, "type": "token_balance", "label": "Hold ≥500 USDC on Ethereum" } ] }conditionHashcanonicalisation (for independent verification):evaluatedConditionobject with fields:type,chainId,contractAddress,operator,threshold,decimalsJSON.stringifycompact (no whitespace)0xPHP (note:
ksort()sorts in place and returnsbool— two statements required):(Thanks to [@douglasborthwick-crypto](https://github.com/douglasborthwick-crypto) for catching the one-liner bug —
json_encode(ksort($condition), ...)would encodetrue, not the sorted array.)Backwards Compatibility
eligibilityis an optional field on catalog items — omitting it is valid for all existing retail implementationsdev.ucp.shopping.eligibilityis declared only when the capability is active — stores that don't use it have no manifest changes400with aprecondition_failedmessageReference Implementations
UCPReady (WooCommerce) — implements the business-side: manifest capability declaration, product
eligibilityblock surfacing, offline JWT validation viaucpready_checkout_preconditionsfilter, JWKS caching. Live endpoint: https://houseofparfum.nl/.well-known/ucpInsumerAPI / SkyeWoo (Skye Meta) — implements the attestation-provider side:
POST /v1/attestacross 32 chains, ES256-signed JWTs, JWKS at/.well-known/jwks.json, per-product condition configuration in WooCommerce via SkyeWoo plugin. Zero merchant registration required — conditions are declared per product, evaluated dynamically. MCP server available:npx -y mcp-server-insumerScope and Generalisability
The capability is deliberately mechanism-agnostic. The
attestation_providerURL on each product means any attestation provider can be used — on-chain token verification (InsumerAPI), Verifiable Credentials, OIDC identity tokens, Gitcoin Passport, or custom enterprise credential systems. The JWT structure withsub,jti,exp,conditionHash, andpassis a minimal standard that any provider can implement.This generalises beyond token-gating to:
All of these follow the identical agent flow: discover conditions → obtain attestation → present at checkout → validate offline.
Open Questions for the TC
gate_level: "discovery"require a separate query parameter for agents to present an attestation at catalog-query time, or is this out of scope for this proposal?jtireplay prevention be handled by the business (store thejtiand reject reuse) or by the attestation provider (single-use codes)? We've implemented both — UCPReady stores usedjtivalues with the session ID; InsumerAPI issues single-use attestations by default.We are both actively building on this — feedback and co-contributors welcome. Happy to draft a formal Enhancement Proposal if the TC finds this direction worth pursuing.
— Almin Zolotic ([zologic](https://github.com/zologic)) · Douglas Borthwick ([douglasborthwick-crypto](https://github.com/douglasborthwick-crypto))
Beta Was this translation helpful? Give feedback.
All reactions