Documentation
AlphaFlow's headline capability is snapshot sybil screening: submit an airdrop claimant list, get back the clusters of wallets operated together, with the on-chain evidence behind every flag.
Getting Started
- Generate a key from API Keys in the dashboard
POST /api/sybil/checkwith your claimant list — you get back ajobId- Poll
GET /api/sybil/jobs/:iduntil status iscomplete - Pull the forwardable summary or CSV from
/api/sybil/jobs/:id/report
Prefer not to write code? Snapshot Screening in the dashboard runs the same pipeline through a UI.
Authentication
Two accepted credentials, checked in this order: an af_ API key, then the dashboard session cookie. Session users are treated as DEVELOPER tier and aren't counted against any key's quota.
Authorization: Bearer af_your_key_here
OpenAPI Spec
The full route inventory — every endpoint, method, and tier requirement — is available as a machine-readable OpenAPI 3.0 document, generated from the same route source this page used to be hand-transcribed from. Import it directly into Postman, Insomnia, or Swagger UI.
GET /api/openapi.json
description field rather than guessing at a shape.Response Shape
Every successful response is wrapped as { "data": ... }, with pagination or other response context under a sibling meta key when present — data is always exactly the resource you asked for, never mixed with metadata about the response itself. Errors are unchanged: { "error": "..." } with a non-2xx status. The CSV report format is the one exception — it returns a raw CSV body, not JSON.
response.data now.Async Jobs
The three forensics endpoints are enqueue-only. A 500-wallet snapshot fans out to thousands of on-chain lookups, so the work runs on a background worker rather than inside the request. POST → 202 {jobId, poll} → poll until complete or failed.
/api/sybil/checkDEVELOPER+Snapshot sybil screening — cluster an airdrop claimant list into wallets operated together
body: { "addresses": [ "<base58>", ... ] }
/api/sybil/jobs/:id/api/consolidation/scanDEVELOPER+Trace claimant wallets forward to shared sink addresses (farm treasuries and CEX deposit accounts)
body: { "addresses": [ "<base58>", ... ] }
/api/consolidation/jobs/:id/api/fundflow/traceDEVELOPER+Trace outbound fund flow from any address (exploit / rug tracing)
body: { "address": "<base58>", "sinceTimestamp": 1719792000 }
/api/fundflow/jobs/:idStatus moves pending → processing → complete or failed. Poll every few seconds; there's no webhook yet.
Batch caps per request
Separate from the daily rate limit below — this caps addresses in one call, because addresses are the real unit of upstream cost. Applies to /sybil/check and /consolidation/scan.
Snapshot Screening
1 — Enqueue the snapshot:
curl -X POST https://getalphaflow.xyz/api/sybil/check \
-H "Authorization: Bearer af_..." \
-H "Content-Type: application/json" \
-d '{"addresses": ["Wallet1...", "Wallet2...", "Wallet3..."]}'
# 202 Accepted
# {
# "data": {
# "jobId": "clx7f2k9a0001abcd",
# "status": "pending",
# "submitted": 3,
# "poll": "/api/sybil/jobs/clx7f2k9a0001abcd"
# }
# }2 — Poll until it completes:
curl https://getalphaflow.xyz/api/sybil/jobs/clx7f2k9a0001abcd \
-H "Authorization: Bearer af_..."
# while status is "pending" or "processing", wait and poll again.
# on "complete", data holds the result (every success response is
# wrapped in { data }, with optional pagination/context under meta):
# {
# "data": {
# "status": "complete",
# "submitted": 3,
# "flaggedCount": 2,
# "clusters": [
# {
# "confidence": 0.82,
# "signals": ["shared_funder", "behavior_match"],
# "memberCount": 2,
# "sharedFunder": "Funder...",
# "members": ["Wallet1...", "Wallet2..."],
# "smartMoneyMembers": [],
# "evidence": [
# {
# "address": "Wallet1...",
# "funderAddress": "Funder...",
# "fundingTxSignature": "5xY...",
# "commonFeePayer": "Payer...",
# "behaviorFingerprint": "a91c..."
# }
# ]
# }
# ],
# "knownFarmers": [
# { "address": "Wallet2...", "timesFlagged": 3, "confidence": 0.88 }
# ],
# "unclustered": ["Wallet3..."]
# }
# }Response fields
signals[]Per cluster — which detectors fired: shared_funder, shared_fee_payer, behavior_match, timing_sync, funding_burst, age_batch, known_farm_wallet
evidence[]Per cluster member — { address, funderAddress, firstFundedAt, fundingTxSignature, commonFeePayer, behaviorFingerprint }. The receipts that make an exclusion defensible in public
knownFarmers[]Submitted addresses that earlier screenings already flagged, with timesFlagged and confidence. Populated whether or not this run clustered them again
band / bandLabelPer cluster, on the report endpoint — likely_organic (<0.5), needs_review (0.5–0.75), high_confidence (>=0.75). Maps the raw score onto the decision you actually have to make. Note that 0.6, the threshold at which a cluster is recorded to cross-job memory, sits INSIDE needs_review: strong enough to remember, not strong enough to exclude on alone
smartMoneyMembersPer cluster — members with a verified profitable trading history. Their presence LOWERS the cluster confidence; review these before excluding them
band field states this directly per cluster. Check smartMoneyMembers before excluding anyone: those wallets have a real trading record behind them.Reports
GET /api/sybil/jobs/:id/report turns a completed job into something you can forward or feed to tooling. JSON gives counts, clusters sorted by confidence, a bands breakdown, and a plain-English summary paragraph; ?format=csv gives one row per flagged address. Non-complete jobs return the same status shape as the poll route, so a client can point at this endpoint the whole way through.
# JSON summary — the shape you forward to a protocol team curl https://getalphaflow.xyz/api/sybil/jobs/clx7f2k9a0001abcd/report \ -H "Authorization: Bearer af_..." # CSV — one row per flagged address, for your exclusion tooling curl "https://getalphaflow.xyz/api/sybil/jobs/clx7f2k9a0001abcd/report?format=csv" \ -H "Authorization: Bearer af_..." \ -o sybil-report.csv # address,clusterIndex,confidence,signals,funderAddress,fundingTxSignature,band
Full enqueue → poll → report loop:
JOB=$(curl -s -X POST https://getalphaflow.xyz/api/sybil/check \ -H "Authorization: Bearer $AF_KEY" \ -H "Content-Type: application/json" \ -d @snapshot.json | jq -r .data.jobId) until [ "$(curl -s https://getalphaflow.xyz/api/sybil/jobs/$JOB \ -H "Authorization: Bearer $AF_KEY" | jq -r .data.status)" = "complete" ]; do sleep 5 done curl -s "https://getalphaflow.xyz/api/sybil/jobs/$JOB/report?format=csv" \ -H "Authorization: Bearer $AF_KEY" -o sybil-report.csv
Bulk Export
The report endpoints above cover one job, case, or wallet at a time. For everything at once, two list-level export endpoints return a summary row per record rather than each record's full detail — pull the per-record report separately for anything that needs deeper inspection.
GET /api/cases/export?format=csv GET /api/sybil/jobs/export?format=csv
?format=csv returns a raw CSV body. There is no bulk PDF — per-case and per-job PDF already exist at their individual report endpoints, and a combined multi-record PDF wasn't built (documented as a gap, not a silent omission).Other Forensics
Consolidation scan — trace known claimants forward to the addresses they swept into. Sinks receiving from 3+ claimants surface as farm treasuries; a sink that is itself a labeled CEX deposit address is its own tell.
curl -X POST https://getalphaflow.xyz/api/consolidation/scan \
-H "Authorization: Bearer af_..." \
-H "Content-Type: application/json" \
-d '{"addresses": ["Claimant1...", "Claimant2..."]}'
# then: GET /api/consolidation/jobs/<jobId>
# result: { claimantsScanned, sinks: [{ address, inflowCount, totalSol,
# fromClaimants, knownDestination }], unresolved }Fund-flow trace — follow outbound SOL from any root address, flagging hops that land on known CEX/bridge destinations.
curl -X POST https://getalphaflow.xyz/api/fundflow/trace \
-H "Authorization: Bearer af_..." \
-H "Content-Type: application/json" \
-d '{"address": "SourceWallet..."}'
# then: GET /api/fundflow/jobs/<jobId>Wallet API
Synchronous reads — these return results inline, no job needed.
/api/wallet/:addressFREE+Wallet score and stats
/api/wallet/:address/intelligenceFREE+Full profile — reason codes, reputation, risk, fund flow, relationships, token activity, outcomes
/api/wallet/:address/reputationFREE+Allow / review / block recommendation
/api/wallet/:address/historyFREE+Wallet's early-buy trading history
/api/wallet/:address/outcomesFREE+Outcomes of every alert fired on this wallet
/api/wallet/:address/sybilFREE+Read prior sybil cluster membership (no new detection)
/api/wallet/:address/token-riskFREE+Wallet's own rug exposure from tokens it has bought
/api/wallet/:address/fundflowDEVELOPER+Trace outbound fund flow from this wallet (synchronous convenience read)
/api/token-risk/:mintDEVELOPER+Scan a token's mint authority, LP lock, holder concentration
/api/token/:mint/lineageDEVELOPER+Mint metadata plus a best-effort creation event and mint/burn candidates
/api/token/:mint/concentrationDEVELOPER+Point-in-time top1/top5/top10 holder concentration snapshot
/api/token/:mint/lp-pull-candidatesDEVELOPER+Scans the token's top 10 holders for candidate large liquidity withdrawals
/api/wallet-reputation/:address is deprecated — it still works and returns the same fields, plus "deprecated": true. Move to /api/wallet/:address/intelligence.Rate Limits
Requests per UTC day. Same numbers api-auth.ts enforces server-side — not a second copy that could drift. Enqueueing a job and each poll both count as one request.
Status & Error Codes
A job that fails during processing is not an HTTP error: the poll route returns 200 with status: "failed" and an error message. Check the body, not just the code.
SDK
fetch call or curl works without one. If you build a wrapper library, we'd genuinely like to hear about it.Best Practices
- Split snapshots larger than your tier cap into sequential batches — clustering runs per job, so keep wallets you expect to be related in the same batch
- Poll every 3–5 seconds, not tighter; polls count against your daily limit
- Persist the
jobId. Results stay retrievable, so a dropped connection never means re-running the batch - Never auto-exclude on confidence alone — read
evidence[]and checksmartMoneyMembersfirst /wallet/:address/token-riskand/token-risk/:mintanswer different questions — a wallet's own exposure vs. a specific token's risk vectors — check you're calling the right one- Fund-flow and consolidation only label CEX/bridge destinations that are in the verified registry. An empty
knownDestinationmeans unlabeled, not unrelated