00

API

JSON over HTTPS, no sign-up. Every response is { version, data }, and errors are { version, error }. Anyone can make 30 requests a minute; partners with an x-api-key get more. Over the limit you get 429 with retry-after.

Endpoints

GET/api/v1/protocolsAll watched protocols with grade, score, flags and key facts.
GET/api/v1/protocols/:slugOne protocol plus its controls: programs, multisigs, signers, nonces, mints.
GET/api/v1/protocols/:slug/eventsGovernance timeline for a protocol.
GET/api/v1/events?severity=high&since=ISOEvents across protocols, filtered by minimum severity and time.
GET/api/v1/scores/:slug/historyScore history.
GET/api/v1/streamServer-Sent Events: event, score, registry, shield.
GET/api/v1/statusHealth: current slot, database, protocol count, last event.
POST/api/v1/subscriptions/webhookCreate a webhook. Returns its id and secret once. 5 per IP per day.
POST/api/v1/subscriptions/emailEmail alerts. Nothing is sent until the address confirms the link we mail.
POST/api/v1/subscriptions/testTest-fire a webhook with a signed sample payload. 10 per hour.
GET/api/v1/subscriptions/:idRead a subscription. Header x-subscription-secret.
PATCH/api/v1/subscriptions/:idChange min_severity, protocols, url (webhooks) or active (pause/resume).
DELETE/api/v1/subscriptions/:idUnsubscribe.

Examples

curl
curl -s https://<host>/api/v1/protocols/drift \
  | 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 / shield
create 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"]}'
# → { id, secret, ... }  keep both

# change or pause it later
curl -X PATCH https://<host>/api/v1/subscriptions/$ID \
  -H "x-subscription-secret: $SECRET" -H 'content-type: application/json' \
  -d '{"min_severity":"CRITICAL"}'      # or {"active":false}

curl -X DELETE https://<host>/api/v1/subscriptions/$ID -H "x-subscription-secret: $SECRET"

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, ... }