Market Abuse
Scan a wallet for on-chain manipulation patterns, and read the report the scanner produces.
A market abuse scan looks at a wallet's on-chain behaviour and scores it against four manipulation patterns: pump and dump, insider trading, smurfing and wash trading. Each detector produces a score, a threshold, and the detail of every signal it examined.
Scans are asynchronous. Launching one returns immediately with a job_id;
the report appears later, under that same id. There is no callback: poll the
result endpoint.
Launching a scan
POST /v1/mabu/runs with a wallet and a chain:
{ "wallet": "0xd90e2f925da726b50c4ed8d0fb90ad053324f31b", "chain": "ethereum" }The response carries the only identifier you need to keep:
{ "status": "ok", "job_id": "2966a324-2b67-48ee-a0e1-3fe6b123e1b2" }That job_id is both the run id and the scan_id its report is filed under.
chain accepts either the full name or your wallet's own chain code, so
ethereum and ETH both work. Supported: ethereum, bitcoin, bsc,
polygon, arbitrum, optimism, base, solana.
The scanned wallet is added to your organization's wallets if it is not already there.
Following a run
A run moves through a small set of states:
| Status | Meaning |
|---|---|
PENDING | created, not yet handed off |
DISPATCHED | handed off and running |
DONE | its report exists |
FAILED | the hand-off failed, or nothing was published in time |
Use GET /v1/mabu/runs/search to list runs, filtered by status, chain,
wallet, or a prefix of the run id. GET /v1/mabu/runs/detail?id=… returns a
single run.
Reading a report
GET /v1/mabu/runs/result?scan_id=… returns the report.
A 404 means the scan has not published anything yet. That is the normal
state of a run still in progress, not an error: poll until it answers.
The payload is the ingestion envelope; the report itself sits under data.
Start with data.summary, then open data.patterns for the detail.
Signal statuses are the important part
Every detector reports a list of signals, and each signal carries one of three statuses:
| Status | Meaning |
|---|---|
confirmed | the signal fired, and its points count toward the score |
not_confirmed | assessed, and absent |
not_evaluable | could not be assessed at all |
not_evaluable is not a negative result. A signal that needs data the scan
could not obtain is reported as unanswerable rather than as clean, so a low
score never silently means "nothing found" when it actually means "nothing was
looked at". Read coveragePct and confidence on a pattern to see how much of
its scoring was reachable.
Counterparties that are a finding in themselves
Mixers and phishing addresses are excluded from the counterparty graph so they
cannot inflate a score. They are listed separately under riskCounterparties,
with their entity and interaction count: excluding them from the scoring is not
the same as hiding them from you.
Scanning on a schedule
A wallet can carry a recurring scan, so you do not have to launch one yourself each time. Schedules live on the wallet, not on the scan:
POST /v1/wallet/schedules
{ "wallet_id": "…", "kind": "MABU", "interval_days": 7, "enabled": true }interval_days runs from 1 to 90: daily at the tightest, quarterly at the
loosest. Enabling a schedule makes its first run due straight away.
GET /v1/wallet/schedules?wallet_id=… lists what a wallet has, and
DELETE /v1/wallet/schedules?wallet_id=…&kind=MABU removes one.
The endpoint is generic on purpose: kind names what recurs, so other kinds of
recurring work will use the same three calls. MABU is the only kind today.
A schedule keeps its cadence even when a launch fails: the reason is kept in
last_error and the next occurrence still stands, because one failed launch is
not a reason to stop watching a wallet. A schedule on a chain the scanner cannot
read is refused when you create it, rather than failing quietly on every
occurrence.
Being told when something is found
A scan that flags raises an alert, which then travels through the notification channels your organization already configured.
| Source | market_abuse |
| Severity | HIGH, or CRITICAL when the worst pattern reaches 1.5x its threshold |
| Entity | the wallet, so the alert links back to it |
| Metadata | the scan id, every flagged pattern with its score and threshold, risk counterparties, and a link to the scan |
A clean scan raises nothing: an alert for every scan would train everyone to ignore them.
A channel that filters on specific sources will not receive these until
market_abuse is added to its list. A channel with no source filter receives
them straight away.
Thresholds
Each detector raises a flag when its score reaches a threshold. GET /v1/mabu/thresholds returns the values in force, with the platform default and
whether you have overridden it.
POST /v1/mabu/thresholds changes only the patterns you send:
{ "thresholds": { "pump_dump": 55, "wash_trading": 80 } }POST /v1/mabu/thresholds/reset drops every override.
Limits worth knowing
A scan reads a bounded window of the wallet's history, not all of it. The
report states exactly how much it read, in data.fetch, and which parts of the
method it could not evaluate, in data.summary. Both are worth reading before
drawing a conclusion from a score.