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.
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 -X GET \
https://vaultmind-6.polsia.app/api/alerts/summary \
-H "Authorization: Bearer ck_live_your_api_key_here" \
-H "Content-Type: application/json"
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.
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.
| Field | Type | Required | Description |
|---|---|---|---|
| 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 -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"
}
]
}'
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: [] }
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}
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}
{
"success": true,
"batch_id": "ingest_1742034600000",
"accepted": 47,
"rejected": 2,
"errors": [
{
"index": 5,
"errors": ["amount is required"]
}
],
"warnings": []
}
{
"success": false,
"batch_id": "ingest_1742034600001",
"accepted": 0,
"rejected": 3,
"errors": [
{
"index": 0,
"errors": [
"account_id is required",
"Invalid transaction_type"
]
}
]
}
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.
| Field | Type | Required | Description |
|---|---|---|---|
| csv | string | required | Raw CSV content as a string. First row must be headers. Flexible header mapping — column names are normalized automatically. |
| Canonical Field | Accepted 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 -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"
}'
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}`);
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']}")
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.
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 -X POST \
https://vaultmind-6.polsia.app/api/scan \
-H "Authorization: Bearer ck_live_your_key_here"
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 }
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")
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"
{
"success": true,
"scanned": 1240,
"flagged": 18,
"alerts_created": 7,
"high_risk": 3,
"duration_ms": 412
}
| scanned | Total transactions evaluated |
| flagged | Unique transactions flagged |
| alerts_created | New alert records created |
| high_risk | Alerts with risk_score ≥ 75 |
| duration_ms | Scan wall-clock time (ms) |
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.
| Parameter | Type | Default | Description |
|---|---|---|---|
| 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 -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"
{
"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
}
}
Returns aggregate compliance statistics across all transactions. Useful for dashboard widgets and executive reporting. No parameters required.
curl https://vaultmind-6.polsia.app/api/alerts/summary \
-H "Authorization: Bearer ck_live_your_key_here"
{
"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.
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.
| Field | Type | Description |
|---|---|---|
| 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 -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 -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
}
}'
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"
}
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
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
{
"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"
}
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 https://vaultmind-6.polsia.app/api/model-card \
-H "Authorization: Bearer ck_live_your_key_here"
{
"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"
}
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 https://vaultmind-6.polsia.app/api/monitoring/drift \
-H "Authorization: Bearer ck_live_your_key_here"
{
"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.
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 https://vaultmind-6.polsia.app/api/system/status \
-H "Authorization: Bearer ck_live_your_key_here"
{
"success": true,
"mode": "full_ai",
"kill_switch_active": false,
"ml_enabled": true,
"rules_enabled": true,
"uptime_hours": 720
}
{
"success": true,
"mode": "rules_only",
"kill_switch_active": true,
"kill_switch_reason": "Drift threshold exceeded",
"ml_enabled": false,
"rules_enabled": true
}
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.
| Field | Type | Required | Description |
|---|---|---|---|
| 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 -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"
}'
{
"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"
}
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.
| Parameter | Type | Default | Description |
|---|---|---|---|
| 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 -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"
{
"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 }
}
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 https://vaultmind-6.polsia.app/api/fairness/latest \
-H "Authorization: Bearer ck_live_your_key_here"
{
"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. |
{
"success": false,
"message": "transaction_id 99999 not found"
}