Start
What Integra Lens checks, and what you build for each stage
Lens rubric 0.3.0 groups its checks into ladders (R1, R2 …). A stage needs the first rungs of certain ladders. Each tab here lists those checks, the fix, and this shop's working code.
| 1 · Discoverable | R1.2 product data in the served HTML · R3.2 admit self-identified agents |
| 2 · Agreeable | R4.2–R4.5 terms · R7.2 legal name · R8.2 product identifier · R9.2–R9.4 price, tax basis, total. Needs Discoverable. |
| 3 · Transactable | R2.2–R2.3 a checkout an agent completes without a browser. Needs Discoverable. |
| 4 · Provable | R10.2–R10.3 an agreement record (ATR) per sale · R6.2 the buyer's payment signature covers its hash. Needs Agreeable and Transactable. |
Three ways to build it
| By hand | Stages 1 and 2 are static files and page markup. This shop does both; copy from the tabs. |
| Integra's appliance | Stage 4 for your own checkout: it issues the ATR and checks the payment (tab 4). Your checkout still needs an agent protocol for stage 3 (tab 3). |
| Integra Demo Studio | All four at once, on test networks: describe a shop and it is generated with every check in place. Use it to see a passing reference before you build. |
This shop passes 1 and 2. Its Studio-built version passes all four.
Check a site ↗The full rubric ↗This shop's report ↗
Stage 1
Discoverable
| R1.2 | Can an agent read a product and its price without a browser? Fix: JSON-LD Product with an Offer on every product page, in the HTML as served, not injected by script. |
| R3.2 | Does the site answer an agent that says what it is? Fix: serve clients that identify themselves in User-Agent; rate-limit them rather than challenge them with a CAPTCHA. |
This shop's product markup (trimmed)
<script type="application/ld+json">
{ "@context": "https://schema.org", "@type": "Product",
"name": "Wear the Standard Sweatshirt",
"sku": "standard-sweatshirt",
"offers": { "@type": "Offer",
"price": "17.87", "priceCurrency": "USD",
"url": "https://integralens.store/products/standard-sweatshirt" } }
</script>
price is a plain decimal string (no symbol), priceCurrency an ISO 4217 code. Next rungs: R1.3 a downloadable catalog (this shop serves /products.json), R1.4 a UCP business profile with the catalog capability.
Stage 2
Agreeable
| R4.2 | Terms found and readable without a browser. Fix: serve them in the delivered HTML or as a file. |
| R4.3 | The terms state their effective or last-changed date. |
| R4.4 | Each version has an identifier and a stable URL. |
| R4.5 | Byte-identical across fetches. Fix: a static file, no per-request content. |
| R7.2 | The seller's legal entity, machine-readable. Fix: Organization with legalName. |
| R8.2 | Each product carries an identifier an agreement can name: sku, or better a gtin. |
| R9.2–R9.4 | price and priceCurrency on every offer; priceSpecification.valueAddedTaxIncluded; delivery cost in shippingDetails. |
The terms: LCP's discovery file
Publish the terms as one static file, take the SHA-256 of its exact bytes, and point to both from /.well-known/legal-context.json. This satisfies R4.6–R4.8 too.
{ "terms": "https://integralens.store/terms.md",
"termsFormat": "markdown",
"atrHash": "0x9e3a5c3e…9deb6b03",
"contact": { "legal": "legal@integraledger.com" } }
curl -s https://integralens.store/terms.md | sha256sum
The first lines of /terms.md give R4.3 and R4.4: Version 1.2. Last updated: October 4, 2026. Change the terms and you publish a new version and a new hash.
Seller and price, in the same JSON-LD
"offers": { …,
"priceSpecification": { "@type": "UnitPriceSpecification",
"price": "17.87", "priceCurrency": "USD",
"valueAddedTaxIncluded": false },
"shippingDetails": { "@type": "OfferShippingDetails",
"shippingRate": { "@type": "MonetaryAmount", "value": "4.99", "currency": "USD" } },
"priceValidUntil": "2026-12-31" },
"seller": { "@type": "Organization",
"name": "Integra Ledger, Inc.", "legalName": "Integra Ledger, Inc." }
Next rung for the seller, R7.3: add a register identifier (an LEI, EU VAT number, CIK, UK company number or ABN) beside legalName.
The LCP specification ↗
Stage 3
Transactable
| R2.2 | Can an agent start a purchase without a browser? Cart links count, but an agent protocol (R2.3) is the real fix. |
| R2.3 | Can it complete one? Fix: publish the UCP checkout capability, or ACP's discovery document. |
| R2.4 | Next rung: accept a payment built for agents: x402, MPP or L402, or AP2 mandates through UCP. |
What a passing shop exposes
The Studio-built version of this shop passes, so it is a working reference. Its agent surfaces:
| UCP | checkout over REST (/checkout-sessions) and over MCP (create_checkout … complete_checkout) |
| x402 | /buy/<offer> answers 402 with a payment challenge |
| A2A | an agent card at /.well-known/agent-card.json |
| MPP, AP2 | the same checkout, paid with MPP's credential or AP2's mandates |
Its /llms.txt documents every one of these entry points, with the headers and payloads an agent sends. This shop's own checkout is not open yet, so it stops at Agreeable.
The passing reference ↗Generate your own ↗
Stage 4
Provable
| R10.2 | Each sale offers one agreement record (ATR) whose bytes hash to the value advertised with the payment request. |
| R10.3 | The ATR contains the published terms' digest. |
| R6.2 | The buyer's payment signature covers the ATR's hash. On x402 exact with EIP-3009, the hash is the authorization's nonce. |
With Integra's appliance, beside your checkout
Your backend calls the appliance's seller door (bearer credential isk_…, server to server only):
POST /issue
{ "mintRequestId": "order-1042:v1",
"resource": "checkout",
"lifetimeSeconds": 300,
"offers": [{ "pairing": "x402/exact/eip155/eip3009",
"option": { "scheme": "exact", "network": "eip155:84532",
"amount": "17870000", "asset": "0x036C…CF7e",
"payTo": "0x…", "maxTimeoutSeconds": 300 } }],
"request": { "method": "POST", "path": "/pay", "query": "",
"bodyDigest": "0x…" },
"content": [{ "slot": "terms", "bytes": "<base64 of the terms JSON>" }] }
It writes the ATR to your storage and answers with atrHash, link and carriers: the hash as lcp:sha256:0x… and as a legalContext object, ready to place in your payment request. Then:
POST /claim | with the buyer's payment: checks it carries the hash of a record you issued |
POST /report | paid or declined, with the transaction reference |
GET /status/<hash> | the record's state, and what it proves |
Or put the appliance in front: it serves the x402, MCP and A2A doors itself and asks your backend (its "seam") what to offer.
Run it locally first
The appliance's getting-started guide runs it in Docker with PostgreSQL 18 on Base Sepolia, a test network: you get a first 402, fetch the ATR it links to, and check its hash with sha256sum. No money moves and no licence is needed. Production networks and card rails need a licence.
A passing example
A test purchase from the Studio-built version of this shop. Fetch the record and hash it: you get the same value the payment carries.
curl -s https://atr.demos.integraledger.net/atr/0x50ecfbf0…1415134a | sha256sum
Its proof page ↗The ATR ↗The payment ↗Get the appliance ↗
How this shop was built
Four steps, each one you can check
- Generated by the Integra Demo Studio from one written description, in under five minutes:
- Finished: the real Integra Lens and LCP logos, a lighter look, and the products made in Printify and read from its API: names, prices, sizes and photos.
- Checkout through Integra's appliance, beside the shop's own checkout (stage 4's seller door):
/issue writes the agreement record, the buyer signs a USDC authorization whose nonce is its fingerprint, /claim checks it, the x402.org facilitator settles it on Base Sepolia, and /report records the transaction. Each record is served at /atr/<fingerprint>, and each paid order becomes a held TEST order in Printify.
- Checked with Integra Lens at every step.
Agents buy at /buy/<product>, listed in /openapi.json. People use the checkout page. Test money only.
Try the checkoutopenapi.json ↗
Your own demo
Build a shop like this in the Demo Studio
- Open a Studio. The Demo Studio pays in test USDC on Base Sepolia. The Circle Studio pays in test USDC on Arc, into your own Circle wallet.
- Circle only: make a wallet. Choose "Make a Circle wallet", then sign in by email. Circle makes a test wallet on Arc, and every demo you build pays it.
- Describe the shop in the chat: what it sells and at what prices, the seller's legal name, whether prices include tax, until when they hold, and the terms of sale. Lens checks each of these.
- Wait for the checks. The Studio tests every page at desktop and phone width, and every product through checkout as an agent shops, and repairs what fails.
- Publish, then press Run scenarios: Integra's buyer agent makes a real test purchase, and each one gets a proof page.
- Check it with Integra Lens.
A live example
The same merch shop, built in the Circle Studio and paid into a Circle wallet on Arc. Its first purchase, checked on chain:
The Circle shop ↗Its proof page ↗The payment on Arc ↗