certilayer
Verify human sessions server-side in 3 lines.
The official Python SDK for CertiLayer — a fully async client for calling
CertiLayer's HCS (Human Confidence Score) API after your Web, iOS,
Android, or React Native SDK has captured a session. Gate critical
actions — login, checkout, signup, password changes — with a single
await.
Installation
pip install certilayer
Framework integrations are optional extras — install only what you need:
pip install certilayer[fastapi] # FastAPI dependency helper
pip install certilayer[django] # Django middleware
⚠️ Secret key — server-side only
CertiLayerClient takes your secret key
(certilayer_live_sk_... or certilayer_test_sk_...). This SDK is for
server environments only — never ship this key to a browser, mobile app,
or any client-side code. For the client side, use @certilayer/web (or
the iOS/Android/React Native SDK), which takes your public key instead.
Quick start
from certilayer import CertiLayerClient
client = CertiLayerClient(api_key="certilayer_live_sk_...")
result = await client.verify_session(session_id)
if result.verdict == "synthetic":
raise HTTPException(status_code=403, detail="bot_detected")
session_id is the session ID produced by whichever client-side SDK
(@certilayer/web, iOS, Android, or React Native) is running on the
same page/app the user is on.
Use the client as an async context manager, or call aclose() yourself
on shutdown:
async with CertiLayerClient(api_key="certilayer_live_sk_...") as client:
result = await client.verify_session(session_id)
Client configuration
CertiLayerClient(
api_key: str,
base_url: str = "https://api.certilayer.net/v1",
timeout_s: float = 10.0,
max_retries: int = 2,
)
| Parameter | Default | Notes |
|---|---|---|
api_key |
— | Required. Raises INVALID_API_KEY if empty. |
base_url |
https://api.certilayer.net/v1 |
Override only for self-hosted deployments. |
timeout_s |
10.0 |
Per-request timeout, in seconds. |
max_retries |
2 |
Retries 5xx and network errors with exponential backoff. 4xx errors are never retried. |
API reference
await client.verify_session(session_id, critical=False) -> VerifyResult
Full verification — returns score, verdict, and session metadata.
@dataclass(frozen=True)
class VerifyResult:
score: float # 0.0 – 1.0
verdict: HCSVerdict # 'human_verified' | 'human_likely' | 'synthetic'
session_id: str
scored_at: str # UTC ISO-8601
Pass critical=True immediately before a high-stakes action (payment,
password change, account mutation). This tells the policy engine to
apply stricter critical-action rules, which can escalate a grey-zone
score to a step-up challenge or session termination instead of a softer
response.
try:
await client.verify_session(session_id, critical=True)
except CertiLayerError as e:
if e.code == "STEP_UP_REQUIRED":
return prompt_webauthn()
raise
await client.quick_check(session_id, min_score=0.30, critical=False) -> QuickCheckResult
Lighter than verify_session() — just a pass/fail gate decision without
full session metadata.
@dataclass(frozen=True)
class QuickCheckResult:
score: float
verdict: HCSVerdict
passed: bool # True if score >= min_score
check = await client.quick_check(session_id)
if not check.passed:
return JSONResponse({"error": "bot_detected"}, status_code=403)
HCS verdict thresholds
| Verdict | Score range | Recommended action |
|---|---|---|
human_verified |
≥ 0.35 | Allow — high confidence |
human_likely |
0.30 – 0.35 | Soft friction / step-up auth |
synthetic |
< 0.30 | Block or challenge |
Unknown/future verdict strings from the API fall back to synthetic as
a safe default.
Framework integrations
FastAPI
from fastapi import Depends
from certilayer import CertiLayerClient
client = CertiLayerClient(api_key=settings.CERTILAYER_KEY)
guard = client.fastapi_dependency(min_score=0.90)
@app.post("/checkout", dependencies=[Depends(guard)])
async def checkout(): ...
client.fastapi_dependency(
session_header: str = "x-certilayer-session",
min_score: float = 0.30,
)
Reads the session ID from the given header and raises HTTPException(403)
if the check fails. Fails open (allows the request) if the CertiLayer
API call itself errors — a transient outage never blocks real users.
Django
# settings.py
client = CertiLayerClient(api_key=settings.CERTILAYER_KEY)
MIDDLEWARE = [
...
client.django_middleware(),
]
client.django_middleware(
session_header: str = "HTTP_X_CERTILAYER_SESSION",
min_score: float = 0.30,
reject_status: int = 403,
)
Note the header name uses Django's META convention — Django
automatically converts an x-certilayer-session HTTP header into
HTTP_X_CERTILAYER_SESSION. Like the FastAPI dependency, this fails
open on transient CertiLayer API errors.
Error handling
All SDK errors raise CertiLayerError with a machine-readable .code:
from certilayer import CertiLayerError
try:
result = await client.verify_session(session_id)
except CertiLayerError as e:
if e.code == "SESSION_NOT_FOUND":
return JSONResponse({"error": "session_expired"}, status_code=400)
raise
| Code | Meaning |
|---|---|
INVALID_API_KEY |
API key missing, empty, or rejected by the server |
SESSION_NOT_FOUND |
No session exists for the given session_id |
SESSION_EXPIRED |
Session exists but has exceeded its TTL |
STEP_UP_REQUIRED |
Policy engine requires additional verification (WebAuthn/OTP) |
SESSION_TERMINATED |
Policy engine has revoked this session as confidently synthetic |
RATE_LIMITED |
Too many requests — back off and retry |
NETWORK_ERROR |
Could not reach the CertiLayer API |
TIMEOUT |
Request exceeded timeout_s |
UNEXPECTED_ERROR |
Unclassified server or SDK error |
Requirements
- Python 3.9+
httpx(installed automatically as a dependency)
License
MIT
Support
- Docs: certilayer.net/docs
- Issues: please contact contact@certilayer.net
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file certilayer-1.0.0.tar.gz.
File metadata
- Download URL: certilayer-1.0.0.tar.gz
- Upload date:
- Size: 14.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f1fef05413a5b4ee1da877446189c5a6d8251346f872ff6170b165a10b8bde25
|
|
| MD5 |
fd887db1b49c79ed9f2e462a62ca1b12
|
|
| BLAKE2b-256 |
ace52d0e09d8c5abf679239b53b292c8da498d003575b70948ad0cba8f8f4bff
|
File details
Details for the file certilayer-1.0.0-py3-none-any.whl.
File metadata
- Download URL: certilayer-1.0.0-py3-none-any.whl
- Upload date:
- Size: 11.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6195376814ff1bbe571eddd17ddca73f68feddbb0697b7981d9e6938bd88aa5e
|
|
| MD5 |
d12cb70f84860fd3f48edc0104b57ea9
|
|
| BLAKE2b-256 |
233993ceef5d4cb57853e9cbf677667e0e3d8d4f328ee564eff95074a983dfba
|