Developer and Partner API
VerdictSwarm exposes two integration surfaces today: a public pay-per-scan B2A API and partner/private API-key routes for higher-trust integrations.
Public B2A
Pay per scan
Use /api/v1/scan or the /api/v1/pay/scan/* family. No API key is required for baseline access.
Partner Access
API key routes
Use X-API-Key with /api/scan/sync or /api/scan/stream. Keys are provisioned manually today.
Shareable Reports
Cached report lookup
Use /api/report/{address} or /api/report/{chain}/{address} to read a cached public report after a scan exists.
Auth modes
1. Public pay-as-you-go
Start with /api/v1/scan or /api/v1/pay/scan/*. The server grants a limited free quota per IP and then returns 402 with payment instructions for USDC on Solana.
2. Partner/private API key
There is no self-serve API-key issuance flow in the app today. Keys are provisioned manually for partners and internal integrations. When issued, pass them as X-API-Key: YOUR_API_KEY.
3. Staked lane
Wallets with sufficient VSWARM balance can call /api/v1/staked/scan using X-Wallet-Address, X-Wallet-Signature, and X-Timestamp.
Rate limits
Public B2A lane
Free: 10 lifetime scans per IP, plus a global 60 scans/hour IP cap.
Paid standard lane: 10/min, 100/hour, 500/day per IP.
Paid premium lane: 60/min, 500/hour, 5000/day per IP.
API-key lane
Free: 5/day and 10/min.
Pro: 50/day and 60/min.
Pro+: 100/day and 120/min.
Verified endpoints
These routes match the current FastAPI routers under api/routers/.
| Method | Path | Auth | Notes |
|---|---|---|---|
| POST | /api/v1/scan | Free quota or x402 payment | Async-first B2A scan endpoint. Returns cached result immediately or 202 with poll_url. |
| GET | /api/v1/scan/{scan_id}/status | None | Poll async scans until status is complete or failed. |
| POST | /api/v1/pay/scan/basic | Free quota or x402 payment | Quick score lane. |
| POST | /api/v1/pay/scan/standard | Free quota or x402 payment | Security plus tokenomics lane. |
| POST | /api/v1/pay/scan/pro | Free quota or x402 payment | Full 6-agent scan lane. |
| POST | /api/v1/pay/scan/premium | Free quota or x402 payment | Higher-rate paid lane. |
| POST | /api/v1/pay/scan/swarm | x402 payment | Debate-heavy swarm lane. |
| POST | /api/v1/staked/scan | Signed wallet headers | Staked lane for wallets that qualify by VSWARM balance. |
| GET | /api/report/{address} | None | Public shareable report lookup with chain autodetect. |
| GET | /api/report/{chain}/{address} | None | Public shareable report lookup when you want an explicit chain. |
| POST | /api/scan/sync | X-API-Key | Partner/internal synchronous JSON wrapper over the stream scan pipeline. |
| GET | /api/scan/stream | X-API-Key or api_key query param | Partner/internal SSE stream endpoint. |
Example: start a scan
/api/v1/scan is the easiest public entry point. It returns cached data immediately or 202 with a poll URL.
curl -X POST "https://verdictswarm-production.up.railway.app/api/v1/scan" \
-H "Content-Type: application/json" \
-d '{
"address": "DezXAZ8z7PnrnRJjz3wXBoRgixCa6tRLh9sJX7YaB1pB",
"chain": "solana",
"tier": "PRO_PLUS",
"async": true
}'{
"status": "processing",
"scan_id": "6f820e4c-3b7a-4d38-a1c6-9b4b9656ad5d",
"poll_url": "https://verdictswarm-production.up.railway.app/api/v1/scan/6f820e4c-3b7a-4d38-a1c6-9b4b9656ad5d/status",
"retry_after": 15,
"message": "Scan started. Poll poll_url every 15s until status == 'complete'.",
"report_url": "https://vswarm.io/report/DezXAZ8z7PnrnRJjz3wXBoRgixCa6tRLh9sJX7YaB1pB"
}If the free quota for that caller IP is exhausted and no payment signature is attached, the same endpoint returns 402 with payment instructions:
{
"detail": {
"price_usd": "1.00",
"network": "solana",
"token": "USDC",
"token_mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"payment_address": "CoYNmewtotjUhqiE9DTmppZ8EgcVt1vz7GuKBKFa1K8",
"expires_at": 1773360000,
"endpoint": "/api/v1/scan"
}
}Example: poll scan status
Async scans store job state in Redis for up to one hour. Poll every 15 seconds until status becomes complete or failed.
curl "https://verdictswarm-production.up.railway.app/api/v1/scan/<scan_id>/status"
{
"status": "complete",
"data": {
"address": "DezXAZ8z7PnrnRJjz3wXBoRgixCa6tRLh9sJX7YaB1pB",
"chain": "solana",
"depth": "full",
"tier": "pro_plus",
"score": 78.4,
"grade": "B+",
"risk_level": "MEDIUM",
"bots": {
"TechnicianBot": { "score": 7.9, "category": "Technical" },
"SecurityBot": { "score": 8.1, "category": "Safety" }
},
"agent_details": {
"TechnicianBot": {
"score": 7.9,
"sentiment": "bullish",
"category": "Technical",
"confidence": 0.88
}
},
"token": {
"name": "BONK",
"symbol": "BONK",
"price_usd": 0.0000123,
"mcap": 845000000
},
"security_findings": [],
"consensus_narrative": "The swarm found a liquid, established meme token with manageable but non-zero concentration risk.",
"scoring": {
"weights": {
"Technical": 0.24,
"Safety": 0.28,
"Tokenomics": 0.18,
"Social": 0.15,
"Macro": 0.15
},
"tokenMaturity": "mature",
"regimeLabel": "risk_on"
},
"scanned_at": "2026-03-11T19:05:12Z",
"tier_used": "PAYG",
"cached": false
}
}Example: get a cached report
Use the public report endpoint after a scan exists. This returns the tier-gated cached report payload used by the report page.
curl "https://verdictswarm-production.up.railway.app/api/report/solana/DezXAZ8z7PnrnRJjz3wXBoRgixCa6tRLh9sJX7YaB1pB"
Example: API-key request
Partner/private routes use X-API-Key. The current synchronous JSON route is /api/scan/sync.
curl -X POST "https://verdictswarm-production.up.railway.app/api/scan/sync" \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_API_KEY" \
-d '{
"address": "DezXAZ8z7PnrnRJjz3wXBoRgixCa6tRLh9sJX7YaB1pB",
"chain": "solana",
"tier": "PRO"
}'{
"address": "DezXAZ8z7PnrnRJjz3wXBoRgixCa6tRLh9sJX7YaB1pB",
"chain": "solana",
"score": 78.4,
"grade": "B+",
"risk_level": "MEDIUM",
"bots": {
"TechnicianBot": {
"score": 7.9,
"category": "Technical",
"reasoning": "Strong liquidity and holder depth."
}
},
"agent_details": {
"TechnicianBot": {
"score": 7.9,
"sentiment": "bullish",
"category": "Technical",
"confidence": 0.88
}
},
"scoring": {
"weights": {
"Technical": 0.24,
"Safety": 0.28
},
"tokenMaturity": "mature",
"regimeLabel": "risk_on"
}
}Response schema notes
scoreFinal 0-100 score.gradeLetter grade derived from score.risk_levelLOW, MEDIUM, HIGH, or CRITICAL.botsPer-agent output including score, category, and sometimes reasoning.agent_detailsPer-agent score, sentiment, category, confidence, and findings.scoring.weightsNormalized category weights used for the final score.scoring.tokenMaturityCurrent maturity label, such as new, established, or mature.scoring.regimeLabelMarket regime label used during calibration.agent_scores field. Use bots and agent_details for real per-agent score data.Try it
Use a prefilled Solana example in the web app or hit the report page directly.
Example token
DezXAZ8z7PnrnRJjz3wXBoRgixCa6tRLh9sJX7YaB1pB