> ## Documentation Index
> Fetch the complete documentation index at: https://docs.range.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Building a Compliance Screening Pipeline

> Combine multiple Risk API endpoints to build an automated AML/KYC compliance workflow for blockchain transactions.

This guide walks through building an automated compliance screening pipeline using Range's Risk API. You'll learn how to choose the right endpoint for your use case and build a multi-layered screening flow.

<Info>
  **Prerequisites:** You need a [Risk API key](/introduction/getting-started) and familiarity with the [Address Risk Score](/risk-api/risk/get-address-risk-score), [Sanctions & Blacklist Check](/risk-api/risk/get-sanctions-blacklist-check), and [Payment Risk Assessment](/risk-api/risk/get-payment-risk-assessment) endpoints.
</Info>

***

## Choosing the Right Approach

Range's risk endpoints are layered - each higher-level endpoint includes the checks of the ones below it:

| Endpoint                                                                    | What It Includes                                                                                                                                      | Best For                                  |
| --------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------- |
| [Sanctions & Blacklist Check](/risk-api/risk/get-sanctions-blacklist-check) | OFAC sanctions, stablecoin issuer blacklists                                                                                                          | Fast pass/fail sanctions screening        |
| [Address Risk Score](/risk-api/risk/get-address-risk-score)                 | Everything in Sanctions + proximity analysis + ML-based threat detection                                                                              | Screening a single address                |
| [Payment Risk Assessment](/risk-api/risk/get-payment-risk-assessment)       | Everything in Address Risk + new wallet detection, dormant wallet detection, address poisoning, interaction history, token risk, cross-chain analysis | Assessing a payment between two addresses |

<Tip>
  You don't need to call all three endpoints sequentially - each higher-level endpoint already includes the checks from the ones below it. Choose based on your use case and how much context you have.
</Tip>

## Architecture Overview

A compliance pipeline typically uses one of two patterns:

### Pattern A: Payment Flow (Recommended for Transactions)

When you have both sender and recipient, use Payment Risk Assessment as the primary check. It includes address risk scoring and sanctions/attribution data for both addresses, plus payment-specific analysis.

```
Sender + Recipient + Amount
      │
      ▼
┌───────────────────────────┐
│  Payment Risk Assessment  │──── High risk? → FLAG / REJECT
│  (8 dimensions including  │     Unknown?  → FLAG for review
│   address risk + sanctions│
│   for both addresses)     │
└───────────────────────────┘
      │ Low/Medium
      ▼
    ALLOW
```

### Pattern B: Address Screening (No Payment Context)

When screening a single address (e.g., during onboarding, before allowing deposits), use Address Risk Score - which already includes sanctions and blacklist data.

```
Inbound Address
      │
      ▼
┌─────────────────────┐
│  Address Risk Score │──── Score ≥ threshold? → FLAG / REJECT
│  (Includes sanctions│
│   + ML + proximity) │
└─────────────────────┘
      │ Acceptable
      ▼
    ALLOW
```

### When to Use the Standalone Sanctions Endpoint

The [Sanctions & Blacklist Check](/risk-api/risk/get-sanctions-blacklist-check) endpoint is still useful when you need:

* **Explicit OFAC compliance documentation** - a dedicated sanctions check provides a clear audit record specifically for sanctions screening
* **High-volume, low-latency pre-filtering** - the sanctions endpoint is the fastest and cheapest check, useful as a first gate before more expensive analysis
* **Detailed blacklist event data** - with `include_details=true`, it returns specific blacklist/unblacklist events from stablecoin issuers that aren't available through the other endpoints

***

## Screening a Payment

When you have sender, recipient, and amount, the Payment Risk Assessment is the single endpoint you need. It analyzes both addresses across 8 risk dimensions - including malicious connection analysis and attributed address checks (which cover sanctions and blacklist data).

```bash theme={null}
curl -G https://api.range.org/v1/risk/payment \
  --data-urlencode "sender_address=SENDER_ADDRESS" \
  --data-urlencode "recipient_address=RECIPIENT_ADDRESS" \
  --data-urlencode "amount=1000" \
  --data-urlencode "sender_network=solana" \
  --data-urlencode "recipient_network=solana" \
  -H "Authorization: Bearer your_api_key_here"
```

```javascript theme={null}
async function checkPaymentRisk(sender, recipient, amount, network) {
  const params = new URLSearchParams({
    sender_address: sender,
    recipient_address: recipient,
    amount: amount.toString(),
    sender_network: network,
    recipient_network: network,
  });
  const response = await fetch(
    `https://api.range.org/v1/risk/payment?${params}`,
    { headers: { Authorization: `Bearer ${API_KEY}` } }
  );
  return response.json();
}
```

### Decision Matrix

| Payment Risk Level |                               Risk Factors                               | Action                                           |
| :----------------: | :----------------------------------------------------------------------: | ------------------------------------------------ |
|         Any        | `malicious_address_sender` or `malicious_address_recipient` flagged HIGH | **REJECT** - Address flagged as malicious        |
|        High        |                           Multiple HIGH factors                          | **REJECT** - High risk on multiple signals       |
|        High        |              Single HIGH factor (e.g., `first_interaction`)              | **FLAG** - Manual review required                |
|       Medium       |                                     -                                    | **FLAG** - Elevated risk, needs review           |
|         Low        |                                     -                                    | **ALLOW** - Low risk                             |
|       Unknown      |                                     -                                    | **FLAG** - Insufficient data, treat with caution |

<Note>
  These thresholds are recommendations. Calibrate them based on your risk appetite, regulatory requirements, and use case. See the calibration guidance below.
</Note>

***

## Screening a Single Address

When you don't have payment context (e.g., during onboarding or deposit screening), use Address Risk Score. It includes sanctions and blacklist data along with proximity analysis and ML-based threat detection.

```bash theme={null}
curl -G https://api.range.org/v1/risk/address \
  --data-urlencode "address=COUNTERPARTY_ADDRESS" \
  --data-urlencode "network=solana" \
  -H "Authorization: Bearer your_api_key_here"
```

```javascript theme={null}
async function checkAddressRisk(address, network) {
  const params = new URLSearchParams({ address, network });
  const response = await fetch(
    `https://api.range.org/v1/risk/address?${params}`,
    { headers: { Authorization: `Bearer ${API_KEY}` } }
  );
  return response.json();
}
```

### Decision Thresholds

|    Score | Risk Level                | Action                                                           |
| -------: | ------------------------- | ---------------------------------------------------------------- |
| **8–10** | Critical / Extremely high | **REJECT** - Directly or closely connected to malicious activity |
|  **6–7** | High                      | **FLAG** or **REJECT** - Depends on risk tolerance               |
|  **4–5** | Medium                    | **FLAG** - Manual review recommended                             |
|  **1–3** | Low / Very low            | **ALLOW**                                                        |

***

## Adding a Dedicated Sanctions Check

For compliance teams that need an explicit, documented sanctions screening step - separate from the broader risk analysis - add a standalone Sanctions & Blacklist Check as a fast pre-filter:

```javascript theme={null}
async function checkSanctions(address) {
  const response = await fetch(
    `https://api.range.org/v1/risk/sanctions/${address}?include_details=false`,
    { headers: { Authorization: `Bearer ${API_KEY}` } }
  );
  const data = await response.json();

  return {
    blocked: data.is_ofac_sanctioned || data.is_token_blacklisted,
    ofac: data.is_ofac_sanctioned,
    blacklisted: data.is_token_blacklisted,
  };
}
```

This is optional since Address Risk Score and Payment Risk Assessment already include sanctions data, but useful for:

* Creating a separate audit record specifically for sanctions compliance
* Fast pre-filtering before more expensive checks
* Getting detailed blacklist event history with `include_details=true`

***

## Log and Audit

For compliance, store the raw API responses alongside your decision. This creates an audit trail showing what data was available at the time of the decision.

```javascript theme={null}
async function logComplianceDecision(transaction, checks, decision) {
  const record = {
    timestamp: new Date().toISOString(),
    transaction_id: transaction.id,
    counterparty: transaction.counterparty,
    checks: {
      payment_risk: checks.paymentRisk,     // or address_risk for single-address screening
      sanctions: checks.sanctions || null,   // if standalone sanctions check was used
    },
    decision: decision, // "allow", "flag", "reject"
    reasoning: decision.reasoning,
  };

  // Store in your compliance database
  await complianceDB.insert(record);
}
```

Key fields to retain:

* **Timestamp** of each check
* **Raw API responses** (scores, risk levels, reasoning, individual risk factors)
* **Decision** and the logic that produced it
* **Operator overrides** if a flagged transaction was manually approved or rejected

***

## Threshold Calibration

Different use cases warrant different risk tolerances. These thresholds apply to Address Risk Score (`riskScore` 1–10):

| Use Case                   | Reject At |  Flag At  | Rationale                                   |
| -------------------------- | :-------: | :-------: | ------------------------------------------- |
| **Consumer wallet**        | Score ≥ 8 | Score ≥ 6 | Protect retail users, fewer false positives |
| **Exchange compliance**    | Score ≥ 6 | Score ≥ 3 | Regulatory obligation, tighter screening    |
| **Institutional treasury** | Score ≥ 4 | Score ≥ 2 | Maximum caution for large value flows       |
| **DeFi protocol**          | Score ≥ 8 | Score ≥ 6 | Balance usability with risk mitigation      |

***

## Full Pipeline Examples

### Payment Flow

```javascript theme={null}
async function screenPayment(sender, recipient, amount, network) {
  // Payment Risk Assessment - comprehensive check for both addresses
  const paymentRisk = await checkPaymentRisk(sender, recipient, amount, network);

  // Check for malicious address flags in risk factors
  const maliciousFlags = paymentRisk.risk_factors?.filter(
    (f) => f.factor.startsWith("malicious_address") && f.risk_level === "high"
  );

  if (maliciousFlags?.length > 0) {
    return { decision: "reject", reasoning: "Address flagged as malicious" };
  }

  if (paymentRisk.overall_risk_level === "high") {
    return { decision: "flag", reasoning: "High payment risk - manual review required" };
  }

  if (paymentRisk.overall_risk_level === "unknown") {
    return { decision: "flag", reasoning: "Insufficient data - proceed with caution" };
  }

  return { decision: "allow", reasoning: "Payment risk assessment passed" };
}
```

### Address Screening with Optional Sanctions Audit

```javascript theme={null}
async function screenAddress(address, network, requireSanctionsAudit = false) {
  // Optional: Dedicated sanctions check for audit trail
  if (requireSanctionsAudit) {
    const sanctions = await checkSanctions(address);
    if (sanctions.blocked) {
      return {
        decision: "reject",
        reasoning: `Address is ${sanctions.ofac ? "OFAC sanctioned" : "token blacklisted"}`,
      };
    }
  }

  // Address Risk Score - includes sanctions + proximity + ML analysis
  const addressRisk = await checkAddressRisk(address, network);

  if (addressRisk.riskScore >= 8) {
    return {
      decision: "reject",
      reasoning: `Risk score ${addressRisk.riskScore}/10: ${addressRisk.reasoning}`,
    };
  }

  if (addressRisk.riskScore >= 6) {
    return { decision: "flag", reasoning: "Elevated risk - manual review required" };
  }

  return { decision: "allow", reasoning: "Address screening passed" };
}
```

***

## What's Next

<CardGroup cols={2}>
  <Card title="Understanding Risk Scores" icon="chart-bar" href="/risk-api/product-info/understanding-risk-scores">
    Deep dive into how risk scores are calculated and how to interpret them.
  </Card>

  <Card title="Faraday API" icon="route" href="/faraday-api/introduction">
    For end-to-end compliant payment execution with built-in Risk API screening.
  </Card>
</CardGroup>
