Skip to main content

Webhooks — events, signatures, Slack and Teams

Webhooks deliver workspace events to your endpoint as JSON POSTs. They are an Enterprise+ feature, configured at /settings/webhooks. Slack, Microsoft Teams, and Discord endpoints are auto-detected and rendered with native message cards.

Event types

EventWhen it fires
brief.generatedA daily Brief completes synthesis and validation
brief.retractedA Brief paragraph is retracted via the moderation queue
forecast.prediction_createdA new Forecast prediction crosses the publish threshold
watch.alert_firedA watched agency, vendor, or keyword triggers an alert
saved_search.alert_firedA saved-search delta crosses the per-search threshold
case.evidence_addedEvidence is pinned to a case

Each event payload includes id, event, created_at, workspace_id, and a typed data block. The full payload schema lives in the public API docs at /docs/api.

Signature verification

Every delivery includes an X-FedGrade-Signature header with the HMAC-SHA256 of the raw body, signed with your endpoint's signing secret. Verify before processing:

signed = hmac_sha256(signing_secret, raw_body)
ok = constant_time_equal(signed_hex, header_value)

Reject any request where the signature doesn't match. Reject any request whose X-FedGrade-Timestamp is more than 5 minutes off your server clock — that protects against replay.

Rotate the signing secret at /settings/webhooks/{endpoint} → "Rotate secret." Like API keys, rotation has a 24-hour grace window during which both the old and new secret will validate.

Slack, Teams, Discord auto-rendering

If your endpoint hostname matches hooks.slack.com, outlook.office.com/webhook/, or discord.com/api/webhooks/, the delivery is reformatted into the native message format for that platform:

  • Slack — Block Kit with a header, paragraph block, and "View in FedGrade" action button
  • Teams — Adaptive Card with the same layout
  • Discord — Embed with title, description, and inline-field metadata

No transformation is applied to other hostnames — your endpoint receives the raw JSON payload.

Retries

Failed deliveries (non-2xx response, or timeout past 10s) are retried with exponential backoff. The delay after attempt n is 2ⁿ seconds, capped at one hour — so in practice the retry gaps are ~2s, 4s, 8s, 16s. A retry sweep runs every 5 minutes and picks up deliveries whose next_retry_at has elapsed, so the observed gap is the backoff rounded up to the next sweep.

A delivery is attempted at most 5 times; after the fifth it is dead-lettered. Separately, an endpoint is auto-disabled after 10 consecutive failed deliveries (a running counter — there is no one-hour window). Disabled endpoints are flagged at /settings/webhooks with the reason recorded.

Testing

Each endpoint has a "Send test event" button that delivers a synthetic brief.generated payload with data.test == true. Use this for development setup and to verify signature handling without waiting for a real Brief.

Audit

Every webhook delivery (success or failure) is logged at /settings/webhooks/{endpoint}/deliveries with the request ID, timestamp, response status, response body (first 4KB), and signature header. Deliveries are retained for 30 days; Government tier extends to 7 years.

Last updated 2026-05-28.


Was this article helpful?
Still need help? File a ticket via the floating "?" button on any app view, or email support@fedgrade.com.
Webhooks — events, signatures, Slack and Teams · Help