API Routes
1. API Routes
1.1 Response Format
All API responses use an envelope format:
{
"success": true,
"data": { ... },
"meta": {
"pagination": { "page": 1, "limit": 20, "total": 100, "totalPages": 5 },
"cached": false
}
}
Error response:
{
"success": false,
"error": {
"code": "INVALID_ADDRESS",
"message": "Invalid Ethereum address format",
"details": { ... }
}
}
1.2 Endpoints
Scan
GET /api/v1/scan/{input}
Input: 0x address, ENS name (.eth), or domain
Response: ScanResult
Flow:
→ detectInputType(input)
→ address: getBytecode → analyze patterns → calculate risk
→ ens: resolveEns → then scan resolved address
→ domain: checkDomain → DB lookup
Returns:
- riskScore (0-100)
- riskLevel (LOW/MEDIUM/HIGH/CRITICAL)
- isVerified
- patterns[] (detected scam patterns)
- similarScams[] (by bytecode hash)
- reportCount
- scanDuration
Address Details
GET /api/v1/address/{address}
Response: AddressDTO
- address, name, chain, status, riskScore
- category, source, description
- url, logoUrl, tvl
- verifiedBy, verifiedAt
- tags[] (address tags)
- reportCount
- lastScanned
Address Tags (nested)
GET /api/v1/address/{address}/tags
Response: { data: AddressTagDTO[], address, count }
DELETE /api/v1/address/{address}/tags?tag=scam
Response: { message, address, tag }
Address ENS (nested)
GET /api/v1/address/{address}/ens
Response: { address, primaryName, records[], count }
Address Tags (top-level, with reputation)
GET /api/v1/address-tags
Query: ?address=0x...&tag=scam&taggedBy=0x...&page=1&limit=20
Response: Paginated tags with address info
POST /api/v1/address-tags
Body: { address, tag, taggedBy? }
Logic:
- Creates address record if not exists
- Upserts tag (unique on address + tag)
- Awards +5 reputation to tagger
- Creates/updates UserProfile for tagger
Response: Tag record + user profile
Tags (simplified)
POST /api/v1/tags
Body: { address, tag, taggedBy? }
Logic: Simple tag creation with upsert (no reputation system)
Response: Created tag record
Check Domain
GET /api/v1/check-domain?domain=example.com
Response: { domain, isScam, riskScore, category, description, source, checkedAt }
Logic: Cleans domain (removes protocol, www, paths), checks ScamDomain table
History
GET /api/v1/history?checker=0x...&limit=50
Response: ContractScan[] with address details
Logic: Returns most recent scans, optionally filtered by checker address
ENS Resolution
GET /api/v1/resolve/{ens}
Response: { ens, address, resolvedAt }
Logic: Validates ENS name via Zod, resolves via EnsService
Scam Domains
GET /api/v1/scam-domains?page=1&limit=20&search=uniswap&status=ACTIVE
Response: Paginated list of scam domains
Reports
GET /api/v1/reports
Query: ?status=PENDING&category=PHISHING&page=1&limit=20
Response: ReportsResponse { data: ReportDTO[], pagination }
POST /api/v1/reports
Body: CreateReportRequest {
address: string,
reason: string,
evidenceUrl?: string,
category: AddressCategory,
reporterAddress: string,
reasonHash?: string,
reasonData?: { selectedReasons: string[], customText: string }
}
Response: CreateReportResponse { id, status, txHash?, message }
Vote Status
GET /api/v1/reports/vote-status?address=0x...&voterAddress=0x...
Response: { hasVoted, voteType, reportId }
Logic: Checks if voter has already voted on any report for the address
Vote on Report
POST /api/v1/reports/{id}/vote
Body: { vote: "FOR"|"AGAINST", voterAddress, txHash? }
Response: VoteResponse { reportId, votesFor, votesAgainst, status }
Watchlist
GET /api/v1/watchlist?userAddress=0x...
Response: Watchlist entries with current/previous risk scores, last checked
POST /api/v1/watchlist
Body: { userAddress, watchedAddress }
Logic: Creates watched address if needed, creates UserProfile for FK constraint
DELETE /api/v1/watchlist/{address}?userAddress=0x...
Response: { deleted: boolean }
dApps Directory
GET /api/v1/dapps
Query: ?status=LEGIT&category=DEFI&search=uni&page=1&limit=20&sort=tvl&order=desc
Response: DappsResponse { data: AddressDTO[], pagination }
Sync
POST /api/v1/sync
Body: { source: "defillama"|"scamsniffer"|"cryptoscamdb"|"base"|"all" }
Response: SyncResponse { success, source, recordsAdded, recordsUpdated, syncLogId, duration }
Stats
GET /api/v1/stats
Response: PlatformStats {
totalAddresses, legitCount, scamCount, suspiciousCount, unknownCount,
totalReports, verifiedReports, pendingReports,
topCategories[], recentScams[], scansToday, updatedAt
}
Health Check
GET /api/health
Response: { status: "healthy"|"degraded"|"unhealthy", database, blockchain, externalApis }
1.3 Error Codes
| Code | HTTP Status | Description |
|---|---|---|
INTERNAL_ERROR |
500 | Server error |
INVALID_REQUEST |
400 | Validation failed |
NOT_FOUND |
404 | Resource not found |
UNAUTHORIZED |
401 | Auth required |
FORBIDDEN |
403 | Insufficient permissions |
RATE_LIMITED |
429 | Too many requests |
INVALID_ADDRESS |
400 | Bad address format |
ADDRESS_NOT_FOUND |
404 | Address not in database |
REPORT_NOT_FOUND |
404 | Report ID not found |
REPORT_ALREADY_VOTED |
400 | User already voted |
INSUFFICIENT_REPUTATION |
403 | Need more reputation |
SCAN_TIMEOUT |
408 | Scan took too long |
SCAN_FAILED |
500 | Scanner error |
SYNC_FAILED |
500 | Sync error |
SYNC_IN_PROGRESS |
409 | Sync already running |