Public BetaRisk models continue to evolve during validation.
Campaign Webhooks v1

Connect campaign decisions to your own backend.

Subscribe to signed analysis, review, Decision Package, policy-version and lifecycle events. Failed deliveries use the existing retry queue; analysis-scoped campaign events are idempotent per endpoint and analysis.

analysis.completed
The deterministic analysis is complete and canonical campaign links are available.
analysis.review_required
Emitted only when the completed analysis contains wallets requiring human review.
decision_package.ready
The latest read-only campaign Decision Package can be retrieved as JSON or CSV.
campaign.policy_changed
A new explicit campaign policy version was activated for future runs.
campaign.lifecycle_changed
The campaign moved between draft, active, paused, completed, or archived states.
Signed payloads
Every delivery includes x-triproof-timestamp and an HMAC-SHA256 x-triproof-signature.

Existing Team Policy events remain supported

`policy.blocked` and `policy.review` remain valid subscription types. Campaign Webhooks v1 extends the event surface without removing the existing Team Policy integration.

Outbound delivery is fail-closed

Webhook destinations must resolve only to public routable addresses. DNS is validated again for every initial delivery and retry, the connection is pinned to a validated address, and HTTP redirects are not followed. Localhost, private, link-local, metadata and internal destinations are blocked.

Create webhook endpoint
API Growth keys can manage endpoints through API v2. The same operations are also available in Dashboard → Developer. The signing secret is shown only when the endpoint is created.
curl -X POST https://triproofprotocol.com/api/v2/webhooks \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "url": "https://yourapp.com/api/triproof-webhook",
    "eventTypes": [
      "analysis.completed",
      "analysis.review_required",
      "decision_package.ready",
      "campaign.policy_changed",
      "campaign.lifecycle_changed"
    ],
    "description": "Production campaign webhook"
  }'
Verify the signature
Sign exactly `timestamp.rawBody` with HMAC-SHA256 and compare against the v1 signature.
import { createHmac, timingSafeEqual } from "node:crypto"

export function verifyTriProofWebhook(rawBody: string, headers: Headers, secret: string) {
  const timestamp = headers.get("x-triproof-timestamp") ?? ""
  const provided = (headers.get("x-triproof-signature") ?? "").replace(/^v1=/, "")
  const expected = createHmac("sha256", secret)
    .update(`${timestamp}.${rawBody}`)
    .digest("hex")

  if (!provided || provided.length !== expected.length) return false
  return timingSafeEqual(Buffer.from(provided), Buffer.from(expected))
}
Operational boundaries
Webhook delivery never changes a stored wallet decision. Policy-change events describe a version that applies to future runs only. Lifecycle events describe campaign state transitions. A failed or blocked customer endpoint does not roll back a completed analysis, policy activation, or lifecycle transaction.