{"name":"warden api","description":"governance intelligence. rule changes are being voted on across defi right now — this api maps them to wallet exposure: the rule changing, the source, your exposure, the simulated effect. simulation only, not financial advice.","version":"0.1.0","stability":"pre-1.0 — response shapes may change. every list/detail response is an envelope (never a bare array); error responses are always { error, code, hint }.","lifecycle":{"versionHeader":"x-api-version","pinHeader":"api-version","versioning":"semver in openapi info.version, echoed on every api response as the x-api-version header. pre-1.0: a minor bump may change shapes.","pinning":"send api-version on a request to pin the version line you built against, e.g. \"0.1\" or \"0.1.0\". the line is major.minor before 1.0 and the major after. a line this api no longer serves answers 400 unsupported_version instead of a changed shape. no header = the current version.","signals":["the operation is marked deprecated: true in /api/openapi.json","responses carry a Deprecation header (rfc 9745) once deprecated","responses carry a Sunset header (rfc 8594) with the removal date once one is set","the change is listed in /llms.txt before it ships"]},"docs":{"openapi":"/api/openapi.json","llms":"/llms.txt","app":"https://try.warden.cash","walletPage":"https://try.warden.cash/w/{address}"},"rateLimit":{"perMinutePerClient":30,"headers":["ratelimit-policy","ratelimit","x-ratelimit-limit","x-ratelimit-remaining"],"format":"ietf draft-ietf-httpapi-ratelimit-headers-11: ratelimit-policy: \"default\";q=30;w=60 and ratelimit: \"default\";r=<left>;t=<seconds until r goes up>. x-ratelimit-* are legacy twins.","on429":"retry-after header (seconds) is set — back off that long."},"cors":"open on every public endpoint — any origin, no credentials. callable straight from a browser; the rate-limit headers are exposed.","errors":{"envelope":{"error":"human-readable message","code":"machine-readable code","hint":"what to do next — one fixed hint per code"},"hints":{"invalid_address":"pass an evm address (0x…), an ens name, or a solana, cosmos, or xrp address. do not retry as-is.","invalid_input":"a query param failed validation. fix it and resend — allowed values are in /api/openapi.json.","unsupported_version":"the api-version you pinned is not served. drop the header, or pin the version in GET /api — then check the changelog in /llms.txt for what changed.","not_found":"check the path or id. GET /api lists every endpoint.","rate_limited":"wait retry-after seconds, then retry. the RateLimit header carries the remaining budget.","upstream_unavailable":"a source rpc or api is down. safe to retry shortly, with backoff.","internal_error":"our fault. safe to retry shortly, with backoff."},"unknownPaths":"any /api path that does not exist answers 404 with the same json envelope, never an html page.","codes":{"invalid_address":"400 — the wallet address failed validation. do not retry as-is.","invalid_input":"400 — a query param failed validation. do not retry as-is.","unsupported_version":"400 — the pinned api-version line is not served. drop the header or re-pin.","not_found":"404 — no resource with that id.","rate_limited":"429 — respect retry-after.","upstream_unavailable":"502 — source rpc/api down. safe to retry shortly.","internal_error":"500 — our fault. safe to retry shortly."}},"endpoints":[{"method":"GET","path":"/api/scan/{address}","description":"the primary endpoint: positions detected for a wallet plus every governance proposal that touches them, with simulated impact. {address} can be an ens name. ?view=compact strips proposal bodies; ?protocol=, ?minImpact=, ?status=, ?since= narrow to the slice you want (?protocol= also skips the other modules' rpc). mode \"mock\" marks demo wallets — never treat mock data as real exposure.","example":"/api/scan/vitalik.eth?view=compact&protocol=lido&minImpact=medium"},{"method":"GET","path":"/api/proposals","description":"rule-change feed. no params → the global cross-protocol feed (no impact data). ?address= (wallet or ens) → that wallet's proposals with impact, most material first. ?view=compact, ?limit= (default 50, max 200), ?protocol=, ?status=, ?since=; ?minImpact= needs an address.","example":"/api/proposals?address=vitalik.eth&minImpact=medium&status=active"},{"method":"GET","path":"/api/proposals/{id}","description":"one proposal by id. ?address= attaches that wallet's impact when the proposal touches their positions; otherwise the global version comes back with mode \"global\".","example":"/api/proposals/{id}?address=0xYOURWALLET"},{"method":"GET","path":"/api/positions/{address}","description":"positions only — the lightweight half of a scan. {address} can be an ens name; ?protocol= narrows to a slice.","example":"/api/positions/vitalik.eth?protocol=aave"},{"method":"GET","path":"/api/ens/resolve","description":"ens name → address. 200 with address null means valid but unregistered.","example":"/api/ens/resolve?name=vitalik.eth"},{"method":"GET","path":"/api/health","description":"liveness probe.","example":"/api/health"}],"notes":["handing a result to a human? link them to https://try.warden.cash/w/{address} (accepts an ens name) — the same scan as a page, with a one-tap way to keep watching the wallet. scan responses carry it as webUrl. never hand a person the raw json url.","scan results are cached ~60s server-side; refreshedAt is the truth.","the global proposals feed is cached ~5min.","addresses accept ens names anywhere a wallet is taken — resolved server-side, mainnet.","wallet-scan responses carry completeness (\"complete\" | \"partial\") — branch on that, read `degraded` for which protocol could not be checked.","?protocol= is also the cheap retry: re-scan just the protocols that came back in `degraded` instead of the whole wallet.","impact claims carry sourceLinks (where the rule change lives) and impact.analysisStatus (simulated vs awaiting_analysis) — surface both to your users.","scans degrade honestly: when a protocol source or position adapter fails, the response succeeds with a `degraded` list naming the gap. a protocol missing from `degraded` and from results genuinely has nothing; a protocol in `degraded` could not be checked. 502 only means every source failed."]}