FreezeRadar Developers · v1
Asynchronous freeze-risk intelligence API
Business customers can submit wallet and transaction screenings, poll a result, and receive signed completion events. Results are explainable risk signals — not legal advice, AML certification, an ownership assertion, or an instruction to block a payment.
Authentication
Use a Business API key in the Authorization Bearer header. Create and revoke keys from the Developer Console.
Async workflow
Create a screening, retain its id, then poll the result URL or wait for a signed webhook.
Signed delivery
Every webhook includes an event id, Unix timestamp and HMAC-SHA256 signature.
Getting started
Overview
The FreezeRadar Business API mirrors the same freeze-risk analysis used in the app. Every screening is asynchronous: a create call returns immediately with a job id, and the result becomes available once analysis finishes — via polling or a signed webhook event.
Quickstart
No API key needed for this one — it hits a public endpoint. Run it now and you have a real result in under a minute:
curl "https://freezeradar.com/api/sanctions/check?address=TBZefVsyQpzzxc2WSCLbZBECvxVdzGqdtC"{
"ok": true,
"data": {
"address": "TBZefVsyQpzzxc2WSCLbZBECvxVdzGqdtC",
"chain": "tron",
"sanctioned": true,
"matches": [
{ "source": "OFAC", "entityName": "CHEIL CREDIT BANK", "entitySlug": "cheil-credit-bank-ea8e1b0944" }
]
}
}That address is a real, currently-sanctioned entity (see it on /sanctions). For the Business API below you'll need a key from the Developer Console, or try every public endpoint with your own address in the playground.
Authentication
Send Authorization: Bearer <API_KEY> over HTTPS on every request. Keys are account-owned and shown only once when created. Store them in a server-side secret manager; never place them in browser code, mobile apps, or public repositories.
Invalid, revoked, or absent keys return 401 UNAUTHORIZED. Business feature or quota restrictions return a safe error without internal provider details.
{
"ok": false,
"error": {
"code": "UNAUTHORIZED",
"message": "A valid Business API key is required."
}
}Versioning & stability
Business API endpoints below are relative to https://freezeradar.com/api/v1. Public endpoints live outside the version prefix (/api/sanctions/check, etc.) since they mirror the free site rather than a versioned contract. The current Business API version is v1.
- Breaking changes ship under a new version prefix (
/api/v2) — v1 keeps working. - A new optional field on a response is not a breaking change; do not fail on unrecognized fields.
- A deprecated field or endpoint is announced here and in the changelog with a removal date at least 90 days out.
API reference
Create an address screening
/api/v1/address-screeningsAccepts the same address, chain, optional asset list, and optional scan mode as the FreezeRadar app. Returns immediately with an id and QUEUED status.
| Parameter | Type | Description |
|---|---|---|
addressrequired | string | Wallet address to screen. |
chainrequired | ethereum | tron | bsc | polygon | solana | base | arbitrum | optimism | avalanche | Chain the address belongs to. |
assetsoptional | (USDT | USDC | PAXG | XAUt)[] | Restrict analysis to specific freezeable assets. Defaults to full coverage. |
scanModeoptional | STANDARD | DEEP | DEEP performs a more thorough, slower analysis. Defaults to STANDARD. |
curl -X POST https://freezeradar.com/api/v1/address-screenings \
-H "Authorization: Bearer fr_live_…" \
-H "Content-Type: application/json" \
-d '{
"address": "0x…",
"chain": "ethereum",
"assets": ["USDT"],
"scanMode": "STANDARD"
}'{
"ok": true,
"data": {
"id": "scan_job_id",
"status": "QUEUED",
"resultUrl": "/api/v1/screenings/scan_job_id"
}
}Create a transaction screening
/api/v1/transaction-screeningsScreens a specific on-chain transaction. Coverage is returned only where the underlying chain provider can prove a supported freezeable-asset transfer.
| Parameter | Type | Description |
|---|---|---|
chainrequired | ethereum | tron | bsc | polygon | solana | base | arbitrum | optimism | avalanche | Chain the transaction belongs to. |
transactionHashrequired | string | The transaction hash to analyze. |
policyIdoptional | string | Apply an existing risk policy's thresholds to the verdict. |
curl -X POST https://freezeradar.com/api/v1/transaction-screenings \
-H "Authorization: Bearer fr_live_…" \
-H "Content-Type: application/json" \
-d '{
"chain": "ethereum",
"transactionHash": "0x…",
"policyId": "cl…"
}'{
"ok": true,
"data": {
"id": "screening_id",
"status": "QUEUED",
"resultUrl": "/api/v1/screenings/screening_id"
}
}A transaction that is valid but has no supported asset coverage, or cannot be assessed for that chain, returns 422 and releases its reserved quota.
Get a screening result
/api/v1/screenings/{id}Returns the latest job state for either screening type. Possible statuses are QUEUED, RUNNING, COMPLETED, and FAILED. Do not treat QUEUED or RUNNING as a final result.
curl https://freezeradar.com/api/v1/screenings/scan_job_id \
-H "Authorization: Bearer fr_live_…"{
"ok": true,
"data": {
"id": "scan_job_id",
"status": "COMPLETED",
"resultUrl": "/scan/wallet_scan_id",
"walletScanId": "wallet_scan_id",
"errorMessage": null,
"scan": {
"id": "wallet_scan_id",
"overallRisk": 34,
"riskCategory": "MEDIUM",
"confidenceScore": 81,
"accessMode": "SUMMARY",
"scanMode": "STANDARD",
"analyzedAt": "2026-08-05T02:10:00.000Z",
"summary": "MEDIUM risk driven by 1-hop exposure to issuer-blacklisted address.",
"scoreDrivers": [
{
"findingType": "ONE_HOP_SANCTIONS_EXPOSURE",
"title": "1-hop exposure to issuer-blacklisted address",
"contribution": 62,
"confidence": 86,
"direction": "INCREASE",
"detail": "This wallet received 20,000 USDT across 1 transfer 12 days ago with TQ86… — 0.45% of tracked volume, which is blacklisted on-chain by the token issuer."
}
]
}
}
}{
"ok": true,
"data": {
"id": "screening_id",
"status": "COMPLETED",
"verdict": "CLEAR",
"riskCategory": "LOW",
"overallRisk": 12,
"chain": "ethereum",
"transactionHash": "0x…",
"resultUrl": "/api/v1/screenings/screening_id",
"completedAt": "2026-08-05T02:10:00.000Z",
"errorMessage": null,
"result": { "findings": [], "transferCoverage": "…", "policyVersion": null }
}
}Transaction results include verdict (CLEAR / REVIEW / BLOCK), riskCategory, findings, transfer coverage, and the policy version when one was used. Responses never include raw evidence blobs.
Public API · no key, IP rate-limited
Sanctions check
/api/sanctions/checkDirect sanctions-list matches for an address. 20 requests/minute per IP.
| Parameter | Type | Description |
|---|---|---|
addressrequired | string | Address to check. |
chainoptional | string | Auto-detected from the address format if omitted (includes bitcoin, sanctions-only). |
curl "https://freezeradar.com/api/sanctions/check?address=TBZefVsyQpzzxc2WSCLbZBECvxVdzGqdtC&chain=tron"Widget check
/api/widget/checkBlacklist and sanctions status only — no score, no findings. Same endpoint the embeddable widget calls. 30 requests/minute per IP.
curl "https://freezeradar.com/api/widget/check?address=TLXDJUauN4vgN75tJtCbXiAm4mQaDTmTNY"{
"ok": true,
"data": {
"address": "TLXDJUauN4vgN75tJtCbXiAm4mQaDTmTNY",
"chain": "tron",
"blacklisted": true,
"sanctioned": false
}
}Stats
/api/statsGlobal and per-chain freeze totals, revalidated hourly. No rate limit beyond normal fair use.
curl "https://freezeradar.com/api/stats"{
"ok": true,
"data": {
"totalFrozenUsd": 1284930221,
"totalFreezeEvents": 41823,
"blockedWallets": 39012,
"largestFreeze": {
"chain": "tron",
"walletAddress": "T…",
"assetSymbol": "USDT",
"observedValueUsd": 62000000,
"occurredAt": "2026-03-11T14:02:00.000Z"
},
"newBans30d": 612,
"released": 1103,
"burned": 47,
"lostFunds": 18200000,
"byChain": { "tron": 28110, "ethereum": 9822 },
"byAsset": { "USDT": 39900, "USDC": 1500 },
"coverageByChain": [
{ "chain": "tron", "status": "OK", "lastSyncedAt": "2026-08-27T09:00:00.000Z" }
],
"lastUpdatedAt": "2026-08-27T09:00:00.000Z"
}
}Events feed
/api/eventsPaginated freeze events, or pass since to poll for new ones. Backs the /events page.
curl "https://freezeradar.com/api/events?chain=tron&range=24h"Assets
/api/assetsThe freezeable-asset registry: which assets are freezeable on which chain, and the mechanism used.
curl "https://freezeradar.com/api/assets?chain=tron"Chains
/api/chainsEvery chain FreezeRadar tracks.
curl "https://freezeradar.com/api/chains"{
"ok": true,
"data": [
{ "value": "ethereum", "label": "Ethereum" },
{ "value": "tron", "label": "Tron" },
{ "value": "bitcoin", "label": "Bitcoin (sanctions check only)" }
]
}Webhooks
Events
Select events in the Business Developer Console. Payloads are JSON and include id, type, createdAt, and data.
| Event | Fires when |
|---|---|
screening.completed | A transaction screening has a final result. |
freeze-state.changed | A priority issuer monitor observed a direct state change. |
risk.alert.created | A related priority-monitor alert was created. |
Verifying signatures
Every delivery includes these headers. The signature is sha256= plus an HMAC-SHA256 of the timestamp, a dot, and the raw request body, using the webhook secret shown at creation.
| Header | Description |
|---|---|
x-freezeradar-event | The event type, e.g. screening.completed. |
x-freezeradar-timestamp | Unix timestamp the delivery was signed at. |
x-freezeradar-signature | sha256=<hmac> over `${timestamp}.${rawBody}`. |
import { createHmac, timingSafeEqual } from "node:crypto";
const signed = `${timestamp}.${rawBody}`;
const expected =
"sha256=" +
createHmac("sha256", webhookSecret).update(signed).digest("hex");
if (!timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
throw new Error("Invalid FreezeRadar signature");
}import hashlib
import hmac
signed = f"{timestamp}.{raw_body}"
expected = "sha256=" + hmac.new(
webhook_secret.encode(), signed.encode(), hashlib.sha256
).hexdigest()
if not hmac.compare_digest(signature, expected):
raise ValueError("Invalid FreezeRadar signature")Verify the signature against the raw body before parsing. Deduplicate on event id. Reject stale timestamps according to your replay window. Return any 2xx response to acknowledge delivery.
A non-2xx or timed-out response is retried up to 5 times with exponential backoff (roughly 2, 4, 8, then 16 minutes apart, 10s timeout per attempt), then marked FAILED. Retries are not guaranteed to arrive in order — an older event can be redelivered after a newer one — so order events by their x-freezeradar-timestamp header, not by arrival time.
Reference
Errors & rate limits
| Status | Meaning |
|---|---|
| 400 | Invalid request shape or invalid chain/address/hash. |
| 401 | Missing, invalid, or revoked API key. |
| 403 | Business entitlement is unavailable (including after plan downgrade), or an account limit is reached. |
| 404 | Screening id does not belong to the authenticated account. |
| 422 | Transaction is valid but has no supported asset coverage, or cannot be assessed for that chain. |
| 429 | Rate limit exceeded — 60/min and 600/hour per API key. Respect Retry-After. |
| 503 | Rate limiting temporarily unavailable; the Business API fails closed until Redis recovers. |
| 5xx | A temporary safe failure. Retry with exponential backoff. |
Every Business API and rate-limited public response carries X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset (Unix seconds) — read these instead of guessing your remaining budget.
Usage is account-scoped. Keys remain hashed at rest but are rejected on use unless the account still has an active Business entitlement. A transaction screening that cannot start because it is invalid, unsupported, or provider-unavailable releases its reserved transaction quota. Bridge-trace and graph-explorer entitlements are plan flags for product gating; they are not exposed as separate public /api/v1 endpoints yet.
Integration checklist
Before you ship
Keep keys and webhook secrets server-side.
Poll until a final status or verify signed webhooks.
Store evidence and coverage alongside your own decision.
Use a human review path for high-risk or incomplete results.
Do not represent FreezeRadar output as a legal determination or automatic freeze prediction.
Need higher limits or a custom policy?
Reach out and we'll help you scope a Business plan for your volume.