RugPull Risk API
Public MVP documentation for scoring Ethereum contracts for rug-pull risk signals. This site reflects your live routes, headers, and JSON contracts.
curl -sS "https://api.ravenwolflabs.com/v1/risk/score" \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"blockchain": "ethereum",
"contractAddress": "0x0000000000000000000000000000000000000000",
"maxBlockScanRange": 2000
}'
{
"riskScore": 42,
"riskLevel": "MEDIUM",
"confidence": "MEDIUM",
"coveragePercent": 85,
"dataQuality": "GOOD",
"factors": [
{
"id": "RF01_PROXY_UPGRADEABLE",
"status": "NOT_TRIGGERED",
"severity": "MEDIUM",
"evidence": { "isProxy": false }
},
{
"id": "RF06_LIQUIDITY_NOT_LOCKED",
"status": "UNKNOWN",
"severity": "HIGH",
"evidence": { "reason": "not enough data" }
}
],
"unknowns": [
"RF06_LIQUIDITY_NOT_LOCKED"
],
"aiExplanation": "MVP: AI explanation not yet enabled"
}
blockchain: "ethereum" only. Anything else returns a 400.
Overview
The RugPull Risk API evaluates a contract and returns a risk score (0–100), a risk tier, confidence, coverage, and a list of factor evaluations with evidence.
- Score:
POST /v1/risk/score - Quote:
POST /v1/quote(units required + quota + plan cap evaluation) - Usage:
GET /v1/usage(units used/remaining + reset time) - Deep scan jobs:
POST /v1/risk/deep-scanand pollGET /v1/risk/deep-scan/{jobId}
Base URL
All public MVP endpoints are served under:
https://api.ravenwolflabs.com
Authentication
Every public MVP route requires an API key via the header configured in code:
Metering.ApiKeyHeaderName = "X-Api-Key".
X-Api-Key: YOUR_API_KEY
- Missing
X-Api-Key→401 Unauthorized - Unknown/invalid key →
401 Unauthorized
Plans, units & limits
Requests are metered by “units” based on maxBlockScanRange. Your plan defines:
a monthly unit quota and a max scan range per request.
DefaultMaxBlockScanRange: 2000BlockUnitSize: 1000Plans.*.MonthlyUnitQuotaPlans.*.MaxBlockScanRangePerRequest
- Over plan scan cap →
422 Unprocessable Entity - Over quota →
429 Too Many Requestswith a JSON body
POST /v1/risk/score
/v1/risk/score
Scores a contract and returns a RiskScoreResponse.
MVP supports blockchain = "ethereum" only.
{
"blockchain": "ethereum",
"contractAddress": "0x…",
"maxBlockScanRange": 2000
}
blockchainmust be"ethereum"or returns400with{"error":"MVP supports ethereum only"}contractAddressmust look like an EVM address (0x+ 40 hex chars) or returns400with{"error":"Invalid contractAddress"}maxBlockScanRangeover plan cap →422with details
curl -sS "https://api.ravenwolflabs.com/v1/risk/score" \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"blockchain": "ethereum",
"contractAddress": "0x0000000000000000000000000000000000000000",
"maxBlockScanRange": 2000
}'
{
"riskScore": 17,
"riskLevel": "LOW",
"confidence": "HIGH",
"coveragePercent": 92,
"dataQuality": "GOOD",
"factors": [
{
"id": "RF02_OWNER_CAN_MINT",
"status": "NOT_TRIGGERED",
"severity": "HIGH",
"evidence": {
"mintSelectorsFound": [],
"notes": "No mint selectors detected"
}
}
],
"unknowns": [],
"aiExplanation": "MVP: AI explanation not yet enabled"
}
POST /v1/quote
/v1/quote
Returns a preflight quote showing units required for the request, whether you’re within plan scan caps, and whether you have enough remaining quota.
{
"blockchain": "ethereum",
"contractAddress": "0x…",
"maxBlockScanRange": 2000
}
{
"plan": "starter",
"effectiveMaxBlockScanRange": 2000,
"blockUnitSize": 1000,
"unitsRequired": 2,
"allowedByPlanCap": true,
"allowedByQuota": true,
"unitsRemaining": 1991,
"unitsRemainingAfter": 1989,
"resetsAtUtc": "2026-02-01T00:00:00.0000000+00:00",
"allowedMaxBlockScanRange": 5000
}
GET /v1/usage
/v1/usage
Returns the current billing-period usage and reset timestamp for the API key’s plan.
curl -sS "https://api.ravenwolflabs.com/v1/usage" \
-H "X-Api-Key: YOUR_API_KEY"
{
"plan": "starter",
"unitsUsedThisPeriod": 14,
"unitsLimit": 2000,
"unitsRemaining": 1986,
"resetsAtUtc": "2026-02-01T00:00:00.0000000+00:00"
}
POST /v1/risk/deep-scan
/v1/risk/deep-scan
Creates an asynchronous deep scan job. Units are charged upfront to prevent job spamming.
Returns 202 Accepted and a jobId you can poll.
{
"blockchain": "ethereum",
"contractAddress": "0x…",
"maxBlockScanRange": 25000
}
{
"jobId": "b1a2c3d4e5f6...",
"status": "Pending",
"plan": "builder",
"unitsCharged": 25,
"effectiveMaxBlockScanRange": 25000
}
422 with:
{"error":"deep scan is disabled"}.
GET /v1/risk/deep-scan/{jobId}
/v1/risk/deep-scan/{jobId}
Fetches a deep scan job. The server enforces basic isolation: a job is only visible to the API key that created it.
If the key doesn’t match, you get a 404 (not found).
curl -sS "https://api.ravenwolflabs.com/v1/risk/deep-scan/b1a2c3d4e5f6..." \
-H "X-Api-Key: YOUR_API_KEY"
{
"jobId": "b1a2c3d4e5f6...",
"status": "Completed",
"plan": "builder",
"blockchain": "ethereum",
"contractAddress": "0x0000000000000000000000000000000000000000",
"effectiveMaxBlockScanRange": 25000,
"unitsCharged": 25,
"createdAtUtc": "2026-01-21T22:10:00.0000000Z",
"updatedAtUtc": "2026-01-21T22:10:04.0000000Z",
"resultJson": "{ ... }",
"error": null
}
Errors
The API uses a small set of consistent error bodies for common conditions. Below are the exact patterns you’ll see based on the current implementation.
{
"error": "maxBlockScanRange exceeds plan limit",
"plan": "starter",
"requestedMaxBlockScanRange": 9000,
"allowedMaxBlockScanRange": 5000,
"blockUnitSize": 1000,
"estimatedUnitsForRequestedRange": 9
}
{
"error": "quota exceeded",
"plan": "starter",
"unitsRequested": 12,
"unitsRemaining": 3,
"unitsLimit": 2000,
"resetsAtUtc": "2026-02-01T00:00:00.0000000+00:00"
}
400— invalid blockchain or invalid contractAddress401— missing/invalid API key422— deep scan disabled, or plan scan cap exceeded429— quota exceeded (metering)404— deep-scan job not found (or not owned by your key)
Response headers
The scoring endpoint sets several headers that are useful for debugging and client behavior.
X-Plan: starter
X-Cache: HIT | MISS
X-Units-Consumed: 0 | <units>
X-Units-Remaining: <remaining> (only set on MISS after consumption)
X-Units-Reset-At-Utc: 2026-02-01T00:00:00.0000000+00:00 (only set on MISS after consumption)
Cache hits return X-Units-Consumed: 0 and do not charge quota.
Best practices
- On
429, back off and retry after a short delay. - Use
POST /v1/quotebefore expensive scans in automation. - Log
X-Plan,X-Cache, and unit headers for observability.
- Prefer smaller
maxBlockScanRangeunless you truly need more history. - Leverage caching (90s TTL by default) and avoid rescoring the same address repeatedly.
- Run deep scans selectively (e.g., near-threshold scores).