Webhooks and chat destinations
Deliver workspace events (tasks, CRM, documents, security) to your own endpoints as signed JSON.
Webhooks and chat destinations
A destination sends workspace events somewhere else. There are three kinds, all managed at Settings, Developers, Webhooks.
- Discord posts a formatted message to a Discord channel.
- Slack posts a formatted message to a Slack channel.
- Custom endpoint posts signed JSON to your own HTTPS URL.
You can add as many as you like, in any combination. Each one has its own events and its own delivery schedule, so the finance channel does not have to receive task activity.
Adding a Discord or Slack destination
- In Discord, open Channel Settings, Integrations, Webhooks, then New Webhook and Copy Webhook URL. In Slack, create an Incoming Webhook app for the channel and copy its URL.
- Open Settings and pick the Developers tab.
- Under Webhooks, choose Add webhook, then set Destination to Discord or Slack.
- Paste the URL, add a description so you can tell your destinations apart later, and pick the events this channel should receive.
- Choose a delivery schedule.
A chat destination has no signing secret. The webhook URL is itself the credential, which is why it is worth treating like a password. Anyone holding it can post to that channel.
Delivery schedule
Chat destinations support three cadences:
- Immediately posts one message per event, as it happens.
- Daily digest collects everything and posts one summary at a time you choose.
- Weekly digest does the same once a week, on a day and time you choose.
Digests use the time zone set on the destination, so a team spread across regions can have each channel summarised in local working hours. Timing is accurate to within about fifteen minutes of the time you pick.
A digest that has nothing to report stays quiet rather than posting an empty summary. A digest with more than 25 items lists the first 25 and states how many more there were.
Immediate delivery on a busy event like task changes is how a channel becomes noise that everyone mutes. A daily digest for routine activity and immediate delivery for only the events that need a response tends to keep both useful.
Adding a custom endpoint
- Choose Add webhook and leave Destination set to Custom endpoint.
- Enter an HTTPS URL, an optional description, and pick your events. Leave all events unchecked to receive every event.
- Copy the signing secret shown after creation. It is shown only once.
Custom endpoints always deliver immediately. Digests are not offered for them, because a receiver is written to parse one signed event per request and a summary would not match that shape.
Request format
Each delivery is a POST with a JSON body:
{ "event": "task.created", "timestamp": "2026-01-01T00:00:00.000Z", "data": { "id": "...", "title": "..." } }Headers:
X-Zetadeck-Event: the event name.X-Zetadeck-Signature:sha256=<hex>, an HMAC-SHA256 of the raw request body using your webhook secret.
Verifying the signature
Compute HMAC-SHA256 of the raw body with your secret and compare it to the header. For example in Node:
import { createHmac, timingSafeEqual } from "node:crypto";
const expected = "sha256=" + createHmac("sha256", secret).update(rawBody).digest("hex");
const valid = timingSafeEqual(Buffer.from(expected), Buffer.from(signatureHeader));Reject requests whose signature does not match.
Events
task.createdtask.status_changedtask.deletedclient.createdclient.stage_changeddocument.createdsiem.alert
Every event reaches every kind of destination. A chat destination receives it as a readable sentence, a custom endpoint receives it as the JSON above.
Delivery notes
- Custom endpoints must respond within 5 seconds. Slow or failing deliveries are recorded in the recent deliveries list for each destination.
- A failed digest is retried on the next attempt rather than discarded, so a channel that was briefly unreachable still gets its summary.
- Disable a destination with its toggle to pause deliveries without deleting it.
- Rotate a compromised secret, or a leaked Discord or Slack URL, by deleting the destination and creating a new one.
If you set Discord or Slack up before this change, under Settings, Integrations, that still works and needs no action. It behaves as a destination that receives every event immediately. To give it its own events or a digest, add it here as a destination and remove the old integration URL.