API Reference

Build on Clerk

Production-grade REST API for AML transaction monitoring, ML risk scoring, and compliance automation. Integrate Clerk's 8-phase compliance engine into your banking infrastructure in minutes.

Base URL https://vaultmind-6.polsia.app

🔑
Authentication

Clerk uses API key authentication via Bearer tokens. Include your API key in the Authorization header with every request. Generate keys from your dashboard. Keys are environment-scoped — your production key will not work against a staging environment.

🔐 Authorization Header

Include your API key in the Authorization header using the Bearer scheme. Keys are issued from your dashboard and must start with ck_live_. Example key format: ck_live_a1b2c3d4...

curl
curl -X GET \
  https://vaultmind-6.polsia.app/api/alerts/summary \
  -H "Authorization: Bearer ck_live_your_api_key_here" \
  -H "Content-Type: application/json"
⚠️ Keep your API key secret. Never expose it in client-side code or commit it to version control. Rotate keys immediately if compromised. Generate new keys from your dashboard. The full key is shown only once at creation time.

Managing API Keys

Create, list, and revoke API keys from the API Keys tab in your dashboard. Each key has:

  • Label — Descriptive name for identification
  • Permissions — Read and/or write access (JSONB)
  • Rate Limit — Requests per minute (default: 60)
  • Prefix — First 8 characters for identification without exposing full key

📥
Transaction Ingestion

Ingest transaction records for compliance monitoring. The same validation pipeline runs on both JSON and CSV uploads: format normalization, field validation, duplicate detection, and AML pre-screening. Accepted records are stored and made available for scanning and ML prediction.

POST /api/transactions/ingest Batch JSON transaction upload

Accepts a single transaction object or an array of transactions. Also accepts a { transactions: [...] } wrapper. Each record is validated, normalized (currency, dates, fields), and deduplicated before insertion. Returns a per-record error breakdown for any rejected rows.

Request Body — Transaction Object
FieldTypeRequiredDescription
transaction_id string optional Your internal transaction ID. Used for deduplication. Recommended.
account_id string required Account identifier initiating the transaction.
amount number required Transaction amount. Negative values indicate debits. Stored as absolute value internally.
currency string optional ISO 4217 currency code (e.g. USD, EUR). Defaults to USD.
transaction_type string required One of: wire, ACH, cash, check, transfer.
transaction_date string required ISO 8601 date or datetime (e.g. 2025-03-15 or 2025-03-15T09:30:00Z).
counterparty_name string optional Name of the receiving party. Used in OFAC and PEP screening.
counterparty_country string optional ISO 3166-1 alpha-2 country code of counterparty. Influences geographic risk scoring.
description string optional Free-text transaction memo or reference.
curl — Batch Ingest
curl -X POST \
  https://vaultmind-6.polsia.app/api/transactions/ingest \
  -H "Authorization: Bearer ck_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "transactions": [
      {
        "transaction_id": "TXN-001",
        "account_id": "ACC-12345",
        "amount": 9500.00,
        "currency": "USD",
        "transaction_type": "wire",
        "transaction_date": "2025-03-15T09:30:00Z",
        "counterparty_name": "Acme Holdings LLC",
        "counterparty_country": "US",
        "description": "Invoice settlement Q1"
      }
    ]
  }'
Node.js
const response = await fetch('https://vaultmind-6.polsia.app/api/transactions/ingest', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer ' + process.env.CLERK_API_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    transactions: [
      {
        transaction_id: 'TXN-001',
        account_id: 'ACC-12345',
        amount: 9500.00,
        currency: 'USD',
        transaction_type: 'wire',
        transaction_date: '2025-03-15T09:30:00Z',
        counterparty_name: 'Acme Holdings LLC',
        counterparty_country: 'US',
      }
    ]
  }),
});

const data = await response.json();
// { success: true, batch_id: "ingest_1742034600000", accepted: 1, rejected: 0, errors: [] }
Python
import os, requests

API_KEY = os.environ["CLERK_API_KEY"]
BASE = "https://vaultmind-6.polsia.app"

payload = {
    "transactions": [{
        "transaction_id": "TXN-001",
        "account_id": "ACC-12345",
        "amount": 9500.00,
        "currency": "USD",
        "transaction_type": "wire",
        "transaction_date": "2025-03-15T09:30:00Z",
        "counterparty_name": "Acme Holdings LLC",
        "counterparty_country": "US",
    }]
}

resp = requests.post(
    f"{BASE}/api/transactions/ingest",
    json=payload,
    headers={"Authorization": f"Bearer {API_KEY}"},
    timeout=30,
)
data = resp.json()
# {'success': True, 'batch_id': 'ingest_1742034600000', 'accepted': 1, 'rejected': 0}
Ruby
require 'net/http'
require 'json'
require 'uri'

uri  = URI('https://vaultmind-6.polsia.app/api/transactions/ingest')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

req = Net::HTTP::Post.new(uri)
req['Authorization'] = "Bearer #{ENV['CLERK_API_KEY']}"
req['Content-Type']  = 'application/json'
req.body = {
  transactions: [{
    transaction_id:   'TXN-001',
    account_id:       'ACC-12345',
    amount:           9500.00,
    currency:         'USD',
    transaction_type: 'wire',
    transaction_date: '2025-03-15T09:30:00Z',
    counterparty_name:    'Acme Holdings LLC',
    counterparty_country: 'US',
  }]
}.to_json

resp = http.request(req)
data = JSON.parse(resp.body)
# => {"success"=>true, "batch_id"=>"ingest_1742034600000", "accepted"=>1}
200 Success
{
  "success": true,
  "batch_id": "ingest_1742034600000",
  "accepted": 47,
  "rejected": 2,
  "errors": [
    {
      "index": 5,
      "errors": ["amount is required"]
    }
  ],
  "warnings": []
}
422 All Rejected
{
  "success": false,
  "batch_id": "ingest_1742034600001",
  "accepted": 0,
  "rejected": 3,
  "errors": [
    {
      "index": 0,
      "errors": [
        "account_id is required",
        "Invalid transaction_type"
      ]
    }
  ]
}
POST /api/transactions/upload CSV file upload

Accepts raw CSV content as a string in the csv field. The parser handles flexible header naming (e.g. trans_date, transaction_date, or date all map correctly). Same validation pipeline as /ingest.

Request Body
FieldTypeRequiredDescription
csv string required Raw CSV content as a string. First row must be headers. Flexible header mapping — column names are normalized automatically.
Supported CSV Headers
Canonical FieldAccepted Column Names
account_id account_id, account, acct_id
amount amount, amt, transaction_amount
transaction_date transaction_date, date, trans_date, tx_date
transaction_type transaction_type, type, tx_type
curl — CSV Upload
curl -X POST \
  https://vaultmind-6.polsia.app/api/transactions/upload \
  -H "Authorization: Bearer ck_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "csv": "account_id,amount,transaction_type,transaction_date,counterparty_country\nACC-001,9500,wire,2025-03-15,US\nACC-002,12000,ACH,2025-03-15,DE"
  }'
Node.js — Read file and upload
import fs from 'fs';

const csv = fs.readFileSync('./transactions.csv', 'utf8');

const response = await fetch('https://vaultmind-6.polsia.app/api/transactions/upload', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer ' + process.env.CLERK_API_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ csv }),
});

const { accepted, rejected, errors } = await response.json();
console.log(`Ingested ${accepted} rows, rejected ${rejected}`);
Python
import os, requests

with open("transactions.csv") as f:
    csv_content = f.read()

resp = requests.post(
    "https://vaultmind-6.polsia.app/api/transactions/upload",
    json={"csv": csv_content},
    headers={"Authorization": f"Bearer {os.environ['CLERK_API_KEY']}"},
    timeout=60,
)
result = resp.json()
print(f"Ingested {result['accepted']} rows, rejected {result['rejected']}")
Ruby
require 'net/http'
require 'json'

csv_content = File.read('transactions.csv')
uri  = URI('https://vaultmind-6.polsia.app/api/transactions/upload')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

req = Net::HTTP::Post.new(uri)
req['Authorization'] = "Bearer #{ENV['CLERK_API_KEY']}"
req['Content-Type']  = 'application/json'
req.body = { csv: csv_content }.to_json

result = JSON.parse(http.request(req).body)
puts "Ingested #{result['accepted']} rows, rejected #{result['rejected']}"

🔍
Compliance Scanning

Run AML detection across all ingested transactions. Clerk's 8-phase rules engine checks for structuring, rapid fund movement, geographic risk, velocity anomalies, and round-number patterns. Scan results are returned immediately and persisted for audit.

POST /api/scan Trigger full AML scan

Runs the full rule-based AML detection engine across all transactions in the database. Scores flagged transactions, creates alert records, and fires email notifications if thresholds are exceeded. No request body required.

curl
curl -X POST \
  https://vaultmind-6.polsia.app/api/scan \
  -H "Authorization: Bearer ck_live_your_key_here"
Node.js
const response = await fetch('https://vaultmind-6.polsia.app/api/scan', {
  method: 'POST',
  headers: { 'Authorization': 'Bearer ' + process.env.CLERK_API_KEY },
});

const result = await response.json();
// { success: true, scanned: 1240, flagged: 18, alerts_created: 7, high_risk: 3, duration_ms: 412 }
Python
import os, requests

resp = requests.post(
    "https://vaultmind-6.polsia.app/api/scan",
    headers={"Authorization": f"Bearer {os.environ['CLERK_API_KEY']}"},
    timeout=120,
)
result = resp.json()
# {'success': True, 'scanned': 1240, 'flagged': 18, 'alerts_created': 7, 'high_risk': 3}
print(f"Flagged {result['flagged']} of {result['scanned']} transactions")
Ruby
require 'net/http'
require 'json'

uri  = URI('https://vaultmind-6.polsia.app/api/scan')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.read_timeout = 120

req = Net::HTTP::Post.new(uri)
req['Authorization'] = "Bearer #{ENV['CLERK_API_KEY']}"

result = JSON.parse(http.request(req).body)
# => {"success"=>true, "scanned"=>1240, "flagged"=>18, "alerts_created"=>7}
puts "Flagged #{result['flagged']} of #{result['scanned']} transactions"
200 Success
{
  "success": true,
  "scanned": 1240,
  "flagged": 18,
  "alerts_created": 7,
  "high_risk": 3,
  "duration_ms": 412
}
Response Fields
scannedTotal transactions evaluated
flaggedUnique transactions flagged
alerts_createdNew alert records created
high_riskAlerts with risk_score ≥ 75
duration_msScan wall-clock time (ms)
GET /api/alerts List compliance alerts (paginated)

Returns paginated compliance alerts sorted by risk score descending. Each alert includes the linked transaction details, severity classification, and review status. Supports filtering by severity, alert type, date range, and open-only mode.

Query Parameters
ParameterTypeDefaultDescription
page integer 1 Page number for pagination.
limit integer 25 Records per page. Max 100.
severity string Filter by severity: high (≥75), medium (50–74), low (<50).
alert_type string Filter by flag type (e.g. structuring, velocity, geographic_risk).
unreviewed_only boolean false When true, returns only open (unreviewed) alerts.
start_date string ISO 8601 date. Filter alerts created on or after this date.
end_date string ISO 8601 date. Filter alerts created on or before this date.
curl — High-risk open alerts
curl -G \
  https://vaultmind-6.polsia.app/api/alerts \
  -H "Authorization: Bearer ck_live_your_key_here" \
  --data-urlencode "severity=high" \
  --data-urlencode "unreviewed_only=true" \
  --data-urlencode "limit=50"
200 Success
{
  "success": true,
  "alerts": [
    {
      "id": 142,
      "transaction_id": 8834,
      "flag_type": "structuring",
      "risk_score": 88,
      "severity": "high",
      "status": "open",
      "description": "Multiple transactions just below $10,000 threshold within 7 days",
      "transaction_amount": 9800.00,
      "transaction_type": "cash",
      "counterparty_name": "Unknown",
      "created_at": "2025-03-15T11:22:00Z"
    }
  ],
  "pagination": {
    "page": 1, "limit": 50, "total": 14, "pages": 1
  }
}
GET /api/alerts/summary Aggregate alert statistics

Returns aggregate compliance statistics across all transactions. Useful for dashboard widgets and executive reporting. No parameters required.

curl
curl https://vaultmind-6.polsia.app/api/alerts/summary \
  -H "Authorization: Bearer ck_live_your_key_here"
200 Success
{
  "success": true,
  "total_transactions": 12400,
  "total_flagged": 238,
  "high_risk_count": 31,
  "open_count": 47,
  "reviewed_count": 191,
  "pct_reviewed": 80
}

🧠
ML Predictions

Clerk's v1.5 logistic regression model scores transaction risk in real time with SHAP-based explainability. Every prediction includes a human-readable audit trail — designed to meet BSA/AML examiner requirements for model transparency.

POST /api/predict Transaction risk scoring with SHAP explanations

Score a transaction's AML risk. Accepts either a transaction_id (existing DB record) or an inline transaction object for real-time scoring. Returns a 0–100 risk score, binary prediction, confidence, and SHAP feature attributions.

Request Body (one of two modes)
FieldTypeDescription
transaction_id integer Mode A: ID of an existing transaction in the database. Fetches full feature context (7-day/30-day velocity, counterparty history).
transaction object Mode B: Inline transaction object for scoring without storage. Fields: amount, transaction_type, transaction_date, counterparty_country, and optional velocity hints (tx_count_7d, avg_amount_30d).
curl — Score by transaction_id
curl -X POST \
  https://vaultmind-6.polsia.app/api/predict \
  -H "Authorization: Bearer ck_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "transaction_id": 8834 }'
curl — Inline transaction (pre-ingestion screening)
curl -X POST \
  https://vaultmind-6.polsia.app/api/predict \
  -H "Authorization: Bearer ck_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "transaction": {
      "amount": 9750.00,
      "transaction_type": "cash",
      "transaction_date": "2025-03-15T14:00:00Z",
      "counterparty_country": "IR",
      "tx_count_7d": 5,
      "avg_amount_30d": 2000
    }
  }'
Node.js
const response = await fetch('https://vaultmind-6.polsia.app/api/predict', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer ' + process.env.CLERK_API_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ transaction_id: 8834 }),
});

const { risk_score, prediction, top_reasons } = await response.json();

if (risk_score > 75) {
  console.log(`HIGH RISK: ${top_reasons[0]}`);
  // → "HIGH RISK: Amount near BSA reporting threshold with high velocity"
}
Python
import os, requests

resp = requests.post(
    "https://vaultmind-6.polsia.app/api/predict",
    json={"transaction_id": 8834},
    headers={"Authorization": f"Bearer {os.environ['CLERK_API_KEY']}"},
    timeout=30,
)
data = resp.json()

if data["risk_score"] > 75:
    print(f"HIGH RISK ({data['risk_score']}): {data['top_reasons'][0]}")
    # HIGH RISK (88): Amount near BSA reporting threshold
Ruby
require 'net/http'
require 'json'

uri  = URI('https://vaultmind-6.polsia.app/api/predict')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

req = Net::HTTP::Post.new(uri)
req['Authorization'] = "Bearer #{ENV['CLERK_API_KEY']}"
req['Content-Type']  = 'application/json'
req.body = { transaction_id: 8834 }.to_json

data = JSON.parse(http.request(req).body)

if data['risk_score'] > 75
  puts "HIGH RISK (#{data['risk_score']}): #{data['top_reasons'].first}"
  # HIGH RISK (88): Amount near BSA reporting threshold
end
200 Success
{
  "success": true,
  "transaction_id": 8834,
  "prediction": 1,        // 1 = suspicious, 0 = clean
  "confidence": 0.91,
  "risk_score": 88,
  "explanation_text": "Transaction flagged for potential structuring. Amount is in structuring range ($8,000–$9,999) with 5 similar transactions in past 7 days.",
  "top_reasons": [
    "Amount near BSA reporting threshold",
    "High 7-day transaction count",
    "Counterparty in high-risk jurisdiction"
  ],
  "shap_values": {
    "structuring_signal": 0.34,
    "tx_count_7d": 0.28,
    "counterparty_risk_score": 0.21,
    "is_structuring_range": 0.18
  },
  "model_version": "v1.5.0"
}
GET /api/model-card ML model transparency card

Returns the full model card for Clerk's active ML model — including architecture, training dataset size, performance metrics (AUC, Recall, Precision, F1), feature list, and known limitations. Formatted for regulatory disclosure and examiner review.

curl
curl https://vaultmind-6.polsia.app/api/model-card \
  -H "Authorization: Bearer ck_live_your_key_here"
200 Success
{
  "model_name": "Clerk AML Classifier",
  "version": "v1.5.0",
  "architecture": "Logistic Regression (class-weighted SGD)",
  "features_count": 20,
  "training_dataset_size": 617,
  "metrics": {
    "auc": 0.91,
    "recall": 0.84,
    "precision": 0.48,
    "f1": 0.62
  },
  "features": [
    "amount_usd", "log_amount", "is_over_bsa_threshold",
    "structuring_signal", "tx_count_7d", "counterparty_risk_score",
    "geo_risk_velocity", "velocity_vs_baseline_ratio",
    // ... 12 more features
  ],
  "last_trained": "2025-03-01T00:00:00Z"
}
GET /api/monitoring/drift Population Stability Index (PSI) drift status

Returns PSI (Population Stability Index) drift scores for all model features. PSI <0.1 = stable, 0.1–0.25 = minor drift (monitor), >0.25 = significant drift (retrain recommended). Clerk automatically alerts when any feature exceeds the 0.25 threshold.

curl
curl https://vaultmind-6.polsia.app/api/monitoring/drift \
  -H "Authorization: Bearer ck_live_your_key_here"
200 Success
{
  "success": true,
  "computed_at": "2025-03-15T06:00:00Z",
  "overall_status": "stable",
  "features": {
    "amount_usd": { "psi": 0.04, "status": "stable" },
    "tx_count_7d": { "psi": 0.11, "status": "monitor" },
    "counterparty_risk_score": { "psi": 0.03, "status": "stable" }
  },
  "retrain_recommended": false
}

⚙️
System Management

Operational controls for system mode, emergency kill switch, audit trail access, and regulatory fairness testing. These endpoints are typically called by compliance officers and integration engineers — not on the transaction hot path.

GET /api/system/status Current system mode

Returns the current operating mode of the Clerk compliance engine. In full_ai mode, both ML predictions and rule-based scanning are active. In rules_only mode, the kill switch has been engaged and ML predictions are disabled — the rules engine continues to operate.

curl
curl https://vaultmind-6.polsia.app/api/system/status \
  -H "Authorization: Bearer ck_live_your_key_here"
200 Normal operation
{
  "success": true,
  "mode": "full_ai",
  "kill_switch_active": false,
  "ml_enabled": true,
  "rules_enabled": true,
  "uptime_hours": 720
}
Kill switch engaged
{
  "success": true,
  "mode": "rules_only",
  "kill_switch_active": true,
  "kill_switch_reason": "Drift threshold exceeded",
  "ml_enabled": false,
  "rules_enabled": true
}
POST /api/system/kill-switch Emergency disable ML predictions

Activates or deactivates the ML kill switch. When enabled, all /api/predict calls are blocked and the system falls back to rules-only mode. The rules engine remains fully operational. All kill-switch state changes are written to the immutable audit trail.

Request Body
FieldTypeRequiredDescription
enabled boolean required true to activate kill switch (disable ML), false to restore full AI mode.
reason string optional Human-readable reason for the state change. Recorded in audit trail.
activated_by string optional Identity of the operator. Defaults to "operator". Recorded in audit trail.
curl — Engage kill switch
curl -X POST \
  https://vaultmind-6.polsia.app/api/system/kill-switch \
  -H "Authorization: Bearer ck_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "enabled": true,
    "reason": "Unusual model behavior detected during Q1 audit",
    "activated_by": "jane.doe@bank.com"
  }'
200 Success
{
  "success": true,
  "kill_switch_active": true,
  "mode": "rules_only",
  "message": "Kill switch engaged. ML predictions disabled. Rules engine operational.",
  "timestamp": "2025-03-15T14:00:00Z"
}
GET /api/audit-trail Paginated audit log

Returns a paginated, immutable audit trail of all compliance actions — human reviews, kill switch changes, alert dismissals, SAR filings, and model decisions. Each entry includes the actor, action, timestamp, and linked transaction/flag IDs. Required for BSA/AML examiner access.

Query Parameters
ParameterTypeDefaultDescription
page integer 1 Page number.
limit integer 50 Records per page. Max 200.
start_date string Filter entries from this date (ISO 8601).
end_date string Filter entries until this date (ISO 8601).
curl
curl -G \
  https://vaultmind-6.polsia.app/api/audit-trail \
  -H "Authorization: Bearer ck_live_your_key_here" \
  --data-urlencode "start_date=2025-01-01" \
  --data-urlencode "limit=100"
200 Success
{
  "success": true,
  "entries": [
    {
      "id": 501,
      "action": "human_review",
      "actor": "compliance.officer@bank.com",
      "flag_id": 142,
      "transaction_id": 8834,
      "decision": "escalated",
      "notes": "Referred to SAR team for review",
      "timestamp": "2025-03-15T16:45:00Z"
    }
  ],
  "pagination": { "page": 1, "limit": 100, "total": 1204, "pages": 13 }
}
GET /api/fairness/latest Bias testing results

Returns the most recent fairness analysis report. Clerk runs automated bias testing across demographic and geographic groups to detect disparate impact. Results include flag rate parity, false positive rate parity, and overall fairness verdict. Required for SR 11-7 model risk management compliance.

curl
curl https://vaultmind-6.polsia.app/api/fairness/latest \
  -H "Authorization: Bearer ck_live_your_key_here"
200 Success
{
  "success": true,
  "report_date": "2025-03-15",
  "overall_verdict": "pass",
  "metrics": {
    "flag_rate_parity": { "max_ratio": 1.18, "threshold": 1.25, "pass": true },
    "false_positive_parity": { "max_ratio": 1.09, "threshold": 1.25, "pass": true }
  },
  "groups_analyzed": 8,
  "transactions_analyzed": 12400
}

⚠️
Error Codes

Clerk uses conventional HTTP status codes. All error responses include a success: false flag and a message field with a human-readable description.

Status Meaning Common Causes
400 Bad Request Missing required fields, malformed JSON, empty CSV
401 Unauthorized Missing or invalid Authorization header (use Bearer ck_live_...)
404 Not Found transaction_id does not exist in database
422 Unprocessable Entity All transactions in batch failed validation
500 Internal Server Error Database error or unexpected server fault. Contact support.
503 Service Unavailable ML model not trained yet. Call POST /api/model/train first.
Error Response Shape
{
  "success": false,
  "message": "transaction_id 99999 not found"
}