# lemma.id: relying-site integration pointers for AI agents lemma.id is a **local-first proof layer** for relying sites: verify a signed presentation on your backend and get a site-private, stable `ppid` + assurance level. Use it for **person continuity under abuse**: one handle per human per site, optional **isHuman** step-up (one verified human per account on the same PPID), action stamps, and site-block so bans survive new accounts. Users mint presentations with a passkey. Passkey continuity is free and is not Sybil resistance by itself; require `ishuman` (IDV) when one human per account matters. Keep your existing login if you want; gate sensitive actions with lemma proofs. ## Start here - Continuity & abuse: https://lemma.id/docs/integration/CONTINUITY_AND_ABUSE.md - Quick start (gate an action): https://lemma.id/docs/integration/QUICK_START_SIMPLE_LOGIN.md - Integration guide (assurance, stamps, sessions): https://lemma.id/docs/integration/SIMPLE_INTEGRATION_GUIDE.md - Canonical integration contract (machine-oriented, authoritative): https://lemma.id/docs/integration/ISHUMAN_AGENT_INTEGRATION.md - Trust, recovery, availability: https://lemma.id/docs/integration/SIGN_IN_TRUST_AND_RECOVERY.md - Browser support + SDK error codes: https://lemma.id/docs/integration/BROWSER_SUPPORT.md - Human-readable docs: https://lemma.id/docs - Repo agent entrypoint (if working in the lemma-enterprise repo): AGENTS.md ## Gate a sensitive action (default integration path) Mint a presentation (passkey unlock in the lemma.id popup), verify locally, enforce by `ppid` and assurance: ```javascript const verifier = new ProofVerifier({ siteId: 'app.example.com' }); const { ok, presentation } = await verifier.verifyForBackend({ autoProvision: true, requiredAssurance: 'ishuman', // or 'passkey' for continuity-only }); if (!ok) throw new Error('not_verified'); await fetch('/api/claim-trial', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ presentation }), }); ``` Backend: verify the presentation locally with `@lemma.id/proof-verifier` or `lemma_proof_verifier.py`. No per-request call to lemma.id. Enforce policy on `result.ppid` and `result.assurance`; optionally call site-block APIs. ## Mint a presentation (browser UX) Drop-in button (same SDK; use on gated actions or optional login): ```html ``` ## Assurance ladder (same PPID) - `passkey`: continuity proof (daily unlock). Not Sybil-resistant alone. - `ishuman`: IDV-backed one human per account (Sybil-sensitive actions: trials, tickets, payouts, post-ban recovery) Request per action on client and backend; PPID does not change when upgrading tiers. ## Backend verifiers (local-first) - npm: `npm install "@lemma.id/proof-verifier@1.4.0"` (quote on PowerShell); TypeScript types included - Node/Workers: https://lemma.id/sdk/proof-verifier.mjs - Python: https://lemma.id/sdk/proof-verifier.py - PyPI: `pip install lemma-proof-verifier==1.4.0` - Offline test helpers (no WebAuthn/lemma.id needed in CI): `@lemma.id/proof-verifier/testing` and `lemma_proof_verifier_testing.py` ## Browser SDK notes - Create: `new ProofVerifier({ siteId: 'app.example.com' })` - Compatibility: `ishuman-verifier.js` and `IsHumanVerifier` remain supported aliases - Localhost dev works: `siteId` defaults to the page hostname; all localhost ports share the `localhost` binding ## Live demo - https://lemma.id/demo ## Hard rules 1. `siteId` = canonical hostname (`app.example.com`), not internal `site_...` IDs. 2. Fail closed when `human` is false. 3. For account binding and gated actions, verify a signed `presentation` on the server, never trust a bare client `ppid`. 4. No customer webhooks, no local identity seed (`wallet_secret`) on the developer's backend, no KYC field storage. ## Terminology Call the user-held object **lemma.id** (passkey-protected local credential store), not a "wallet." Internal APIs may still say `wallet_*`; that is engineering vocabulary, not product naming. ## Out of scope for relying-site integration Agent Ops (lemma-cli, Lemma Firewall, runtime control plane) is operator-only.