Webhooks

Add up to five https addresses under Settings > Webhooks and pick what each one hears: All events, which includes types added later, or Selected events. Edit on a webhook changes its pick at any time, and its address and secret stay as they are. Events of one type that arrive close together come as one message. Slack, Discord and Microsoft Teams addresses get each message in their own format, titled with the event's name.

  • stop.guard (Action gate denial, in stops): An action gate stopped an agent's tool call, such as a command or a file edit.
  • stop.check (Code gate block, in stops): A check run failed and blocked an agent, naming the gates that failed.
  • checkpoint.waiting (Checkpoint waiting, in checkpoints): A run stopped before an irreversible step and waits for a person to approve, reject or ask for a revision.
  • sensitive_data.found (Sensitive data found, in findings): Data gate blocked, redacted or held sensitive data, or would have in monitor mode.
  • data_guard.updated (Data gate settings changed, in changes): The Data gate mode, fail mode, rules or detectors changed.
  • api_key.created (Key created, in keys): A device was added or an API key was created.
  • api_key.revoked (Key revoked, in keys): A device or an API key was revoked.

A Data gate block also stops the agent's tool call, so it can arrive as an action gate denial too. Pick the one you want, or both.

A waiting checkpoint names what the run is about to do, its plan and its rollback, and links to the Overview. There the session's owner answers it with Approve, Reject or Revision. Answering needs a recent sign-in, and the run is told who answered.

Message format

Any other address gets JSON. Every message has type, title, count, created_at, timestamp and url, and lists its rows under the field its type names above. A stop also keeps event and projects. The message is signed the Standard Webhooks way, with three headers:

  • webhook-id: the message ID.
  • webhook-timestamp: when it was sent, in seconds since 1970.
  • webhook-signature: v1, and the base64 HMAC-SHA256 of the ID, the timestamp and the raw body, joined by dots.

Verify a message

The key is the text after whsec_ in the signing secret, base64 decoded. Asondy shows the secret once, when you add the address. Check the signature before you trust a message, and refuse one whose timestamp is more than five minutes off your clock. In Node:

const crypto = require('node:crypto');

function verify(secret, headers, rawBody) {
  const key = Buffer.from(secret.replace(/^whsec_/, ''), 'base64');
  const id = headers['webhook-id'], ts = headers['webhook-timestamp'];
  const want = crypto.createHmac('sha256', key).update(id + '.' + ts + '.' + rawBody).digest();
  const fresh = Math.abs(Date.now() / 1000 - Number(ts)) < 300;
  return fresh && headers['webhook-signature'].split(' ').some((sig) => {
    const got = Buffer.from(sig.replace(/^v1,/, ''), 'base64');
    return got.length === want.length && crypto.timingSafeEqual(got, want);
  });
}

The Standard Webhooks libraries for other languages run the same check. Rotate secret in the same list replaces the secret, and the old one stops working at once.

Continue readingDashboard terms