RugPull Risk API
Public MVP documentation for scoring Ethereum contracts for rug-pull risk signals. This site reflects the current routes, headers, and JSON contracts in the codebase.
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": null,
"analyzedAtUtc": "2026-02-23T17:45:00.0000000+00:00"
}
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/risk/quote(units required + quota + plan cap + detector feasibility) - Usage:
GET /v1/risk/usage(units used/remaining + reset time) - Deep scan jobs:
POST /v1/risk/deep-scanand pollGET /v1/risk/deep-scan/{jobId} - Reporting (plan-gated):
POST /v1/risk/report,POST /v1/risk/report/pdf, and PDF retrieval endpoints
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:
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 your effective block lookback window. Your plan defines a monthly unit quota and a max scan range per request.
DefaultMaxBlockScanRange(used when request omitsmaxBlockScanRange)BlockUnitSize(units per block range chunk)Plans.*.MonthlyUnitQuotaPlans.*.MaxBlockScanRangePerRequest
- Over plan scan cap →
422 Unprocessable Entity - Over quota →
429 Too Many Requestswith a JSON body - Cache hit →
X-Units-Consumed: 0(no charge)
- AI explanation (score): plan-gated (Pro/Scale). If requested on other plans →
422. - Reporting/PDFs: plan-gated (Pro/Scale). If called on other plans →
402withupgrade_required.
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,
"explanationStyle": "brief"
}
explanationStyle, the API may attach a structured aiExplanation object.
Allowed values:
brief, standard, investor_memo, compliance.
Availability is plan-gated (Pro/Scale).
blockchainmust be"ethereum"or returns400with{"error":"MVP supports ethereum only"}contractAddressmust be a 42-char EVM address (0x+ 40 hex) or returns400with{"error":"Invalid contractAddress"}maxBlockScanRangeover plan cap →422with details- Invalid
explanationStyle→400with allowed styles - Disallowed
explanationStylefor plan →422with required plans
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,
"explanationStyle": "brief"
}'
{
"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": {
"style": "brief",
"summary": "This contract scored LOW risk with HIGH confidence based on current evidence.",
"topDrivers": [
{ "driver": "Ownership controls", "impact": "LOW", "rationale": "No elevated owner privileges were detected in the scanned window." }
],
"riskScenarios": [
"If ownership can be transferred to a malicious party later, permissions could change."
],
"benignAlternatives": [
"Some contracts intentionally use proxy patterns for upgrades."
],
"confidence": {
"level": "HIGH",
"whatWouldRaiseConfidence": [
"More on-chain history",
"Liquidity lock evidence"
]
},
"recommendedNextChecks": [
"Verify contract on Etherscan",
"Review liquidity lock status"
]
},
"analyzedAtUtc": "2026-02-23T17:45:00.0000000+00:00"
}
POST /v1/risk/quote
/v1/risk/quote
Returns a preflight quote showing units required for the request, whether you’re within plan scan caps, whether you have enough remaining quota, and whether key detectors are executable for the requested window.
{
"blockchain": "ethereum",
"contractAddress": "0x…",
"maxBlockScanRange": 2000
}
{
"plan": "starter",
"executable": true,
"effectiveMaxBlockScanRange": 2000,
"allowedMaxBlockScanRange": 5000,
"blockUnitSize": 1000,
"unitsRequired": 2,
"allowedByPlanCap": true,
"allowedByQuota": true,
"unitsRemaining": 1986,
"unitsRemainingAfter": 1984,
"resetsAtUtc": "2026-02-01T00:00:00.0000000+00:00",
"execution": {
"requestedBlockSpan": 2000,
"maxExecutableBlockSpan": 5000,
"failureReason": "",
"actionRequired": ""
},
"detectors": {
"RF13_SUSPICIOUS_INITIAL_DISTRIBUTION": {
"executable": true,
"reason": "Bounded scan enabled (lookback≈2000 blocks)."
},
"RF19_DEVELOPER_REPUTATION_RISK": {
"executable": true,
"reason": "Bounded scan enabled (lookback≈2000 blocks)."
}
}
}
GET /v1/risk/usage
/v1/risk/usage
Returns the current billing-period usage and reset timestamp for the API key’s plan.
curl -sS "https://api.ravenwolflabs.com/v1/risk/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. Basic isolation is enforced: in non-development environments, a job is only visible
to the API key that created it. If the key doesn’t match, you get a 404.
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
}
POST /v1/risk/report
/v1/risk/report
Generates a high perceived-value narrative report (JSON) and stores it for 30 days.
The response includes a stable reportId used by the PDF endpoints.
Plan-gated: Pro/Scale only (otherwise 402 upgrade_required).
{
"blockchain": "ethereum",
"contractAddress": "0x…",
"template": "standard",
"maxBlockScanRange": 5000
}
shortstandard(default)detailed
{
"reportId": "2b2a0f4d7c4b4a9b9b7e0d2f7b7a1a2c",
"engineVersion": "rprs-1.0.0",
"blockchain": "ethereum",
"contractAddress": "0x0000000000000000000000000000000000000000",
"analyzedAtUtc": "2026-02-23T17:45:00.0000000+00:00",
"template": "standard",
"summary": {
"riskScore": 42,
"riskLevel": "MEDIUM",
"confidence": "MEDIUM",
"coveragePercent": 85,
"dataQuality": "GOOD"
},
"narrative": {
"headline": "Moderate risk with unresolved liquidity signals",
"overview": "The contract shows a mix of normal patterns and incomplete evidence in critical areas.",
"keyTakeaways": [
"No proxy upgrade pattern detected in the scanned window",
"Liquidity lock evidence could not be confirmed",
"Consider deeper inspection before committing significant funds"
]
},
"evidenceHighlights": [
{
"factorId": "RF06_LIQUIDITY_NOT_LOCKED",
"severity": "HIGH",
"title": "Liquidity lock could not be confirmed",
"highlights": [
"No lock transaction found in the scanned window",
"On-chain evidence is incomplete for this factor"
],
"evidence": { "reason": "not enough data" }
}
],
"recommendedChecks": [
{
"checkId": "CHK01_VERIFY_CONTRACT",
"priority": "HIGH",
"title": "Verify contract source and ownership controls",
"why": "Verification reduces uncertainty and helps confirm privileged functions.",
"how": [
"Check Etherscan verification status",
"Review owner privileges and transfer patterns"
]
}
],
"unknowns": [
"RF06_LIQUIDITY_NOT_LOCKED"
]
}
curl -sS "https://api.ravenwolflabs.com/v1/risk/report" \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"blockchain": "ethereum",
"contractAddress": "0x0000000000000000000000000000000000000000",
"template": "standard",
"maxBlockScanRange": 5000
}'
POST /v1/risk/report/pdf
/v1/risk/report/pdf
Stateless PDF generation: analyzes + composes a report, stores reportJson and uploads the PDF
(stored for 30 days), and returns PDF bytes directly.
Plan-gated: Pro/Scale only (otherwise 402 upgrade_required).
{
"blockchain": "ethereum",
"contractAddress": "0x…",
"template": "standard",
"maxBlockScanRange": 5000
}
curl -sS "https://api.ravenwolflabs.com/v1/risk/report/pdf" \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"blockchain": "ethereum",
"contractAddress": "0x0000000000000000000000000000000000000000",
"template": "standard",
"maxBlockScanRange": 5000
}' \
--output risk-report.pdf
application/pdf bytes. The server may include helpful headers like:
X-Report-Id, X-Pdf-Sha256, and X-Report-Template.
GET /v1/risk/report/{reportId}/pdf
/v1/risk/report/{reportId}/pdf
Fetches a stored PDF for a previously generated reportId.
If the PDF blob is missing but the stored report JSON exists, the server may regenerate the PDF and return it.
Plan-gated: Pro/Scale only (otherwise 402 upgrade_required).
curl -sS "https://api.ravenwolflabs.com/v1/risk/report/2b2a0f4d7c4b4a9b9b7e0d2f7b7a1a2c/pdf" \
-H "X-Api-Key: YOUR_API_KEY" \
--output risk-report.pdf
GET /v1/risk/report/{reportId}/pdf-url
/v1/risk/report/{reportId}/pdf-url
Returns a presigned URL for the PDF.
Optional query: ?download=1 forces download disposition.
If the PDF blob is missing but the stored report JSON exists, the server may regenerate + upload first.
Plan-gated: Pro/Scale only (otherwise 402 upgrade_required).
curl -sS "https://api.ravenwolflabs.com/v1/risk/report/2b2a0f4d7c4b4a9b9b7e0d2f7b7a1a2c/pdf-url?download=1" \
-H "X-Api-Key: YOUR_API_KEY"
{
"reportId": "2b2a0f4d7c4b4a9b9b7e0d2f7b7a1a2c",
"url": "https://...presigned...",
"expiresAtUtc": "2026-02-23T18:15:00.0000000Z",
"download": true
}
Errors
The API returns consistent JSON error bodies for common conditions.
{
"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"
}
{
"error": "upgrade_required",
"message": "Reporting is available on the Pro/Scale plans. Please upgrade to access reports.",
"currentPlan": "starter",
"requiredPlan": "pro",
"upgradeUrl": "/billing/upgrade?plan=pro",
"upgradeApiRoute": "/v1/billing/checkout-session",
"features": [
"reporting",
"higher_quota",
"higher_rate_limits",
"priority_processing"
]
}
{
"error": "ai explanation is not available on this plan",
"plan": "starter",
"requiredPlans": [ "pro", "scale" ],
"explanationStyle": "brief"
}
400— invalid blockchain, invalid contractAddress, or invalid explanationStyle401— missing/invalid API key402— reporting/PDF endpoints require upgrade (Pro/Scale)422— deep scan disabled, plan scan cap exceeded, or AI explanation not available on plan429— quota exceeded (metering)404— deep-scan job or reportId not found
Response headers
The API includes headers that help you debug caching + metering 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.0000000Z (only set on MISS after consumption)
# Reporting-specific (when applicable)
X-Report-Id: <reportId>
X-Report-Template: short | standard | detailed
X-Report-Url: https://api.ravenwolflabs.com/v1/risk/report/<reportId>/pdf
X-Pdf-Sha256: <hex>
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/risk/quotebefore expensive scans in automation. - Log
X-Plan,X-Cache, and unit headers for observability. - For reporting/PDF flows, persist
reportIdif you want to fetch PDFs later.
- Prefer smaller
maxBlockScanRangeunless you truly need more history. - Leverage caching and avoid rescoring the same address repeatedly.
- Use deep scan selectively (e.g., for borderline scores or higher-risk thresholds).
- For PDFs, use
/pdf-urlwhen you want the client to download directly from storage.