Pulvan audits AI decisions for banks and fintechs — SHAP explainability, anomaly detection, and compliance-ready narratives. Plug in your model's outputs. Get answers in minutes.
Connect directly via OAuth. The browser pulls rows into memory, strips PII client-side, then sends only clean feature vectors to Pulvan.
Raw credentials and row contents never leave your browser tab's sandbox.
Enterprise connectors — contact us to enable. Self-hosted Pulvan instance recommended for direct DB connections inside a private VPC.
Copy this script into your Jupyter notebook, Databricks cell, or Snowflake worksheet. It runs entirely inside your secure perimeter — only the clean numeric payload is sent out.
import pandas as pd
import requests
# ── 1. Pull data inside your secure corporate perimeter ──────────────────────
raw_df = engine.execute("SELECT * FROM model_decisions LIMIT 500")
# ── 2. Drop PII columns in-memory — nothing identifiable crosses this line ───
pii_cols = ["customer_email", "pan_card", "phone_number", "user_id", "name"]
clean_df = raw_df.drop(columns=[c for c in pii_cols if c in raw_df.columns])
# ── 3. Structure as Pulvan AuditSubmit payload ────────────────────────────────
non_feature = {"decision_id", "outcome", "risk_score"}
decisions_payload = [
{
"external_ref": str(row.get("decision_id", "")),
"outcome": str(row.get("outcome", "UNKNOWN")),
"probability": float(row.get("risk_score", 0.0)),
"features": {
k: float(v) for k, v in row.items()
if k not in non_feature and isinstance(v, (int, float))
},
}
for row in clean_df.to_dict(orient="records")
]
# ── 4. Submit to Pulvan ────────────────────────────────────────────────────────
ORG_ID = "your-org-id" # from POST /orgs response
API_KEY = "your-api-key" # from POST /orgs response
MODEL_ID = 1 # from POST /orgs/{id}/models response
resp = requests.post(
f"https://your-pulvan-instance.com/orgs/{ORG_ID}/audit",
headers={"X-API-Key": API_KEY},
json={"model_id": MODEL_ID, "decisions": decisions_payload},
)
job = resp.json()
print("Audit submitted — Job ID:", job["job_id"])
# Poll GET /orgs/{ORG_ID}/audit/{job["job_id"]} every 2 s until status=complete
Tested with Python 3.9+. Requires pandas and requests.
For Databricks, replace engine.execute() with spark.sql().toPandas().
Paste a pre-structured JSON array of decisions. Drop all PII fields before pasting — only numeric features should be present.
Check any column containing names, emails, phone numbers, PAN, Aadhaar, account IDs, or any other personally-identifiable field. These never appear in the preview or the audit payload.
Running investigation…