AML Screening Integration (Chainalysis, Elliptic, Crystal)

We design and develop full-cycle blockchain solutions: from smart contract architecture to launching DeFi protocols, NFT marketplaces and crypto exchanges. Security audits, tokenomics, integration with existing infrastructure.
Showing 1 of 1 servicesAll 1306 services
AML Screening Integration (Chainalysis, Elliptic, Crystal)
Medium
~3-5 business days
FAQ
Blockchain Development Services
Blockchain Development Stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1217
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1046
  • image_logo-advance_0.png
    B2B Advance company logo design
    561
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    823

AML Screening Integration (Chainalysis, Elliptic, Crystal)

AML screening of cryptocurrency transactions is a mandatory compliance element for any platform working with crypto. Task: on each deposit or withdrawal, check if the address is connected to sanctioned entities, darknet markets, stolen funds, or other high-risk activities.

Chainalysis KYT (Know Your Transaction)

Chainalysis is the market leader, used by most major exchanges and regulators for forensics. API is divided into several products: KYT for transaction monitoring, Reactor for investigation, Kryptos for entity data.

KYT API Integration

class ChainalysisClient {
  private readonly baseURL = "https://api.chainalysis.com";
  
  async registerAddress(address: string, asset: "USDT" | "ETH" | "BTC" | string): Promise<void> {
    await this.post("/api/kyt/v2/users", {
      userId: address,
      asset,
    });
  }
  
  async screenTransfer(params: {
    asset: string;
    network: string;
    transferReference: string; // txHash or address
    direction: "received" | "sent";
    userId: string;
    outputAddress?: string;
    value?: string;
    assetAmount?: number;
    timestamp?: string;
  }): Promise<TransferRisk> {
    const response = await this.post("/api/kyt/v2/transfers", params);
    
    return {
      externalId: response.externalId,
      riskScore: response.riskScore,
      cluster: response.cluster,
      status: response.status, // "APPROVED" | "BLOCKED" | "IN_REVIEW"
    };
  }
  
  // Get detailed alerts for transfer
  async getTransferAlerts(externalId: string): Promise<Alert[]> {
    const response = await this.get(`/api/kyt/v2/transfers/${externalId}/alerts`);
    return response.alerts;
  }
  
  private async post(path: string, body: any): Promise<any> {
    const response = await fetch(`${this.baseURL}${path}`, {
      method: "POST",
      headers: {
        "Token": this.apiKey,
        "Content-Type": "application/json",
      },
      body: JSON.stringify(body),
    });
    return response.json();
  }
}

Risk Score Categories

Score Category Automatic Action
0-39 LOW Skip
40-69 MEDIUM Flag for review
70-100 HIGH Block
N/A SEVERE Block + SAR

Categories that trigger automatic block regardless of score:

  • darknet_market
  • ransomware
  • stolen_funds
  • sanctions
  • terrorist_financing

Deposit Processing

async function processDeposit(deposit: Deposit): Promise<DepositResult> {
  // Register address if new
  await chainalysis.registerAddress(deposit.fromAddress, deposit.asset);
  
  // Screen transaction
  const risk = await chainalysis.screenTransfer({
    asset: deposit.asset,
    network: deposit.network,
    transferReference: deposit.txHash,
    direction: "received",
    userId: deposit.userId,
    value: deposit.usdValue.toString(),
    assetAmount: deposit.amount,
  });
  
  if (risk.status === "BLOCKED") {
    await freezeDeposit(deposit.id);
    await notifyCompliance(deposit, risk);
    return { status: "blocked", reason: risk.cluster?.category };
  }
  
  if (risk.status === "IN_REVIEW") {
    await holdForReview(deposit.id);
    await createComplianceTask(deposit, risk);
    return { status: "pending_review" };
  }
  
  await creditUserAccount(deposit);
  return { status: "approved" };
}

Elliptic Lens / Navigator

Elliptic is a Chainalysis competitor with similar functionality. Stronger in DeFi screening and cross-asset tracing.

class EllipticClient {
  async getWalletRisk(address: string, asset: string): Promise<EllipticRisk> {
    const response = await this.post("/v2/wallet/synchronous", {
      subject: {
        asset,
        type: "address",
        hash: address,
      },
      type: "wallet_exposure",
      customer_reference: address,
    });
    
    return {
      riskScore: response.risk_score, // 0-10 (Elliptic uses different scale)
      exposures: response.exposures,   // breakdown by categories
      clusters: response.entities,
    };
  }
  
  async getTransactionRisk(txHash: string, asset: string): Promise<EllipticRisk> {
    return this.post("/v2/txs/synchronous", {
      subject: { asset, type: "transaction", hash: txHash },
      type: "indirect_exposure",
    });
  }
}

Elliptic score is 0-10 — need normalization for unified risk logic if using both providers.

Crystal Blockchain (for Eastern Europe)

Crystal is a European player, often preferred for projects from CIS/EU due to prices and support.

const crystalResponse = await axios.post(
  "https://aml.crystalblockchain.com/api/v1/risks/check",
  {
    address,
    currency: asset,
  },
  {
    headers: { "X-Auth-Apikey": CRYSTAL_API_KEY },
  }
);

// crystal returns: risk_score (0-100), signals (list of signals)

Dual-Provider Strategy

For production: two providers reduce false negative risk. Logic: BLOCK if at least one blocks, REVIEW if at least one flags.

async function dualProviderScreen(address: string, txHash: string): Promise<RiskDecision> {
  const [chainalysisResult, ellipticResult] = await Promise.allSettled([
    chainalysis.screenTransfer({ transferReference: txHash, ... }),
    elliptic.getWalletRisk(address, asset),
  ]);
  
  const c = chainalysisResult.status === "fulfilled" ? chainalysisResult.value : null;
  const e = ellipticResult.status === "fulfilled" ? ellipticResult.value : null;
  
  // If one provider unavailable — use the other
  if (!c && !e) throw new Error("Both AML providers unavailable");
  
  const maxScore = Math.max(
    c?.riskScore ?? 0,
    e ? e.riskScore * 10 : 0, // normalize Elliptic 0-10 → 0-100
  );
  
  if (maxScore >= 70 || c?.status === "BLOCKED") return { decision: "BLOCK", score: maxScore };
  if (maxScore >= 40) return { decision: "REVIEW", score: maxScore };
  return { decision: "ALLOW", score: maxScore };
}

Integration of one AML provider (API + blocking logic + compliance dashboard) — 1-2 weeks. Dual-provider system with automatic failover — 2-3 weeks.