# 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.