60-second forensics quickstart
Five copy-paste curls. dev-test-key-123 works without signup. All return live data from https://1f.ai.
1. Screen 3 mixed addresses (sanctions / CEX / mixer flags)
curl -s -X POST https://1f.ai/api/forensics/screen \
-H "x-api-key: dev-test-key-123" \
-H "Content-Type: application/json" \
-d '{"addresses":["0xab5801a7d398351b8be11c439e05c5b3259aec9b","0xd551234ae421e3bcba99a0da6d736074f22192ff","0x910cbd523d972eb0a6f4cae4618ad62622b39dbf"]}'
2. CEX exposure for vitalik.eth
curl -s https://1f.ai/api/forensics/cex-exposure/0xab5801a7d398351b8be11c439e05c5b3259aec9b \
-H "x-api-key: dev-test-key-123"
3. Cross-chain follow (recent ETH bridge tx)
curl -s https://1f.ai/api/cross-chain/follow/0x6234f5cd4d61b6cda83b6d35e5fe37c2acaa3ac9caea33a1c1c3a5be99a05432 \
-H "x-api-key: dev-test-key-123"
4. Mixer correlation (known Tornado depositor)
curl -s https://1f.ai/api/forensics/mixer-correlate/0x910cbd523d972eb0a6f4cae4618ad62622b39dbf \
-H "x-api-key: dev-test-key-123"
5. Pre-flight risk check (USDT → Tornado, expect BLOCK)
curl -s -X POST https://1f.ai/api/simulate/preflight \
-H "x-api-key: dev-test-key-123" \
-H "Content-Type: application/json" \
-d '{"from":"0xdac17f958d2ee523a2206206994597c13d831ec7","to":"0x910cbd523d972eb0a6f4cae4618ad62622b39dbf","valueWei":"1000000000000000000"}'
Methodology
Honest documentation of how 1F's two highest-judgement endpoints work — bridge tx pairing and address risk scoring. Each doc lists inputs, formulas, and known limitations.
- Bridge tx pairing — per-bridge windows, confidence formula
tier(40) + value(40) + time(20), why pre-deploy index gaps matter. - Risk scoring — sanctioned/mixer/CEX/bridge weights, exposure profile math, "investigative lead, not evidence" caveat.
Authentication
All /api/* endpoints and the /ws WebSocket require an API key. Provide it via:
| Method | Example |
|---|---|
| HTTP header | X-API-Key: your-key-here |
| Query parameter | ?apiKey=your-key-here |
API keys are configured in appsettings.json under the 1F.ApiKeys array, or via the CHAINGRAPH_API_KEYS environment variable (comma-separated).
Arkham-Compatible Endpoints
Response format mirrors intel.arkm.com/api so existing Arkham users can switch with a URL change.
GET /api/intelligence/address/{address}
Returns intelligence summary for an address: transaction counts, top counterparties, tags, and entity data.
| Parameter | In | Description |
|---|---|---|
address | path | Hex address (0x-prefixed) |
Example request
Example response
GET /api/counterparties/address/{address}?limit=N
Returns the top counterparties for an address, ranked by total transaction count (sent + received).
| Parameter | In | Description |
|---|---|---|
address | path | Hex address (0x-prefixed) |
limit | query | Max results (default 25, max 100) |
Example request
Example response
GET /api/intelligence/search?query=0x...
Search for addresses by hex prefix. Returns up to 20 matching addresses from the index.
| Parameter | In | Description |
|---|---|---|
query | query | Hex address prefix to search |
Example request
Example response
Cross-1F Endpoints
GET /api/graph/neighbors/{address}?direction=out|in|both&limit=N
Returns edges (transactions) for an address. Supports directional filtering and pagination.
| Parameter | In | Description |
|---|---|---|
address | path | Hex address (0x-prefixed) |
direction | query | out (default), in, or both |
limit | query | Max edges returned (default 100, max 10000) |
Example request
Example response
GET /api/graph/bfs/{address}?hops=3&maxResults=100
Breadth-first search from an address. Discovers all reachable addresses within N hops. Essential for fund tracing and cluster analysis.
| Parameter | In | Description |
|---|---|---|
address | path | Starting hex address |
hops | query | Max traversal depth (default 3, max 6) |
maxResults | query | Max paths returned (default 100, max 10000) |
Example request
Example response
GET /api/graph/shortest-path/{from}/{to}?maxHops=5
Find the shortest path between two addresses in the transaction graph. Returns up to 5 shortest paths.
| Parameter | In | Description |
|---|---|---|
from | path | Source hex address |
to | path | Destination hex address |
maxHops | query | Max traversal depth (default 5, max 8) |
Example request
Example response
Natural Language Query
POST /api/query
Submit a question in plain English. The LLM translates it into graph query primitives and executes them against the index. Requires a Groq API key to be configured.
Request body
Example request
Example response
appsettings.json or via GROQ_API_KEY env var. Returns an error if not configured.
Meta
GET /api/stats
Returns index statistics: total addresses, edges, hash table size, and load status.
Example request
Example response
GET /api/chains
Returns the list of supported chains and their ingestion status.
Example request
Example response
Real-Time Event Stream
Subscribe to live mempool + confirmed-tx events across 13 EVM chains. Filter by chain, address, token (with calldata substring scan for Uniswap/Pancake-style swaps), protocol decoder name, and origin chain (for cross-chain bridge pairing). Server pushes JSON frames over WebSocket with per-plan rate caps.
POST /api/stream/subscribe
Create a subscription. Returns a subscriptionId and a ready-to-use wsUrl.
curl -s -X POST https://1f.ai/api/stream/subscribe \
-H "x-api-key: $KEY" -H "content-type: application/json" \
-d '{
"chains": ["bsc", "ethereum"],
"tokens": ["0x2170ed0880ac9a755fd29b2688956bd959f933f8"],
"protocols": ["uniswapV2", "pancake"],
"originChain": "ethereum",
"addresses": ["0xabc..."],
"includePending": true,
"includeConfirmed": false
}'
Filters (all optional, AND-combined):
chains: array of chain slugs. Currently live:ethereum, bsc, polygon, arbitrum, optimism, base, avalanche, linea, scroll, opbnb, zksync, mantle, polygon-zkevm.tokens: array of 0x-addresses. Matches tx.to, ERC-20 transfer recipient, OR substring scan of calldata (catches token-in/token-out inside Uniswap-style swaps).protocols: array of decoder family names (e.g.uniswapV2,pancake,curve,aave,tornado,layerzero). See /api/decoders for the live list.originChain: filter to events whose source chain (via BridgeMessageRegistry pairing) matches this slug.addresses: matches tx.from, tx.to, or ERC-20 transfer recipient.
Plan caps (events/sec; over-cap clients get {"type":"throttled","dropped":N} heartbeats every 5s instead of disconnect):
| Plan | Cap |
|---|---|
| Free | 5/sec |
| Starter | 50/sec |
| Pro | 500/sec |
| Enterprise | unlimited |
WS /api/stream/ws?subscriptionId=&apiKey=
WebSocket — server pushes one JSON frame per matched event. The apiKey on the WS URL must match the one that created the subscription.
websocat "wss://1f.ai/api/stream/ws?subscriptionId=$SID&apiKey=$KEY"
# >> {"type":"hello","subscriptionId":"...","plan":"pro","capPerSec":500}
# >> {"type":"pending","chain":"bsc","txHash":"0x...","from":"0x...","to":"0x...",
# "valueWei":1.2e18,"protocol":"ERC-20 transfer","decodedProtocol":"uniswapV2.swap",
# "erc20To":"0x...","erc20Value":4.2e22,"seenAtUtc":"2026-05-03T02:22:42Z"}
# >> {"type":"heartbeat","dropped":0,"ts":"..."} // every 5s
# >> {"type":"throttled","dropped":127,"ts":"..."} // when capped
ChainGraph__Chains__<chain>__wssUrl=... (Alchemy, QuickNode, NodeReal Meganode, Helius). The endpoint surface and filter semantics are identical regardless of upstream.
GET /api/stream/list DELETE /api/stream/unsubscribe
List the API key's active subscriptions, or remove one by id. Only the original publisher (matching key) can unsubscribe.
Forensics & Risk Screening
POST /api/forensics/screen
Bulk-screen up to 1,000 addresses per call. Returns BLOCK / REVIEW / WARN / ALLOW per address with reason codes (sanctions hit, mixer touch, hacker-active, fraud network, mule pattern). Designed to be called at withdrawal-creation time.
curl -s -X POST https://1f.ai/api/forensics/screen \
-H "x-api-key: $KEY" -H "content-type: application/json" \
-d '{"addresses":["0x...","0x..."]}'
POST /api/forensics/screen/subscribe
Register a webhook that fires when a watched address interacts with a flagged counterparty (sanctions, mixer, hacker-active, fraud network). Body: {address, webhookUrl, hmacSecret}. Webhook payload is HMAC-SHA256 signed in the X-1F-Signature header.
GET /api/forensics/exposure-multihop/{address}?dir=in&hops=2
Multi-hop weighted exposure score. dir=in = "every address that sent funds to this seed within N hops" (the reverse-sweep pattern in Method 2.4 of Investigator-Methods). dir=out for forward exposure. Each hop's weight decays; results sorted by exposure score.
GET /api/forensics/scam-network/{address}
Given a seed scam address, BFS 2 hops and surface candidate cluster members scored by shared-funder + shared-receiver overlap within 24-hour windows. Implements first-hop cluster mapping from Method 2.2.
GET /api/forensics/cex-exposure/{address}
Per-CEX deposit/withdrawal counts and USD totals. Identifies which exchanges this address has touched and the direction of flow.
GET /api/forensics/mixer-correlate/{address}
For an address that has interacted with Tornado/Railgun/Privacy Pools, returns candidate withdrawal endpoints based on commitment-nullifier pairing + timing analysis.
POST /api/simulate/preflight
Pre-confirmation risk check. Body is a partially-signed tx (or just from/to/value). Runs the full screen against the destination + decodes the calldata for protocol-level red flags. Fires before the tx hits a block.
KYC & Sanctions
POST /api/kyc/screen
Wallet-level KYC decision. Returns BLOCK / REVIEW / WARN / ALLOW with mule-pattern, synthetic-account, and fraud-network signals. Call this during your KYC flow with the wallet the customer is depositing from. Pairs with off-chain KYC vendors (Persona, Onfido, Veriff) — we are the on-chain layer.
GET /api/sanctions/check/{address} GET /api/sanctions/stats
OFAC SDN match check. Refreshed daily from upstream OFAC feeds. /stats returns total entries + last refresh time.
Entity & Attribution
GET /api/entity/{address}
Aggregated entity card: name, category, jurisdiction, icon, color, confidence, source list, summary counts (transfers/deposits/withdrawals/sentUsd/receivedUsd), top-20 counterparties with category labels, related cluster (if any).
GET /api/known-labels/{address} GET /api/known-labels
Curated label store backed by Sybil verified.json, Etherscan name tags, OFAC, and community-feed posts. Single-address lookup or full dump.
GET /api/custom-entities POST /api/custom-entities DELETE /api/custom-entities/{address}
Per-customer entity overrides. Set name, category, icon, color on the canvas; persists across sessions. /lookup returns the resolved attribution (custom takes precedence over global).
GET /api/notes/{address} POST /api/notes
Investigator notes attached to an address. Multi-author with timestamps; visible across the customer's team.
Cross-Chain Tracing
GET /api/cross-chain/follow/{txHash}
Given a source-chain bridge tx hash, return the paired destination-chain tx — exact match via BridgeMessageRegistry for LayerZero/Wormhole/CCTP/Stargate/Hop/Across, plus heuristic match for Synapse/deBridge. Falls back to the heuristic (value, time-window, bridge-id) tuple when no message id is available.
GET /api/cross-chain/portfolio/{address}
Per-chain balance snapshot for the address. Aggregated USD value, breakdown by chain + token.
GET /api/cross-chain/bridges/{address} GET /api/cross-chain/timeline/{address} GET /api/cross-chain/transfers/{address}
Bridges this address has used (with frequency + USD volume), full chronological cross-chain timeline, and token-transfer breakdown.
GET /api/bridge-messages/source/{txHash} GET /api/bridge-messages/stats
Direct lookup into the BridgeMessageRegistry. Records src→dst pairings extracted by Tier-1, Tier-2, and Tier-5 bridge decoders (LayerZero V1/V2, Wormhole, CCTP, Stargate, Hop, Across, Synapse, deBridge, Arbitrum, OP-stack, Polygon PoS, Binance Bridge, Avalanche Bridge, Linea, Scroll, Mantle, zkSync, Polygon zkEVM).
Mixer Tracing
GET /api/mixer-commitments/deposit/{txHash} GET /api/mixer-commitments/withdraw/{txHash} GET /api/mixer-commitments/stats
Tornado / Railgun / Privacy Pools / Aztec / THORChain commitment + nullifier registry. Given a deposit, returns matching withdraws (or candidates if not yet revealed). Given a withdraw, returns the deposit set narrowed by anonymity-set heuristics.
GET /api/forensics/tornado/pools
List of tracked Tornado pools (0.1/1/10/100 ETH on mainnet, equivalents on each chain) with active anonymity set sizes.
Investigator-Merged Clusters
Group N addresses (typically the first-hop withdrawal addresses of unrelated victims) under one shared name, icon, color. The cluster becomes a first-class entity referenced everywhere downstream.
POST /api/clusters/merge
curl -X POST https://1f.ai/api/clusters/merge \
-H "x-api-key: $KEY" -H "content-type: application/json" \
-d '{
"name": "40% Return Scam",
"category": "scam",
"icon": "🎣", "color": "#f85149",
"addresses": ["0x...", "0x...", "0x..."],
"note": "Merged from victims #1042, #1118, #1244"
}'
GET /api/clusters GET /api/clusters/{clusterId} GET /api/clusters/by-address/{address} DELETE /api/clusters/{clusterId}
Cross-Tenant Community Feed
Publish newly-identified scam clusters to a shared feed. Other customers pull the feed and auto-merge fresh entries into their local EntityStore with source="community". Each post is signed with a per-publisher SHA-256 fingerprint.
POST /api/community/share
curl -X POST https://1f.ai/api/community/share \
-H "x-api-key: $KEY" -H "content-type: application/json" \
-d '{
"address": "0x...",
"category": "scam",
"name": "Pig butchering — Telegram group XYZ",
"evidenceUrl": "https://...",
"note": "Confirmed by 3 victim reports"
}'
GET /api/community/feed?limit=100&since=ISO GET /api/community/by-address/{address} POST /api/community/retract GET /api/community/stats
Pull the feed (paginated by since), look up posts for a specific address, retract a post (publisher-only — fingerprint must match), or check active post count.
Cases & Court-Ready Reports
GET /api/cases POST /api/cases GET /api/cases/{caseId} POST /api/cases/{caseId}/addresses
One case per investigation. Multiple addresses, full audit log of every action by every actor (timestamped, append-only).
GET /case/{caseId}/report GET /api/cases/{caseId}/report-data
Print-styled HTML report (browser File→Print = court-ready PDF). Every case bundle is signed with HMAC-SHA256 chain-of-custody over {caseId}|{updatedAt}|{caseCanonical}|{reportTime}|{actor} keyed by CASE_SIGNING_KEY. Tamper-detectable via SHA-256 over canonical case body.
GET /case/{caseId}/sar
FinCEN Form 111-style SAR adapter. Renders Filing Institution / Subject Information / Suspicious Activity / Narrative + Audit / Cryptographic Integrity sections. Auto-derives typology checkboxes from address categories. Companion document to an officially-filed Form 111 — not a substitute.
AI Investigation Agent
GET /api/agent/investigate/{address}
End-to-end automated investigation of a target address. Combines: entity attribution, cluster lookup, multi-hop in/out exposure, CEX endpoints, mixer correlation, sanctions check, scam-network BFS, and a natural-language narrative summary. Returns a structured findings[] + narrative blob suitable for display in an investigator UI.
Newsworthy & Threat Feed
GET /api/newsworthy
Last 1,000 detected events from ThreatMonitorService. Six detector classes: SANCTIONED_TOUCH, HACKER_ACTIVE, MIXER_INFLOW_BURST, CEX_LARGE_OUTFLOW, FRAUDULENT_ENTITY_TX, SCREEN_SUBSCRIBE_FLAG. 60-second scan interval. Each detection also fires registered webhooks.
Coverage & Meta
GET /api/coverage GET /api/status/chains
Per-chain status: enabled / mempool / WSS active / last block ingested / index size on disk. Public (no API key).
GET /api/decoders
Live registry of protocol decoders. Currently registered: Uniswap V2/V3, Curve, Balancer, 1inch, PancakeSwap V3, Aerodrome, LayerZero V1/V2, Wormhole, Stargate, Hop, Across, Synapse, CCTP, deBridge, Arbitrum L1 Inbox, OP-stack L1 Bridge, Polygon PoS, Binance Bridge, Avalanche Bridge, Linea/Scroll/Mantle/zkSync/Polygon zkEVM canonical, Aave V2/V3, Compound V2/V3, Lido, EigenLayer, Maker DSR, Tornado, Railgun, Privacy Pools, Aztec, THORChain. Each decoder lists its selectors, name, category, optional contract address, and chain id.
GET /api/reorgs
Recent reorganizations detected by ReorgWatcherService. Detect-and-flag only — does not roll back the index. Useful for downstream consumers to know when to re-fetch a recent block range.
Legacy: Binary Graph WebSocket
ws://host/ws
Binary frame protocol for real-time graph exploration. Used by the Graph Explorer UI.
The WebSocket accepts binary frames where the first byte is the command type:
| Command | ID | Payload |
|---|---|---|
| NEIGHBORS_OUT | 1 | uint32 addr_id |
| NEIGHBORS_IN | 2 | uint32 addr_id |
| BFS | 3 | uint32 addr_id + uint8 hops + uint16 maxResults |
| BLOCK_LOOKUP | 4 | uint32 block_offset |
| ADDR_EXISTS | 5 | uint32 addr_id |
| STATS | 6 | (none) |
Responses are binary frames. See the Graph Explorer source for parsing details.