Official Python SDK for the Lenz Claim Verification API for AI Product Teams.
Two API primitives for AI product teams. extract pulls verifiable
claims out of any text — free, 1000 calls/key/day. verify checks one
with a 7-model panel and citations, ~90s. Use them together or alone.
Built for teams whose AI output is async or document-shaped: legal-memo generators, deep-research products, due-diligence platforms, vertical agents producing structured deliverables. Not chat AI, not voice AI, not real-time copilots — pipeline runs are the wrong shape for those.
pip install lenz-iofrom lenz_io import Lenz
client = Lenz(api_key="lenz_...")
# 1. Pull factual claims out of your model output (free, instant)
claims = client.extract(text=llm_output).claims
# 2. Verify the ones that matter (~90s each, 7-model panel)
for claim in claims:
v = client.verify_and_wait(claim=claim).verdict
print(v.label, v.score, v.confidence)Frame → Collect Evidence → Debate (2 models, 2 rounds) → Adjudicate (3 models: sources, logic, context) → Conclude. ~90 seconds wall-clock per claim.
from lenz_io import Lenz
client = Lenz(api_key="lenz_...")
v = client.verify_and_wait(claim="Sharks don't get cancer")
print(v.verdict.label, v.verdict.score)
# false 2.0
for source in v.sources[:3]:
print(" -", source.title, source.url)The demo claim is pre-cached so this returns in ~1.5s. Your own claims hit the full pipeline (~60-90s) — use webhooks for production async flows.
Get your webhook secret here → lenz.io/api-integration
client.verify_and_wait(...)— submit + poll until the pipeline lands. Returns a typedVerification.client.verify(...)— async submit; returns atask_id. Use webhooks for the callback.client.extract(text=...)— pull verifiable claims out of any text (free, capped at 1000/key/day).client.verify_batch(claims=[...])— fan-out for multi-claim LLM outputs.client.verifications.{list,get,delete,set_visibility}(...)— manage past verifications.client.followup.{history,send,reset}(verification_id)— Q&A on a verification.client.library.{list,get}(...)— browse the public catalog (no API key needed).client.usage()— credits and rate-limit remaining.
from lenz_io import LenzWebhooks, VerificationCompleted, VerificationNeedsInput
webhooks = LenzWebhooks(secret="whsec_...")
# In your web handler:
event = webhooks.parse(raw_body=request.body, headers=request.headers)
if isinstance(event, VerificationCompleted):
vid, result = event.verification_id, event.result
...
elif isinstance(event, VerificationNeedsInput):
tid, ni = event.task_id, event.needs_input
...If you're on Python 3.10+ a match statement reads even cleaner — events are
plain dataclasses, so structural pattern matching works.
Signature verification is HMAC-SHA256 over the raw body; the SDK does it for you and rejects tampered or replayed payloads.
See examples/core/fastapi_webhook.py
for a runnable FastAPI receiver, and examples/core/verify_llm_output.py
for the headline extract-and-verify integration pattern.
Every error subclass is typed and carries a request_id you can quote on
support tickets:
from lenz_io import LenzAuthError, LenzRateLimitError, LenzValidationError
try:
client.verify_and_wait(claim="...")
except LenzAuthError as exc:
print(exc)
# Unauthorized
# Cause: Invalid api key
# Fix: Generate a new key at https://lenz.io/api-integration.
# Docs: https://lenz.io/docs/auth
# Request ID: req_abc123
except LenzRateLimitError as exc:
time.sleep(exc.retry_after)
except LenzValidationError as exc:
for field_err in exc.errors:
print(field_err["loc"], field_err["msg"])If a verify_and_wait call exceeds its timeout (default 120s) or your
process dies mid-poll, the pipeline keeps running. The exception carries the
task_id:
from lenz_io import LenzTimeoutError
try:
client.verify_and_wait(claim="...", timeout=30)
except LenzTimeoutError as exc:
print("resume later via:", exc.task_id)
# Later (different process / restart):
status = client.get_status("tsk_abc123")
if status.status == "completed":
print(status.result.verdict.label)verify_and_wait sends an auto-generated Idempotency-Key on every call by
default, so a network drop after submit doesn't spawn a duplicate verification
or charge a second credit. Override with idempotency_key="..." to pin a
specific key, or idempotency=False to opt out.
Lenz(
api_key="lenz_...", # or set LENZ_API_KEY env var
base_url="https://lenz.io/api/v1", # override for staging / local
timeout=30.0,
max_retries=3,
)Environment variables:
LENZ_API_KEY— read ifapi_key=is not passedLENZ_BASE_URL— read ifbase_url=is not passed
- Python 3.9, 3.10, 3.11, 3.12
- Works in CI/CD (no interactive prompts, no global state)
- Mockable for tests: every HTTP call goes through
httpx; userespxor inject your ownhttpx.ClientviaLenz(..., http_client=...)
github.com/lenzhq/lenz-io-python/issues
For commercial use, volume pricing, or onboarding support, get in touch.
MIT. See LICENSE.