Python client for Preverus fraud decisions, events, lookups, and webhooks.
Project description
Preverus Python
Python client for Preverus backend enforcement.
Use this package with Django, Flask, FastAPI, or any Python backend that loads the hosted Preverus browser script on the frontend and needs trusted server-side fraud decisions.
Install
pip install preverus
Requires Python 3.9+.
Browser And Server Flow
Add the hosted script to your HTML template:
<script
src="https://cdn.preverus.com/v1/preverus.js"
data-preverus-key="pk_live_xxx"
data-preverus-auto="true"
data-preverus-track-forms="true"
></script>
<form method="POST" action="/register" data-preverus-action="signup">
<input name="email" type="email">
<button type="submit">Create account</button>
</form>
Before submit, the script attaches:
preverus_fingerprint
preverus_visitor_id
preverus_risk_session_token
preverus_browser_session_event_id
Your backend sends those values to Preverus with a private server key before approving sensitive actions.
Quick Start
import os
from preverus import Client
client = Client(os.environ["PREVERUS_SERVER_KEY"])
decision = client.decisions.evaluate(
{
"event_type": "signup",
"user_id": "acct_42",
"ip": request.remote_addr,
"risk_session_token": request.form.get("preverus_risk_session_token"),
"fingerprint": request.form.get("preverus_fingerprint"),
"metadata": {
"email": request.form.get("email"),
"browser_session_event_id": request.form.get("preverus_browser_session_event_id"),
},
},
visitor_id=request.form.get("preverus_visitor_id"),
idempotency_key="signup:acct_42:request-id",
)
if decision.is_block():
abort(403)
if decision.is_review():
return redirect("/verify")
# Continue signup.
Prefer risk_session_token when available. It links the backend action to the browser session collected moments earlier.
Configuration
client = Client(
os.environ["PREVERUS_SERVER_KEY"],
endpoint="https://api.preverus.com",
timeout=1.5,
retries=2,
retry_delay=0.15,
max_retry_delay=1.0,
)
The client retries transient network failures and retryable statuses:
408, 409, 425, 429, 500, 502, 503, 504
It does not retry validation or authentication errors such as 400, 401, 403, or 422.
Use idempotency keys for retried POST requests.
Django Example
from django.http import HttpResponseForbidden
from django.shortcuts import redirect
from preverus import Client
client = Client(settings.PREVERUS_SERVER_KEY)
def register(request):
decision = client.decisions.evaluate(
{
"event_type": "signup",
"user_id": request.POST.get("user_id"),
"ip": request.META.get("REMOTE_ADDR"),
"risk_session_token": request.POST.get("preverus_risk_session_token"),
"fingerprint": request.POST.get("preverus_fingerprint"),
"metadata": {
"email": request.POST.get("email"),
"user_agent": request.META.get("HTTP_USER_AGENT"),
},
},
visitor_id=request.POST.get("preverus_visitor_id"),
)
if decision.is_block():
return HttpResponseForbidden()
if decision.is_review():
return redirect("verify")
# Continue registration.
Flask Example
from flask import abort, redirect, request
from preverus import Client
client = Client(os.environ["PREVERUS_SERVER_KEY"])
@app.post("/withdraw")
def withdraw():
decision = client.decisions.evaluate(
{
"event_type": "withdraw",
"user_id": current_user.id,
"ip": request.remote_addr,
"risk_session_token": request.form.get("preverus_risk_session_token"),
"metadata": {
"payment_address": request.form.get("payment_address"),
},
},
visitor_id=request.form.get("preverus_visitor_id"),
)
if decision.is_block():
abort(403)
if decision.is_review():
return redirect("/withdraw/review")
Decisions
decision.recommended_action
decision.is_allow()
decision.is_review()
decision.is_block()
decision.to_dict()
Recommended handling:
allow -> proceed
review -> step-up auth, hold, or manual review
block -> deny or hard challenge
Events
Use events for non-blocking fraud telemetry:
event = client.events.create(
{
"event_type": "login",
"user_id": "acct_42",
"ip": "203.0.113.10",
"fingerprint": "fp_hash",
"metadata": {"email": "person@example.com"},
},
visitor_id="v_abc123",
)
Lookups
visitor = client.visitors.lookup(visitor_id="v_abc123")
visitor = client.visitors.lookup(fingerprint="fp_hash")
metadata = client.metadata.lookup("email", "person@example.com")
graph = client.metadata.graph("v_abc123")
Use lookups for investigation and context. Use decisions.evaluate() for final enforcement.
Webhook Verification
valid = client.webhooks.verify(
raw_body=request.get_data(),
timestamp=request.headers.get("X-Fraud-Webhook-Timestamp", ""),
signature_header=request.headers.get("X-Fraud-Webhook-Signature", ""),
secret=os.environ["PREVERUS_WEBHOOK_SECRET"],
)
if not valid:
abort(400)
Webhook delivery is at-least-once. Dedupe by X-Fraud-Webhook-Id or payload id.
You can also verify, parse, and dispatch by event type:
event = client.webhooks.construct_event(
raw_body=request.get_data(),
headers=dict(request.headers),
secret=os.environ["PREVERUS_WEBHOOK_SECRET"],
)
if already_processed(event.id):
return "", 204
client.webhooks.dispatch(
event,
{
"decision.high_risk": lambda event: open_case(event.payload),
"*": lambda event: log_webhook(event.type),
},
)
The client verifies and parses the event, but your app should store processed event IDs in your database or cache.
Failure Handling
The Python core client raises exceptions for API and network failures:
from preverus import ApiError, NetworkError
try:
decision = client.decisions.evaluate({...})
except ApiError as error:
print(error.status_code, error.error_code)
except NetworkError:
# Apply your app's fail-open, fail-review, or fail-closed policy.
For high-risk flows like withdrawals and payouts, a common policy is fail-review. For signup/login/checkout, many businesses prefer fail-open so the site keeps working during transient network failures.
Production Checklist
- Keep
PREVERUS_SERVER_KEYprivate. - Use a browser key only in templates/frontend code.
- Prefer
risk_session_tokenwhen present. - Include
visitor_idasX-Visitor-IDthrough the client argument. - Send your real customer account ID as
user_id. - Include IP and metadata such as email, phone, username, and payment address.
- Use idempotency keys for retried POST requests.
- Treat
reviewas step-up/manual review, not as automatic allow.
Project details
Release history Release notifications | RSS feed
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 preverus-0.1.0.tar.gz.
File metadata
- Download URL: preverus-0.1.0.tar.gz
- Upload date:
- Size: 10.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.8.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c0ab2fa452352633a91bbfc400bc8f84b556aa64007b26d42f4fd143465b40ac
|
|
| MD5 |
d5eda09448c0912b5a8903c6e4ffb60f
|
|
| BLAKE2b-256 |
5064b576b64a79ce4dc78b4499b13e398fefe755a906d27807c796aeb4502e70
|
File details
Details for the file preverus-0.1.0-py3-none-any.whl.
File metadata
- Download URL: preverus-0.1.0-py3-none-any.whl
- Upload date:
- Size: 8.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.8.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
63e03f3f55b1004582fee1205084dea0a8d9c450bdd4161493a5be23b6cfc47a
|
|
| MD5 |
47dc9ae483652d64190c21d8dd01429a
|
|
| BLAKE2b-256 |
a6e03234df69dc01c57a2cd51768991439ff6345a442b0fb38ab5889785a5c9b
|