Official Python SDK for Xident age and identity verification. Try it live at demo.xident.io.
pip install xidentRequires Python 3.9+.
from xident import Xident
client = Xident(api_key="sk_live_...")
# Create an init token
result = client.verification.init(
callback_url="https://example.com/callback",
min_age=18,
)
print(result.verify_url) # Redirect user here
# After callback, verify result server-side
session = client.verification.get_result("xtk_abc123")
if session.is_verified():
print(f"Verified! Age: {session.age_bracket()}+")from xident import AsyncXident
client = AsyncXident(api_key="sk_live_...")
result = await client.verification.init(
callback_url="https://example.com/callback",
min_age=18,
)
session = await client.verification.get_result("xtk_abc123")client = Xident(
api_key="sk_live_...", # Required: secret API key
base_url="https://...", # Override API URL
timeout=30, # Request timeout (seconds)
max_retries=3, # Retry on 5xx errors
headers={"X-Custom": "..."}, # Extra headers
)result = client.verification.init(
callback_url="https://example.com/callback", # Required
min_age=18, # Age threshold 1-99 (0-99 when purpose="id_verification")
success_url="...", # Override redirect on success
failed_url="...", # Override redirect on failure
user_id="user_42", # Your user identifier
theme="dark", # Widget theme (light, dark, system)
locale="de", # Widget locale
metadata="custom_data", # Opaque metadata string
purpose="age_verification", # "age_verification" (default) or "id_verification"
)
print(result.token) # "xit_abc123" (init token, 10-minute TTL)
print(result.verify_url) # Full URL to redirect user toAfter verification the widget redirects the browser back to callback_url with
query parameters: status (success | failed | cancelled — note the
British spelling, callback only), token (the result token xtk_..., which
is different from the init token xit_...), and user_id (if you supplied one).
Always re-verify the result server-side with get_result() — never trust the
callback query parameters alone.
session = client.verification.get_result("xtk_abc123")
session.is_verified() # True if completed successfully
session.is_failed() # True if verification failed
session.is_pending() # True if still in progress
session.is_terminal() # True if no more changes possible
session.age_bracket() # 18 (verified age threshold)
session.method() # "ml_fast", "ocr", etc.
session.country_code # "US", "DE", etc.
session.status # SessionStatus.COMPLETED# Verify and parse a webhook event
event = client.webhooks.construct_event(
payload=request_body, # Raw JSON string or bytes
signature=x_xident_signature, # X-Xident-Signature header
secret="whsec_...", # Webhook secret from dashboard
tolerance=300, # Max age in seconds (default: 5 min)
)
print(event["type"]) # "session.completed"
print(event["data"]) # Event payload dict
# Or verify signature only
client.webhooks.verify_signature(payload, signature, secret)from xident import (
XidentError, # Base for all errors
AuthenticationError, # 401/403
ValidationError, # 400
NotFoundError, # 404
RateLimitError, # 429 (has retry_after)
ServerError, # 5xx
NetworkError, # Connection failed
)
try:
result = client.verification.init(callback_url="...")
except AuthenticationError as e:
print(f"Bad API key: {e.error_code}")
except RateLimitError as e:
print(f"Rate limited, retry in {e.retry_after}s")
except NetworkError as e:
print(f"Connection failed: {e}")
except XidentError as e:
print(f"SDK error: {e}")# Auto-close HTTP client
with Xident(api_key="sk_live_...") as client:
result = client.verification.init(callback_url="...")
# Async
async with AsyncXident(api_key="sk_live_...") as client:
result = await client.verification.init(callback_url="...")See the examples/ directory for complete integrations:
- basic.py -- Pure Python
- flask_app.py -- Flask
- django_view.py -- Django
- fastapi_app.py -- FastAPI (async)
# Install dev dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Run tests with coverage
pytest --cov=xident
# Type checking
mypy src/xident
# Linting
ruff check src/ tests/MIT