Developer Reference

Compliance & Risk API

Integrate sanctions and KYT screening, mixer and scam attribution, transaction tracing, exchange identification, and continuous monitoring into your stack. Start with 20 free screenings — no credit card required.

Authentication

All API requests require a Bearer token in the Authorization header. Get your key by signing up:

Sign up via API
curl -X POST https://chainevidence.net/api/v1/signup \
  -H "Content-Type: application/json" \
  -d '{"name": "Acme Corp", "email": "dev@acme.com"}'

# Response:
# { "apiKey": "ce_live_a1b2c3d4...", "creditsRemaining": 20, "balanceCents": 100 }

Or sign up through the Portal UI for a dashboard with usage analytics, team management, and billing.

Using your API key
Authorization: Bearer ce_live_a1b2c3d4e5f6g7h8i9j0...

Keep your API key secret. Never expose it in client-side code or public repositories. The key cannot be retrieved after creation — store it securely.

Quick Start

Screen a wallet address in one request:

Request
curl https://chainevidence.net/api/v1/address/1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa/check \
  -H "Authorization: Bearer ce_live_YOUR_API_KEY"
Response
{
  "data": {
    "address": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
    "chain": "BTC",
    "risk": { "score": 15, "level": "low" },
    "scamDatabase": { "isKnown": false, "reports": 0, "labels": [] },
    "firstSeen": null,
    "lastSeen": null
  },
  "meta": {
    "creditsRemaining": 19,
    "balanceCents": 999,
    "costCents": 1,
    "requestId": "req_a1b2c3d4e5f6g7h8"
  }
}

Billing & Credits

Every API call has a per-request cost in cents, deducted from your account balance. New accounts include 20 legacy credits and $1.00 balance. Top up via the Portal billing page or the /api/v1/topup endpoint.

EndpointCost
Address Check$0.01
Address Labels$0.01
Address Classify$0.02
Risk Score$0.05
Exchange ID$0.05
Connections$0.05
Fund Flow / Trace$0.10
Domain Intel$0.10
Path Find$0.15
Investigation (Phase 1)$0.50
Investigation (Full)$10.00
Monitoring: Add Address$0.10
Monitoring: Alerts / WebhooksFree
SDK Check$0.01
Sanctions Check$0.01
Payment Check$0.01
Bulk Check (per address)$0.005

Check X-Balance-Cents and X-Credits-Remaining response headers after each request. Contact api@chainevidence.net for volume pricing.

Rate Limits

API keys are limited to 60 requests per minute. Exceeding this returns 429 RATE_LIMITED with a Retry-After header indicating seconds until the window resets.

Response Header

X-RateLimit-Remaining: 58

Response Header

Retry-After: 12

Endpoints

Base URL: https://chainevidence.net

POST/api/org/screening/screen$0.01

Compliance Screening (KYT)

The compliance product. Screen one address against OFAC + EU sanctions, scam and mixer attribution, and your organization's risk policy. Returns a verdict (ACCEPT / REVIEW / REJECT), a 0–100 risk score, the matched list names, and structured risk typologies — sanctions match, mixer exposure, exchange-deposit clustering, peel-chain. Synchronous: call it at customer onboarding, before a withdrawal, or on a monitored wallet. Every call is written to your immutable audit trail.

Request Body (JSON)

addressstringAddress to screenrequired
chainstringBTC | ETH | BSC | TRX | SOL. Auto-detected from the address when omitted.
customerExternalIdstringYour customer id — links the screen to a customer record (optional).
walletIdstringA monitored-wallet id to attach the result to (optional).
policyIdstringApply a specific risk policy; defaults to your org's default policy (optional).

Examples

curl
curl -X POST https://chainevidence.net/api/org/screening/screen \
  -H "Authorization: Bearer ce_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "address": "0x6fc808c8fdd238fb35c9a67bd99e2cf76e3b2139",
    "chain": "ETH"
  }'
Python
import requests

resp = requests.post(
    "https://chainevidence.net/api/org/screening/screen",
    headers={"Authorization": "Bearer ce_live_YOUR_API_KEY"},
    json={"address": "0x6fc808c8fdd238fb35c9a67bd99e2cf76e3b2139", "chain": "ETH"},
)
result = resp.json()["data"]
if result["verdict"] != "ACCEPT":
    print(f"Hold: {result['verdict']} (score {result['score']})")
Node.js
const resp = await fetch("https://chainevidence.net/api/org/screening/screen", {
  method: "POST",
  headers: {
    "Authorization": "Bearer ce_live_YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    address: "0x6fc808c8fdd238fb35c9a67bd99e2cf76e3b2139",
    chain: "ETH",
  }),
});
const { data } = await resp.json();
if (data.verdict !== "ACCEPT") {
  console.log(`Hold: ${data.verdict} (score ${data.score})`);
}

Response

{
  "data": {
    "id": "cmpyk9vy60001jgque8t2fj7x",
    "address": "0x6fc808c8fdd238fb35c9a67bd99e2cf76e3b2139",
    "chain": "ETH",
    "score": 35,
    "level": "medium",
    "verdict": "REVIEW",
    "sanctioned": false,
    "matchedLists": [],
    "riskTypologies": [
      {
        "code": "MIXER_EXPOSURE",
        "label": "Mixer / tumbler exposure",
        "detail": "→ Tornado Cash",
        "source": "deposit-clustering",
        "severity": "high"
      }
    ],
    "requestId": "req_50b06c0554d54b11"
  },
  "meta": {
    "creditsRemaining": 980,
    "balanceCents": 9999,
    "costCents": 1,
    "requestId": "req_50b06c0554d54b11"
  }
}

Error Responses

400INVALID_ADDRESSAddress format not recognized
401UNAUTHORIZEDMissing or invalid API key
402INSUFFICIENT_BALANCEMonthly screening allowance exhausted and balance is zero
404NOT_FOUNDcustomerExternalId or walletId does not belong to your organization
POST/api/v1/investigate$0.50

Full Investigation

Run a complete investigation with blockchain analysis, scam database cross-referencing, and AI-powered risk assessment. Async endpoint — returns an investigation ID immediately. Poll the result endpoint for status and final report.

Request Body (JSON)

addressstringWallet address (BTC, ETH, BSC, TRX, SOL)required
domainstringAssociated scam domain (optional)
descriptionstringFraud description, max 2000 chars
victimAmountnumberEstimated loss amount

Examples

curl
curl -X POST https://chainevidence.net/api/v1/investigate \
  -H "Authorization: Bearer ce_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "address": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
    "domain": "fake-exchange.com",
    "victimAmount": 2.5
  }'
Python
import requests

resp = requests.post(
    "https://chainevidence.net/api/v1/investigate",
    headers={"Authorization": "Bearer ce_live_YOUR_API_KEY"},
    json={
        "address": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
        "domain": "fake-exchange.com",
        "victimAmount": 2.5,
    },
)
data = resp.json()
investigation_id = data["data"]["investigationId"]
print(f"Investigation started: {investigation_id}")
Node.js
const resp = await fetch("https://chainevidence.net/api/v1/investigate", {
  method: "POST",
  headers: {
    "Authorization": "Bearer ce_live_YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    address: "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
    domain: "fake-exchange.com",
    victimAmount: 2.5,
  }),
});
const { data } = await resp.json();
console.log("Investigation:", data.investigationId);

Response

{
  "data": {
    "investigationId": "cm4x7abc1000008l1g2h3i4j5",
    "status": "running",
    "estimatedSeconds": 120,
    "pollUrl": "/api/v1/investigate/cm4x7abc1000008l1g2h3i4j5"
  },
  "meta": {
    "creditsRemaining": 19,
    "balanceCents": 950,
    "costCents": 50,
    "requestId": "req_a1b2c3d4e5f6g7h8"
  }
}

Error Responses

400INVALID_ADDRESSAddress format not recognized
400INVALID_DOMAINDomain is malformed
402INSUFFICIENT_BALANCENot enough credits/balance
GET/api/v1/address/{address}/check$0.01

Address Check

Instant risk assessment using local database lookups only. Checks against scam databases, sanctions lists, and previously investigated addresses. The cheapest and fastest endpoint — ideal for pre-transaction screening in wallet apps.

Examples

curl
curl https://chainevidence.net/api/v1/address/1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa/check \
  -H "Authorization: Bearer ce_live_YOUR_API_KEY"
Python
import requests

resp = requests.get(
    "https://chainevidence.net/api/v1/address/1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa/check",
    headers={"Authorization": "Bearer ce_live_YOUR_API_KEY"},
)
data = resp.json()["data"]
print(f"Risk: {data['risk']['level']} ({data['risk']['score']}/100)")
Node.js
const resp = await fetch(
  "https://chainevidence.net/api/v1/address/1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa/check",
  { headers: { "Authorization": "Bearer ce_live_YOUR_API_KEY" } }
);
const { data } = await resp.json();
console.log(`Risk: ${data.risk.level} (${data.risk.score}/100)`);

Response

{
  "data": {
    "address": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
    "chain": "BTC",
    "risk": { "score": 15, "level": "low" },
    "scamDatabase": {
      "isKnown": false,
      "reports": 0,
      "labels": []
    },
    "firstSeen": null,
    "lastSeen": null
  },
  "meta": {
    "creditsRemaining": 19,
    "balanceCents": 999,
    "costCents": 1,
    "requestId": "req_a1b2c3d4e5f6g7h8"
  }
}
GET/api/v1/address/{address}/trace$0.10

Fund Flow Trace

Full fund flow analysis with multi-hop tracing. Follows funds across wallets and identifies exchange destinations. Supports BTC (via TxShield), ETH/BSC (via GoPlus security data), TRX, and SOL chains.

Query Parameters

chainstringOverride auto-detection: BTC, ETH, BSC, TRX, SOL
hopsnumberMax trace depth (default: 4)

Examples

curl
curl "https://chainevidence.net/api/v1/address/1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa/trace?chain=BTC" \
  -H "Authorization: Bearer ce_live_YOUR_API_KEY"
Python
import requests

resp = requests.get(
    "https://chainevidence.net/api/v1/address/1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa/trace",
    headers={"Authorization": "Bearer ce_live_YOUR_API_KEY"},
    params={"chain": "BTC"},
)
trace = resp.json()["data"]["trace"]
print(f"Traced {trace['hops']} hops to {len(trace['exchanges'])} exchanges")
Node.js
const url = new URL("https://chainevidence.net/api/v1/address/1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa/trace");
url.searchParams.set("chain", "BTC");

const resp = await fetch(url, {
  headers: { "Authorization": "Bearer ce_live_YOUR_API_KEY" },
});
const { data } = await resp.json();
console.log(`${data.trace.hops} hops, exchanges: ${data.trace.exchanges.join(", ")}`);

Response

{
  "data": {
    "address": "1A1zP1eP5QGefi...",
    "chain": "BTC",
    "trace": {
      "totalIncoming": "12.45 BTC",
      "totalOutgoing": "12.44 BTC",
      "txCount": 847,
      "hops": 4,
      "victimCount": 23,
      "exchanges": ["Binance", "Kraken"],
      "incomingTransactions": [...],
      "outgoingHops": [...]
    }
  },
  "meta": { "creditsRemaining": 17, "balanceCents": 990, "costCents": 10, "requestId": "req_..." }
}
GET/api/v1/address/{address}/classify$0.02

Exchange / Entity Classification

Classify a wallet address as exchange hot wallet, cold storage, mixer, service, or unknown using cluster analysis and known deposit address databases. Essential for determining where stolen funds ended up.

Examples

curl
curl https://chainevidence.net/api/v1/address/1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa/classify \
  -H "Authorization: Bearer ce_live_YOUR_API_KEY"
Python
import requests

resp = requests.get(
    "https://chainevidence.net/api/v1/address/1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa/classify",
    headers={"Authorization": "Bearer ce_live_YOUR_API_KEY"},
)
cls = resp.json()["data"]["classification"]
print(f"{cls['type']}: {cls.get('exchangeName', 'unknown')} ({cls['confidence']:.0%})")
Node.js
const resp = await fetch(
  "https://chainevidence.net/api/v1/address/1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa/classify",
  { headers: { "Authorization": "Bearer ce_live_YOUR_API_KEY" } }
);
const { data } = await resp.json();
const c = data.classification;
console.log(`${c.type}: ${c.exchangeName ?? "unknown"} (${(c.confidence * 100).toFixed(0)}%)`);

Response

{
  "data": {
    "address": "1A1zP1eP5QGefi...",
    "chain": "BTC",
    "classification": {
      "type": "exchange",
      "exchangeName": "Binance",
      "confidence": 0.97,
      "cooperationRating": "high"
    },
    "analysis": {
      "txCount": 15420,
      "totalReceivedBtc": 1247.83
    }
  },
  "meta": { "creditsRemaining": 18, "balanceCents": 998, "costCents": 2, "requestId": "req_..." }
}
GET/api/v1/address/{address}/risk-score$0.05

Risk Scoring

Comprehensive risk score computed from internal investigations, scam database records, and on-demand TxShield blockchain analysis. Returns a 0-100 score with level classification (low/medium/high/critical) and the data source used.

Examples

curl
curl https://chainevidence.net/api/v1/address/1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa/risk-score \
  -H "Authorization: Bearer ce_live_YOUR_API_KEY"
Python
import requests

resp = requests.get(
    "https://chainevidence.net/api/v1/address/1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa/risk-score",
    headers={"Authorization": "Bearer ce_live_YOUR_API_KEY"},
)
risk = resp.json()["data"]["risk"]
print(f"Score: {risk['score']}/100 ({risk['level']}), source: {risk['source']}")
Node.js
const resp = await fetch(
  "https://chainevidence.net/api/v1/address/1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa/risk-score",
  { headers: { "Authorization": "Bearer ce_live_YOUR_API_KEY" } }
);
const { data } = await resp.json();
console.log(`Score: ${data.risk.score}/100 (${data.risk.level})`);

Response

{
  "data": {
    "address": "1A1zP1eP5QGefi...",
    "chain": "BTC",
    "risk": {
      "score": 73,
      "level": "high",
      "source": "investigation"
    },
    "scamReports": {
      "count": 12,
      "labels": ["Investment Scam", "Ponzi"]
    }
  },
  "meta": { "creditsRemaining": 15, "balanceCents": 995, "costCents": 5, "requestId": "req_..." }
}
POST/api/v1/monitoring/addresses$0.10

Monitor Address

Add a wallet address to continuous monitoring. ChainEvidence will periodically re-check the address and trigger alerts when risk scores change, new scam reports appear, or sanctions matches are detected. Configure webhooks to receive alerts in real time.

Request Body (JSON)

addressstringWallet address to monitorrequired
chainstringChain override: BTC, ETH, BSC, TRX, SOL
labelstringHuman-readable label for this address
thresholdsobjectCustom alert thresholds (riskScoreIncrease, newReports)

Examples

curl
curl -X POST https://chainevidence.net/api/v1/monitoring/addresses \
  -H "Authorization: Bearer ce_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"address": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa", "label": "Suspect wallet #1"}'
Python
import requests

resp = requests.post(
    "https://chainevidence.net/api/v1/monitoring/addresses",
    headers={"Authorization": "Bearer ce_live_YOUR_API_KEY"},
    json={"address": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa", "label": "Suspect wallet #1"},
)
print(resp.json()["data"]["id"])
Node.js
const resp = await fetch("https://chainevidence.net/api/v1/monitoring/addresses", {
  method: "POST",
  headers: {
    "Authorization": "Bearer ce_live_YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    address: "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
    label: "Suspect wallet #1",
  }),
});
const { data } = await resp.json();
console.log("Monitoring ID:", data.id);

Response

{
  "data": {
    "id": "mon_a1b2c3d4",
    "address": "1A1zP1eP5QGefi...",
    "chain": "BTC",
    "label": "Suspect wallet #1",
    "status": "active",
    "lastRiskScore": 15,
    "lastRiskLevel": "low",
    "createdAt": "2026-03-25T10:00:00.000Z"
  },
  "meta": { "creditsRemaining": 10, "balanceCents": 990, "costCents": 10, "requestId": "req_..." }
}
GET/api/v1/monitoring/alertsFree

List Alerts

Retrieve monitoring alerts for your organization. Alerts are created when a watched address triggers a threshold change (risk score increase, new scam report, sanctions match, mixer detection). Supports pagination and filtering.

Query Parameters

statusstringFilter: active, acknowledged, all (default: active)
severitystringFilter: critical, high, medium, low
limitnumberMax results (default: 50, max: 200)
offsetnumberPagination offset

Examples

curl
curl "https://chainevidence.net/api/v1/monitoring/alerts?status=active&limit=10" \
  -H "Authorization: Bearer ce_live_YOUR_API_KEY"
Python
import requests

resp = requests.get(
    "https://chainevidence.net/api/v1/monitoring/alerts",
    headers={"Authorization": "Bearer ce_live_YOUR_API_KEY"},
    params={"status": "active", "limit": 10},
)
alerts = resp.json()["data"]["alerts"]
for a in alerts:
    print(f"[{a['severity']}] {a['message']}")
Node.js
const url = new URL("https://chainevidence.net/api/v1/monitoring/alerts");
url.searchParams.set("status", "active");

const resp = await fetch(url, {
  headers: { "Authorization": "Bearer ce_live_YOUR_API_KEY" },
});
const { data } = await resp.json();
data.alerts.forEach(a => console.log(`[${a.severity}] ${a.message}`));

Response

{
  "data": {
    "alerts": [
      {
        "id": "alert_x1y2z3",
        "addressId": "mon_a1b2c3d4",
        "address": "1A1zP1eP5QGefi...",
        "type": "risk_increase",
        "severity": "high",
        "message": "Risk score increased from 15 to 73",
        "previousValue": 15,
        "currentValue": 73,
        "status": "active",
        "createdAt": "2026-03-25T12:00:00.000Z"
      }
    ],
    "total": 1,
    "hasMore": false
  },
  "meta": { "creditsRemaining": 20, "balanceCents": 1000, "costCents": 0, "requestId": "req_..." }
}
POST/api/v1/monitoring/webhooksFree

Register Webhook

Register a webhook URL to receive real-time alerts. Events are delivered as signed HTTP POST requests with HMAC-SHA256 signatures. Supports event filtering — subscribe only to the alert types you care about.

Request Body (JSON)

urlstringHTTPS webhook URLrequired
eventsstring[]Event types to subscribe torequired

Examples

curl
curl -X POST https://chainevidence.net/api/v1/monitoring/webhooks \
  -H "Authorization: Bearer ce_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.com/webhooks/chainevidence",
    "events": ["alert.created", "alert.risk_increase", "alert.sanctions_match"]
  }'
Python
import requests

resp = requests.post(
    "https://chainevidence.net/api/v1/monitoring/webhooks",
    headers={"Authorization": "Bearer ce_live_YOUR_API_KEY"},
    json={
        "url": "https://your-app.com/webhooks/chainevidence",
        "events": ["alert.created", "alert.risk_increase"],
    },
)
wh = resp.json()["data"]
print(f"Webhook secret: {wh['secret']}")  # Store this for signature verification
Node.js
const resp = await fetch("https://chainevidence.net/api/v1/monitoring/webhooks", {
  method: "POST",
  headers: {
    "Authorization": "Bearer ce_live_YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url: "https://your-app.com/webhooks/chainevidence",
    events: ["alert.created", "alert.risk_increase"],
  }),
});
const { data } = await resp.json();
// Store data.secret for HMAC signature verification

Response

{
  "data": {
    "id": "wh_a1b2c3d4",
    "url": "https://your-app.com/webhooks/chainevidence",
    "events": ["alert.created", "alert.risk_increase"],
    "secret": "whsec_a1b2c3d4e5f6...",
    "isActive": true,
    "createdAt": "2026-03-25T10:00:00.000Z"
  },
  "meta": { "creditsRemaining": 20, "balanceCents": 1000, "costCents": 0, "requestId": "req_..." }
}

Response Format

All responses follow a consistent envelope format.

Success (200)
{
  "data": { ... },
  "meta": {
    "creditsRemaining": 15,
    "balanceCents": 850,
    "costCents": 5,
    "requestId": "req_a1b2c3d4"
  }
}
Error (4xx/5xx)
{
  "error": "Human-readable message",
  "code": "MACHINE_READABLE_CODE"
}

Error Codes

Machine-readable error codes for programmatic handling.

CodeHTTPDescription
AUTH_REQUIRED401No Authorization header provided
AUTH_INVALID401API key format is invalid (must be Bearer ce_live_...)
AUTH_FAILED401API key is revoked, inactive, or does not exist
RATE_LIMITED429Exceeded 60 requests per minute — includes Retry-After header
INSUFFICIENT_BALANCE402No balance or credits remaining. Top up at /api/v1/topup
INVALID_ADDRESS400Address format not recognized (BTC, ETH, BSC, TRX, SOL)
INVALID_DOMAIN400Domain is not a valid hostname
VALIDATION_ERROR400Request body validation failed. Details in response.
NOT_FOUND404Resource does not exist
INTERNAL_ERROR500Server error — contact support if persistent

Webhook Events

Event types available for webhook subscriptions. Webhook payloads are signed with HMAC-SHA256 — verify the X-Signature header using the secret returned when you created the webhook.

EventDescription
alert.createdAny new alert for a watched address
alert.risk_increaseRisk score increased above threshold
alert.sanctions_matchAddress matched a sanctions list
alert.new_scam_reportNew scam report filed against address
alert.mixer_detectedFunds routed through a known mixer
alert.phishing_detectedPhishing pattern detected in transaction history
address.status_changeMonitored address status changed
Webhook payload example
POST https://your-app.com/webhooks/chainevidence
Content-Type: application/json
X-Signature: sha256=a1b2c3d4e5f6...

{
  "event": "alert.risk_increase",
  "timestamp": "2026-03-25T12:00:00.000Z",
  "data": {
    "alertId": "alert_x1y2z3",
    "address": "1A1zP1eP5QGefi...",
    "previousRiskScore": 15,
    "currentRiskScore": 73,
    "riskLevel": "high"
  }
}

Ready to integrate?

Get your API key and start screening addresses in minutes. 20 free requests and $1.00 balance included — no credit card required.