The pre-trade token risk gate for agents that move money
POST /v2/verdict returns one adjudicated decision — avoid, caution, or clear — for any token, with full signal detail. Mint a keyed FREE tier credential instantly, then use x402 USDC as the no-signup overflow rail when a daily quota is exhausted. No account or OAuth.
Rail 1
Keyed FREE tier
Mint a key instantly with POST /v2/keys, no auth required. Daily quotas are tracked separately for triage, fast, and deep calls.
Rail 2
x402 overflow
After a FREE quota is used, pay the returned 402 challenge with Base or Solana USDC and retry. Anonymous callers can use the same pay-per-call rail. No signup.
ACP
Virtuals agent
Pre-fund a signed API key for higher usage, or request the same decision through the Virtuals ACP offering preTradeTokenRiskCheck.
What you get
The decision is nested at verdict.action. This recorded v2 response is generated from the checked-in contract fixture; payment identifiers are removed while required schema fields remain.
{
"schema_version": "1.0",
"request": {
"address": "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN",
"chain": "solana",
"level": "fast",
"include": []
},
"verdict": {
"action": "caution",
"score": 55,
"grade": "D",
"risk_level": "high",
"confidence": 0.8,
"summary": "Analysis timed out — using available on-chain data only."
},
"signals": [
{
"id": "honeypot_simulation",
"category": "security",
"severity": "critical",
"pass": true,
"value": "ok",
"detail": "Sell simulation passed."
},
{
"id": "mint_authority",
"category": "security",
"severity": "critical",
"pass": true,
"value": "revoked",
"detail": "Mint authority revoked — cannot inflate supply."
},
{
"id": "freeze_authority",
"category": "security",
"severity": "high",
"pass": true,
"value": "revoked",
"detail": "Freeze authority revoked — holders cannot be frozen."
},
{
"id": "top10_holder_concentration",
"category": "distribution",
"severity": "high",
"pass": false,
"value": 67,
"detail": "Top-10 wallets hold 67.0% of supply."
},
{
"id": "contract_verified",
"category": "transparency",
"severity": "medium",
"pass": true,
"value": "verified",
"detail": "Contract source code is publicly verified."
},
{
"id": "liquidity_vs_mcap",
"category": "liquidity",
"severity": "info",
"pass": true,
"value": 0.0642,
"detail": "Liquidity ratio: 6.42% of market cap."
}
],
"agents": [
{
"name": "FreeTierAI",
"score": 5.5,
"sentiment": "neutral",
"key_findings": [],
"reasoning": null
}
],
"data_freshness": {
"onchain_age_seconds": 6,
"market_age_seconds": 6,
"social_age_seconds": null
},
"data_confidence": 1,
"insufficient_data": false,
"lifecycle": null,
"timing": null,
"observation_id": "4434bc13-5b0d-42bc-88f4-7df50e961b66",
"cached": false,
"generated_at": "2026-07-18T18:47:07.801107Z",
"latency_ms": 5268,
"billing": {
"rail": "free",
"amount_usdc": "0",
"tx": null,
"degraded": true,
"retry_voucher": null
}
}Service levels
| Level | Price | Latency (p95) | What runs |
|---|---|---|---|
| triage | $0.001 USDC | deterministic pre-check | Deterministic-only lane |
| fast | $0.01 USDC | ~2.5s p95 | Fast heuristic verdict path |
| deep | $0.025 USDC | 30-45s | Full 6-agent swarm — the token examined from every angle |
Pricing is served live at GET /v2/verdict/info. The values shown were verified on 2026-07-18; cache hits then cost 20% of the fresh price. Verify live before hardcoding.
Quickstart — FREE key
Mint a key with no auth:
curl -s -X POST https://api.vswarm.io/v2/keys \
-H "Content-Type: application/json" \
-H "X-VS-Integration: web-docs" \
-d '{"channel_ref":"web-docs"}'Copy api_key from the response, then make the first verdict call:
curl -s -X POST https://api.vswarm.io/v2/verdict -H "Content-Type: application/json" -H "X-VS-Integration: web-docs" -H "X-API-Key: vs1_free_YOUR_KEY" -d '{"address":"0x6982508145454Ce325dDbE47a25d4ec3d2311933","chain":"base","level":"fast"}'Mint response: {"api_key":"vs1_free_...","tier":"free","daily_limits":{...},"quickstart":"<one-line curl>"}
Overflow — x402
An anonymous call, or a FREE-key call after its level quota is exhausted, returns a directly payable challenge:
curl -s -X POST https://api.vswarm.io/v2/verdict \
-H "Content-Type: application/json" \
-H "X-VS-Integration: web-docs" \
-d '{"address":"0x6982508145454Ce325dDbE47a25d4ec3d2311933","chain":"base","level":"fast"}'{
"x402Version": 1,
"error": "Payment Required",
"accepts": [{
"scheme": "exact",
"network": "base-mainnet",
"maxAmountRequired": "10000",
"payTo": "0x...",
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"resource": "/v2/verdict/base/0x6982...",
"description": "VerdictSwarm fast verdict — 0.01 USDC",
"maxTimeoutSeconds": 300
}]
}Pay the challenge on-chain and retry with the payment proof. See the coinbase/x402 client SDKs (Python/TypeScript) for automatic payment handling.
Prepaid credits
For higher prepaid usage, pass a funded signed key. No X-PAYMENT header is needed:
# Pass your key in the X-API-Key header (no X-PAYMENT header needed)
curl -s -X POST https://api.vswarm.io/v2/verdict \
-H "Content-Type: application/json" \
-H "X-VS-Integration: web-docs" \
-H "X-API-Key: vs1_agent_your-key-id_your-sig" \
-d '{"address":"0x6982508145454Ce325dDbE47a25d4ec3d2311933","chain":"base","level":"fast"}'Check your balance without spending a call:
curl -s https://api.vswarm.io/v2/credits/balance \ -H "X-VS-Integration: web-docs" \ -H "X-API-Key: vs1_agent_your-key-id_your-sig"
Python client (x402 + credits)
import httpx
from x402.client import handle_402 # pip install x402
async def get_verdict(address: str, chain: str, level: str = "fast") -> dict:
url = "https://api.vswarm.io/v2/verdict"
payload = {"address": address, "chain": chain, "level": level}
async with httpx.AsyncClient() as client:
resp = await client.post(url, json=payload, headers={"X-VS-Integration": "python-x402"})
if resp.status_code == 402:
resp = await handle_402(resp, client, wallet_private_key=WALLET_KEY)
resp.raise_for_status()
return resp.json()
verdict = await get_verdict("0x6982508145454Ce325dDbE47a25d4ec3d2311933", "base")
action = verdict["verdict"]["action"] # "avoid" | "caution" | "clear"Discovery endpoints
Free, unauthenticated. Check these before hardcoding prices.
GET /v2/verdict/infocurl https://api.vswarm.io/v2/verdict/info -H "X-VS-Integration: web-docs"
GET /.well-known/x402x402 discovery document for agent marketplaces (Bazaar, ACP catalog).
curl https://api.vswarm.io/.well-known/x402 -H "X-VS-Integration: web-docs"
Rate limits
Per-payer 5 rps, burst 20 — keyed by credits key-id, then x402 payer address, then client IP (this covers the unauthenticated 402-challenge path too). Exceeded limits return 429 with Retry-After. Current values are always live via GET /v2/verdict/info.
Retry vouchers
If a scan fails after a successful payment, the error response includes a retry_voucher. Retry with the X-Retry-Voucher header — honored once, 24h TTL. You are never charged twice for a failed scan.
Error codes
All errors return structured JSON with a stable code field.
| Code | HTTP | Meaning |
|---|---|---|
| payment_required | 402 | No payment or quota/credits exhausted — details has a payable challenge |
| payment_invalid | 402 | Payment failed verification or key revoked |
| invalid_address | 400 | Address format doesn't match chain |
| unsupported_chain | 400 | Chain is not solana or base |
| upstream_data_unavailable | 503 | On-chain data providers unreachable |
| internal_error | 500 | Scan failed after payment — check for retry_voucher in details |
| rate_limited | 429 | Exceeded per-payer rps/burst — back off per Retry-After header |
Agent Commerce Protocol (ACP)
The same pre-trade decision is available as a Virtuals ACP offering — preTradeTokenRiskCheck, $0.05 per check, avoid / caution / clear with score, top signals, and report URL. Any agent on Virtuals Protocol can request a check and pay with USDC, no API key needed.
Full request schema
addressToken contract/mint (required)chainsolana | base (required)leveltriage | fast | deep (default: fast)max_staleness_secondsVerdict-cache tolerance; 0 bypasses the response cache. Provider data may still be cache-served (5min–24h TTLs).context.intended_actionbuy | sell | hold (optional)context.position_size_usdOptional position sizing hintTry it
Use the same address in the web scanner, or read the full spec in the repo docs.
Example token
0x6982508145454Ce325dDbE47a25d4ec3d2311933