Subscribe a URL, get HMAC-signed JSON on every tier transition and protection-level change. Delivery retries on failure (30s / 2m / 15m) and auto-disables after 10 consecutive failures. Same event shape powers Telegram + Discord alerts.
badge.tier_changedFires when a token's FOUR-LIFE Certified tier transitions (e.g. healthy → at_risk).{
"id": "evt_xxxx...",
"type": "badge.tier_changed",
"created_at": 1776380000,
"token_address": "0xabc...",
"from_tier": "healthy",
"to_tier": "at_risk",
"at": 1776380000,
"why": [
{
"rule": "whale_extreme",
"metric": "top_holder_pct",
"value": 55.2,
"threshold": 40,
"operator": ">=",
"passed": true
}
],
"metrics": { "curve_progress_pct": 42, "top_holder_pct": 55.2, "..." : "..." },
"data_source": "live_monitor"
}protection.level_changedFires when a token under Protection Mode transitions between safe / warn / critical.{
"id": "evt_xxxx...",
"type": "protection.level_changed",
"created_at": 1776380000,
"token_address": "0xabc...",
"from_level": "safe",
"to_level": "critical",
"at": 1776380000,
"fired_rules": [
{
"rule": "contract_rug_critical",
"metric": "contract_risk_score",
"value": 80,
"threshold": 60,
"severity": "critical"
}
],
"recommended_actions": ["halt_content_posts", "fire_webhook_alert"],
"thresholds": { "critical_whale_concentration": 55.0, "..." : "..." }
}# Subscribe — returns the shared secret EXACTLY ONCE
curl -X POST https://four-life.gudman.xyz/api/webhooks \
-H "Authorization: Bearer $API_SECRET" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-service.example/fourlife-webhook",
"events": ["badge.tier_changed", "protection.level_changed"],
"token_filter": null
}'
# Response contains:
# "id" → subscription id (whs_...)
# "secret" → shared HMAC secret (whsec_...) ← STORE THIS NOWsecret is returned once and never recoverable. Use it to verify the signature on every delivery. Requires an API_SECRET bearer token; set one in the deployment env to lock writes.HMAC_SHA256(secret, f"{t}.{raw_body}").|now - t| > 300 seconds to prevent replay attacks.// Node.js / any runtime with crypto
const crypto = require("crypto");
function verifyFourLifeSignature({ secret, body, header, toleranceSeconds = 300 }) {
const parts = Object.fromEntries(
header.split(",").map(s => s.split("=").map(x => x.trim())),
);
const t = parseInt(parts.t, 10);
const v1 = parts.v1;
if (!t || !v1) return false;
if (Math.abs(Math.floor(Date.now() / 1000) - t) > toleranceSeconds) return false;
const expected = crypto
.createHmac("sha256", secret)
.update(`${t}.${body}`)
.digest("hex");
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}
// Express handler
app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
const body = req.body.toString("utf-8");
const sig = req.headers["x-fourlife-signature"] || "";
if (!verifyFourLifeSignature({ secret: process.env.WHSEC, body, header: sig })) {
return res.status(401).send("bad signature");
}
const event = JSON.parse(body);
console.log("received:", event.type, event.token_address);
res.status(200).send("ok");
});# Python (Flask or any framework that gives raw body)
import hmac, hashlib, time
def verify_fourlife_signature(*, secret: str, body: str, header: str, tolerance: int = 300) -> bool:
parts = dict(seg.split("=", 1) for seg in header.split(",") if "=" in seg)
try:
t = int(parts.get("t", ""))
except ValueError:
return False
if abs(int(time.time()) - t) > tolerance:
return False
expected = hmac.new(
secret.encode(), f"{t}.{body}".encode(), hashlib.sha256,
).hexdigest()
return hmac.compare_digest(expected, parts.get("v1", ""))
@app.post("/webhook")
def webhook():
body = request.get_data(as_text=True)
sig = request.headers.get("X-FourLife-Signature", "")
if not verify_fourlife_signature(secret=WHSEC, body=body, header=sig):
return ("bad signature", 401)
event = request.get_json()
print("received:", event["type"], event["token_address"])
return ("ok", 200)