Send alerts to Slack, Discord or webhooks

Send AgentProof events to a Slack channel, a Discord channel or your own webhook. See the events, the payload fields and how to check signatures.

AgentProof can tell your team when a report is ready, when findings are recorded and when a fix is verified. Send these messages to a Slack channel, a Discord channel, or any web address that accepts a signed request, such as your own service, n8n or Zapier.

Workspace owners and admins set this up in Settings, under Integrations. Each workspace can have up to 10 destinations.

Slack

  1. In Slack, create an app for your workspace at api.slack.com/apps, turn on Incoming Webhooks, and choose Add New Webhook to Workspace.
  2. Pick the channel and copy the webhook address. It starts with https://hooks.slack.com/services/.
  3. In AgentProof, open Settings, then Integrations. Choose Slack, enter a name, paste the address and pick the events.
  4. Press Add destination, then Send test.

Discord

  1. In Discord, open the channel settings, then Integrations, then Webhooks, and choose New Webhook.
  2. Copy the webhook address. It starts with https://discord.com/api/webhooks/.
  3. In AgentProof, choose Discord, enter a name, paste the address and pick the events.
  4. Press Add destination, then Send test.

Discord messages never mention @everyone, roles or people.

Your own webhook

Choose Webhook and enter an https address on port 443 or 8443. AgentProof shows a signing secret once, when you add the destination. Copy it and keep it with your service. Press New secret to replace it; the old secret keeps working for 24 hours, so you can switch without missing messages.

Events

Events
EventWhen it is sent
report.readyA run finished and its report is ready.
findings.recordedAn Attack run recorded confirmed findings.
fix.openedThe Defense Agent opened a pull request with a fix.
fix.verifiedThe retest on your live site confirmed the fix.
fix.regressedThe retest did not confirm the fix.
schedule.skippedA scheduled run did not start, for example because no credits were left.
billing.updatedYour plan or subscription status changed.
endpoint.testYou pressed Send test.

Payload

Webhooks receive JSON in the Standard Webhooks format. Messages hold names, statuses, counts and links. They never include evidence, agent replies or memory; open the link to read those on AgentProof.

{
  "type": "findings.recorded",
  "timestamp": "2026-11-09T15:00:00Z",
  "data": {
    "workspace": { "id": "wks_...", "name": "Acme" },
    "run": {
      "id": "run_...",
      "agent": "Attack Agent",
      "team": "Attack",
      "status": "completed",
      "target": "https://example.com/",
      "url": "https://isagentproof.com/runs/run_.../"
    },
    "findings": { "total": 3, "high": 1, "medium": 2, "low": 0, "info": 0 }
  }
}

Check the signature

Each request has three headers:

  • webhook-id: the message ID. It stays the same when a message is sent again, so use it to skip duplicates.
  • webhook-timestamp: the time of the attempt, in seconds.
  • webhook-signature: v1, followed by a base64 HMAC-SHA256 signature. During a secret change it holds two signatures separated by a space.

Sign webhook-id, a dot, webhook-timestamp, a dot and the raw request body with your secret (the part after whsec_, decoded from base64). Accept the message if any signature matches, and reject timestamps more than five minutes old. In Node.js:

import crypto from "node:crypto";

export function verify(secret, headers, rawBody) {
  const key = Buffer.from(secret.replace(/^whsec_/, ""), "base64");
  const id = headers["webhook-id"], stamp = headers["webhook-timestamp"];
  if (Math.abs(Date.now() / 1000 - Number(stamp)) > 300) return false;
  const expected = crypto.createHmac("sha256", key).update(`${id}.${stamp}.${rawBody}`).digest("base64");
  return headers["webhook-signature"].split(" ").some(sig => {
    const value = sig.split(",")[1] || "";
    return value.length === expected.length && crypto.timingSafeEqual(Buffer.from(value), Buffer.from(expected));
  });
}

The official Standard Webhooks libraries for many languages do the same check.

Retries

Answer with any 2xx status within 10 seconds. If the request fails, times out or gets 408, 429 or a 5xx status, AgentProof sends it again after 1 minute, 5 minutes, 30 minutes, 2, 5, 10, 14, 20 and 24 hours, and follows Retry-After. Redirects are not followed.

A destination is turned off if it answers 410 Gone, or if every delivery fails for five days. Turn it back on in Settings with Enable. Recent deliveries shows the last 10 attempts and their results.

Manage destinations with the API

API tokens with the notifications:read and notifications:write scopes can list, add, test and remove destinations at /api/workspaces/current/notifications. Assistants connected through the MCP server can list destinations and send a test message, but they cannot add one.