API
JSON over HTTPS. Every response is { version, data }. Pass x-api-key for paid tiers; anonymous use is limited to 30 requests a minute.
Endpoints
| GET | /api/v1/protocols | All watched protocols with grade, score, flags and key facts. |
| GET | /api/v1/protocols/:slug | One protocol including the full control snapshot. |
| GET | /api/v1/protocols/:slug/events | Governance timeline for a protocol. |
| GET | /api/v1/events?severity=high&since=ISO | Events across protocols, filtered by minimum severity and time. |
| GET | /api/v1/scores/:slug/history | Score history. |
| GET | /api/v1/stream | Server-Sent Events: event, score, registry, shield. |
| POST | /api/v1/subscriptions/webhook | Create a webhook. Returns the signing secret once. |
| POST | /api/v1/subscriptions/test | Test-fire a webhook with a signed sample payload. |
Examples
curl
curl -s https://<host>/api/v1/protocols/drift -H "x-api-key: $OVERWATCH_KEY" \
| jq '.data | {grade, score, flagNames, threshold, timelockSec}'
curl -s "https://<host>/api/v1/events?severity=critical&since=2026-10-01T00:00:00Z"
curl -N https://<host>/api/v1/stream # event: event / score / registry / shieldcreate a webhook
curl -X POST https://<host>/api/v1/subscriptions/webhook \
-H 'content-type: application/json' \
-d '{"url":"https://example.com/hooks/overwatch",
"min_severity":"HIGH",
"protocols":["drift","kamino-lend"]}'Webhook signatures
Each delivery is signed: x-overwatch-signature = hex(HMAC-SHA256(secret, rawBody)). Failed deliveries retry with exponential backoff, up to 6 attempts.
verify.ts
import { verifyWebhook } from "@overwatch/sdk";
const ok = await verifyWebhook(rawBody, req.headers["x-overwatch-signature"], process.env.OVERWATCH_SECRET);
if (!ok) return new Response(null, { status: 401 });Onchain: read the registry from your program
The RiskRecord PDA is ["risk", sha256(slug)] under the registry program. Check the owner and the PDA, then test flags & RED_MASK.
lib.rs
#[account(seeds = [b"risk", protocol_id.as_ref()], bump = risk.bump,
seeds::program = overwatch_registry::ID)]
pub risk: Account<'info, overwatch_registry::RiskRecord>, // owner checked by Account<>
...
if risk.flags & overwatch_registry::flags::RED_MASK != 0 { /* exit */ }sdk.ts
import { fetchRiskRecord } from "@overwatch/sdk";
const r = await fetchRiskRecord("https://api.devnet.solana.com", "drift");
// { score, grade, flags, red, ... }