Admin panel

Webhooks

Outbound webhooks — triggers, HMAC signatures, retries, delivery log and replay.

Admin only

Webhooks push events to your systems the moment they happen. Configured in the admin panel: endpoint URL, a signing secret, and which triggers to subscribe to — optionally filtered (e.g. one community only).

Triggers

Key Fires when
message.created a standard message is posted to a channel
message.replied a thread reply is posted
reaction.added a reaction lands on a message
moderation.action warn / timeout / ban / server_ban is issued

Direct messages never reach webhooks — DM content stays between participants.

Verifying deliveries

Anyone who learns your endpoint URL could POST fake events to it — so every delivery carries a signature only your Tyto server can produce, made with the secret you set on the webhook. Headers on each POST:

  • X-Tyto-Event — the trigger key
  • X-Tyto-Delivery — unique delivery id
  • X-Tyto-Signature — the seal, e.g. t=1784450000,v1=a3f9c2…

To verify, redo the computation and compare:

  1. Split the header

    t is when the delivery was signed (unix seconds); v1 is the signature to check.

  2. Rebuild the signed string

    The timestamp, a literal dot, then the raw request body — before any JSON parsing: “<t>.<body>”.

  3. Compute HMAC-SHA256

    Over that string, keyed with the webhook’s secret. The hex result must equal v1 (constant-time compare).

  4. Check freshness

    Reject deliveries whose t is older than a few minutes — that’s what stops an attacker replaying a captured request later.

import { createHmac, timingSafeEqual } from "node:crypto";

function verify(header, rawBody, secret) {
  const { t, v1 } = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
  const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
  return timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}

Reliability

Failed deliveries retry with backoff; persistent failure auto-disables the webhook while new events buffer (up to the configured cap) — re-enable and the buffer replays. Every attempt is inspectable in the delivery log.

Note

Endpoints must be external by default — targeting internal networks requires flipping the SSRF guard deliberately.