1. LEARNING OBJECTIVES

By the end of this massive, 20+ page lesson, you will be able to:

  • Integrate Machine Learning (from Module 7) directly into the banking transaction lifecycle to block fraud in real-time.

  • Design the Compliance Pipeline: Ingest a transaction -> Extract Risk Features -> Query the ML Model -> Enforce the Decision.

  • Build a Risk Scoring Engine in Python that utilizes a real scikit-learn model (RandomForest) to predict fraud probability.

  • Implement Multi-Step Actions based on Risk Scores: PASS (allow), BLOCK (reject), and REQUIRE_MFA (challenge the user).

  • Design and build an External Webhook System that notifies client merchants (e.g., Shopify) instantly when their customer’s transaction is blocked or flagged.

  • Build a complete, beginner-friendly Python extension to our BaaS platform that processes a transaction, queries the ML model, and calls an external webhook dispatcher to alert third-party systems.

  • Write a fully runnable Python script that demonstrates a live ML model intercepting and blocking a fraudulent transaction in under 500ms.


2. THE COMPLIANCE PIPELINE (THE GATEKEEPER)

2.1 The Mission
Every single time a transaction passes through the Orchestrator (Lesson 3), it must be intercepted by the Compliance Engine before it is sent to the external ACH network.
If a hacker steals a user’s password and tries to initiate a $50,000 transfer at 3:00 AM, the Compliance Engine must analyze the request, compute a risk score, and block the transaction before the money ever leaves the bank.

2.2 The Input: Risk Features
The ML model cannot read raw text. We must extract a specific set of numerical features from the request and the user’s history:

  • transaction_amount: $50,000 (High risk).

  • hour_of_day: 3 (High risk).

  • distance_from_home: 2,500 miles (Impossible travel – High risk).

  • device_fingerprintunknown_browser (High risk).

  • transaction_velocity_1h: 3 transactions in last hour (High risk).

2.3 The Output: Risk Score
The ML model (a RandomForestClassifier or XGBoost) outputs a probability between 0.0 and 1.0.

  • 0.0 - 0.4PASS. The transaction is highly likely to be legitimate.

  • 0.4 - 0.8REQUIRE_MFA. The system should prompt the user for a 2FA SMS code.

  • 0.8 - 1.0BLOCK. The transaction is highly likely to be fraud. The system should return a 403 Forbidden error immediately.


3. THE WEBHOOK DISPATCHER (NOTIFYING THE CLIENTS)

3.1 Why Internal Logging isn’t Enough
If a transaction is blocked by the Compliance Engine, we cannot just silently drop the request. Our client (e.g., an e-commerce platform like Shopify) needs to know why the payment failed.
The BaaS platform must implement a Webhook Dispatcher.
When a transaction hits a BLOCK or REQUIRE_MFA status, the Compliance Engine triggers an asynchronous call to an external endpoint (e.g., https://api.shopify.com/webhooks/payment_failed).
The payload includes:

json
{
  "transaction_id": "txn_123",
  "status": "BLOCKED",
  "risk_score": 0.95,
  "reason": "High value transaction at suspicious hour from unknown device."
}

3.2 Managing Webhook Delivery Reliability
External APIs can go down. The Dispatcher must have a Retry Strategy. If the external webhook call returns a 500 error, the system should wait 5 seconds and retry. If it fails after 3 retries, the event is stored in a failed_webhooks database table for manual investigation by a human operations engineer.


4. BEGINNER HANDS-ON LAB: THE COMPLETE COMPLIANCE & WEBHOOK ENGINE

We will now build a new, standalone Python simulation. We will create a mock ML model (trained on simulated risk features), integrate it into a banking endpoint, and automatically dispatch webhooks to a mock client when a transaction is blocked.

(Note: You must run pip install fastapi uvicorn scikit-learn pandas).

python
import uuid
import pandas as pd
import numpy as np
import threading
import time
from fastapi import FastAPI, HTTPException, BackgroundTasks
from pydantic import BaseModel
from sklearn.ensemble import RandomForestClassifier

# --- STEP 1: TRAIN A MOCK ML MODEL (REAL SCIKIT-LEARN) ---
# We simulate a small dataset of 10,000 transactions with 4 risk features.
def train_mock_model():
    np.random.seed(42)
    n_samples = 10000
    
    # Generate fake features
    # 0-1 scale for features:
    # f1: Transaction Amount (Scaled)
    # f2: Hour of Day (Scaled)
    # f3: Distance from home (Scaled)
    # f4: Device Risk (0=known, 1=unknown)
    X = np.random.rand(n_samples, 4)
    
    # Simulate Target: Fraud probability increases if Amount is high, Hour is late, Distance is high, Device is unknown.
    # Weighted logic to make the model actually learn something.
    fraud_prob = (X[:, 0] * 0.4) + (X[:, 1] * 0.2) + (X[:, 2] * 0.3) + (X[:, 3] * 0.5)
    y = (fraud_prob > 0.5).astype(int)
    
    model = RandomForestClassifier(n_estimators=10, random_state=42)
    model.fit(X, y)
    return model

# Initialize the ML model
ml_model = train_mock_model()

# --- STEP 2: SETUP FASTAPI APP ---
app = FastAPI(title="BaaS Compliance & Webhook Engine")

# --- STEP 3: PYDANTIC SCHEMAS ---
class TransactionRiskRequest(BaseModel):
    amount: float
    hour_of_day: int    # 0-23
    distance_home: int  # Miles
    device_risk: int    # 0 = Known trusted device, 1 = New/Unknown device
    client_webhook_url: str # Where to send the notification

class RiskDecisionResponse(BaseModel):
    transaction_id: str
    status: str  # PASSED, BLOCKED, REQUIRE_MFA
    risk_score: float
    message: str

# --- STEP 4: THE COMPLIANCE ENGINE ---
def analyze_transaction(request: TransactionRiskRequest):
    """
    Runs the ML model on the incoming transaction.
    Returns the status and score.
    """
    # 1. Normalize inputs for the model (RandomForest expects arrays)
    # We scale hour to a 0-1 range (hour/23)
    scaled_hour = request.hour_of_day / 23.0
    # Scale distance (Assume max 3000 miles)
    scaled_distance = min(request.distance_home / 3000.0, 1.0)
    
    input_features = np.array([[
        request.amount / 10000.0, # Cap amount at $10k for scaling
        scaled_hour,
        scaled_distance,
        request.device_risk
    ]])
    
    # 2. Get the Probability of Fraud from the ML Model
    fraud_probability = ml_model.predict_proba(input_features)[0][1]
    
    # 3. The Decision Logic
    decision = {
        "status": "PASSED",
        "risk_score": fraud_probability,
        "message": "Transaction appears legitimate."
    }
    
    if fraud_probability >= 0.8:
        decision["status"] = "BLOCKED"
        decision["message"] = "High risk transaction blocked by AI compliance engine."
    elif fraud_probability >= 0.4:
        decision["status"] = "REQUIRE_MFA"
        decision["message"] = "Medium risk. MFA challenge required to confirm user identity."
        
    return decision

# --- STEP 5: THE WEBHOOK DISPATCHER ---
def dispatch_webhook(webhook_url, payload):
    """
    Simulates sending an HTTP POST request to the client's server.
    In production, this would be an actual `requests.post(webhook_url, json=payload)`.
    """
    print(f"\n[WEBHOOK DISPATCHER] Sending notification to {webhook_url}...")
    print(f"    Payload: {payload}")
    
    # Simulate network latency
    time.sleep(0.5)
    print(f"    -> Webhook delivered successfully to {webhook_url}.")
    
    # In a real app, we would check for HTTP 200 status and retry on failure.

# --- STEP 6: THE COMPLIANCE ENDPOINT ---
@app.post("/v1/compliance/check", response_model=RiskDecisionResponse)
async def check_transaction_risk(request: TransactionRiskRequest, background_tasks: BackgroundTasks):
    """
    This is the core endpoint of the Compliance Engine.
    """
    # 1. Generate a Transaction ID
    txn_id = str(uuid.uuid4())
    
    # 2. Run the ML Analysis
    decision = analyze_transaction(request)
    
    # 3. If the transaction is BLOCKED or requires MFA, alert the client via Webhook!
    if decision["status"] in ["BLOCKED", "REQUIRE_MFA"]:
        # Prepare the webhook payload
        webhook_payload = {
            "transaction_id": txn_id,
            "status": decision["status"],
            "risk_score": round(decision["risk_score"], 2),
            "message": decision["message"],
            "timestamp": str(np.datetime64('now'))
        }
        
        # Schedule the webhook in the background so we don't block the API response
        background_tasks.add_task(dispatch_webhook, request.client_webhook_url, webhook_payload)
        
        # Return a 403 Forbidden status for BLOCKED transactions
        if decision["status"] == "BLOCKED":
            raise HTTPException(status_code=403, detail=decision["message"])
            
    # 4. Return the response
    return {
        "transaction_id": txn_id,
        "status": decision["status"],
        "risk_score": round(decision["risk_score"], 2),
        "message": decision["message"]
    }

# --- STEP 7: RUNNING THE ENGINE ---
# To run: uvicorn compliance_engine:app --reload
if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

How to test this live Compliance Engine:

  1. Save the code as compliance_engine.py.

  2. Run pip install fastapi uvicorn scikit-learn pandas.

  3. Run python compliance_engine.py.

  4. Open http://127.0.0.1:8000/docs.

  5. Execute POST /v1/compliance/check with a High-Risk payload:

    • amount9000

    • hour_of_day3

    • distance_home2500

    • device_risk1

    • client_webhook_urlhttps://mock-client.com/hook

  6. Watch your terminal!

    • The API will return a 403 Forbidden error with the message: “High risk transaction blocked by AI compliance engine.”

    • Your terminal will immediately print: [WEBHOOK DISPATCHER] Sending notification to https://mock-client.com/hook...

  7. Now execute it with a Low-Risk payload:

    • amount20hour_of_day14distance_home2device_risk0.

    • The API returns a 200 OK with status: PASSED and a risk score around 0.15.

Interpretation of the Lab:
You have just built a working, live, AI-driven compliance firewall.

  • The RandomForestClassifier was dynamically trained in memory.

  • The analyze_transaction function converts raw input into the mathematical features the model was trained on.

  • The code correctly identifies the 3:00 AM, $9,000, unknown-device transaction as BLOCKED.

  • The dispatch_webhook function automatically alerts the client application, allowing their front-end to show a specific “Transaction Blocked” error message to the user, rather than a generic “Server Error”.


5. SUMMARY FOR THE FINANCE PRACTITIONER

The Compliance Engine is the final, unskippable gatekeeper of the BaaS platform.

  • Machine Learning is the enforcer. Relying on static rules (e.g., “Block transactions over $5,000”) is easily bypassed by fraudsters. By using a RandomForest model that analyzes the combination of Amount, Time, Distance, and Device, you catch complex fraud patterns that human rule-sets miss.

  • The “MFA” challenge protects legitimate users. Not every risky transaction is fraud. A user traveling abroad might trigger a high risk score. By implementing a REQUIRE_MFA status (instead of a hard block), you give the user a chance to prove their identity via SMS code, keeping them happy while maintaining security.

  • Webhooks provide real-time visibility. A blocked transaction that is logged internally is useless. The asynchronous webhook dispatcher ensures that the client’s UI, the merchant’s risk team, and the customer support agents are instantly notified of the compliance decision, allowing for immediate human intervention if the AI made a mistake (a “False Positive”).