Skip to main content

Preverus Python

Python client for Preverus backend enforcement.

Website: https://preverus.com
Documentation: https://preverus.com/docs

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://api.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")

user_risk_profile = client.lookup_user_risk_profile("acct_42")

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_KEY private.
  • Use a browser key only in templates/frontend code.
  • Prefer risk_session_token when present.
  • Include visitor_id as X-Visitor-ID through 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 review as step-up/manual review, not as automatic allow.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

preverus-0.1.2.tar.gz (10.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

preverus-0.1.2-py3-none-any.whl (8.8 kB view details)

Uploaded Python 3

File details

Details for the file preverus-0.1.2.tar.gz.

File metadata

  • Download URL: preverus-0.1.2.tar.gz
  • Upload date:
  • Size: 10.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.8.2

File hashes

Hashes for preverus-0.1.2.tar.gz
Algorithm Hash digest
SHA256 5e84f0a033e1a749e89f86867619e52ec15e5bf9d7002c90340999b7f8ee7770
MD5 d25eafe56297c8b141c07618d5024e81
BLAKE2b-256 13be38e6dfc2cb61bdc2790491e19a2a4b340e75793a8f202adee14edaefad9e

See more details on using hashes here.

File details

Details for the file preverus-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: preverus-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 8.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.8.2

File hashes

Hashes for preverus-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 e2cc83559705f6b44a5fc239bc284c33e59f48df7723a2586a5a833ac8dfba9b
MD5 43a30fa84474763f8b61c56e66299466
BLAKE2b-256 9e09d997ad2ee8d96d0af1d63bfa7f4bbb6a300de3da8bd6160154d077b935f4

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.2 This release

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page