Delivery and Limitations
Webhooks are a best-effort notification, not a reliable event stream. This page sets out exactly what the delivery mechanism does and does not guarantee, so that you can design around it rather than discover it in production.
How a delivery happens
When an enabled event occurs, Dead Simple Chat sends a single POST request to your Webhook URL
with the JSON body described in Payloads. The request is made out of band —
nothing in the chat room waits for it.
Delivery is therefore asynchronous and out of band. Nothing in the chat room waits for your endpoint, and nothing in the chat room changes based on your response. Dead Simple Chat does not read your response body.
Deliveries are unsigned
There is no signature header. Requests arrive with no X-Signature, no HMAC, no shared secret,
no bearer token and no custom Dead Simple Chat header of any kind. A request from Dead Simple Chat
is indistinguishable from a request that anyone else makes to the same URL with the same body.
Because of that:
- Treat the Webhook URL as a secret. Use a long, unguessable path, for example
https://example.com/hooks/dsc/9f2c1d4a6b8e47f0a1c3, and rotate it if it leaks. - Use
https. The payload can include user email addresses, IP addresses, message content and, for the chat room events, the room's own configuration. - Do not trust the body. Treat everything in it as a claim rather than a fact. If a webhook is going to trigger something that matters — billing, moderation, provisioning — confirm it first by reading the state back with an authenticated REST API call such as Get a Chat Room.
- We do not publish a source IP range, so an IP allowlist is not an alternative to keeping the URL secret.
There is no retry
A delivery is attempted exactly once. If the request fails — your endpoint is down, it times
out, it returns a 500, DNS fails, the TLS handshake fails — the event is discarded. There is:
- no retry and no backoff
- no delivery history or failure report in the dashboard
- no way to inspect, replay or recover a failed delivery
An event that is not delivered is simply gone.
Do not use webhooks as your only copy of anything. If you need a complete record of chat activity, reconcile periodically with the Get Chat Messages API or the Export Messages API, and treat webhooks as the fast path rather than the source of truth.
Because a slow response is as fatal as a failed one, acknowledge the request as soon as you have the body, and do your own work afterwards:
app.post("/hooks/dsc/9f2c1d4a6b8e47f0a1c3", express.json(), (req, res) => {
res.sendStatus(200); // acknowledge first
queue.push(req.body); // process afterwards, in your own worker
});
Ordering and duplicates
Events are sent as they happen and usually arrive within a second or two, but the order is not
guaranteed. Do not assume that user_joined_chatroom arrives before
that user's first new_chatroom_message, or that a room's chatroom_created arrives before the
channel_created of a channel inside it. Where order matters, use the created timestamps in the
payload.
Events carry no delivery id, so a handler that must be idempotent should key on the ids inside the
payload, such as data.chatMessage._id.
One URL for the whole account
There is a single Webhook URL per account. It cannot be set per chat room, per channel or per event, and there is no secondary or fallback URL. Every event you switch on goes to that one endpoint, for every room in the account.
If you need per-room routing, send everything to one endpoint of your own and fan it out from there using the room identifier in the payload — see Which identifier each event gives you.
Plan availability
Webhooks are not included in every plan. When an account is on a plan that does not include them, Settings -> Webhooks shows an upgrade prompt and no events are sent, even if a URL and switches were saved earlier on a plan that did include them. Events that happen during that time are not delivered later either.
Actions that do not send webhooks
Some things that look like they should produce an event do not:
| Action | What is sent |
|---|---|
| Deleting all of a room's messages, from the dashboard or with the Delete Chat Room Messages API | Nothing. There is no chatroom_message_deleted per message. |
| Deleting a user's messages from Dashboard -> Moderation | Nothing |
| Sending a message as a moderator from Dashboard -> Moderation | Nothing. new_chatroom_message is not sent for it. |
| Deleting or approving a channel message from Dashboard -> Moderation | Nothing. The chat room equivalents do send events from that page. |
| Starting a conversation or sending a private message from Dashboard -> Moderation | Nothing |
| Sending a message with the Send Bot Message API | Nothing. Bot messages do not raise new_chatroom_message. |
| A user joining a channel | Nothing — see below |
Known limitations
Three of the switches on the Settings -> Webhooks page do not behave the way their labels suggest. Read this section before you rely on them.
The Channel Joined switch does nothing
Settings -> Webhooks has a Channel Joined switch, described as "Webhook will be sent when a user join the channel/sub-room". No such event exists — nothing is emitted for it anywhere in the product. Turning the switch on has no effect and no event will arrive.
There is no webhook for channel joins, and no other switch delivers one.
Private Message Initiated is controlled by the Channel Created switch
private_message_initiated is delivered whenever the Channel Created switch is on, and the
Private Message Initiated switch has no effect. This has two consequences:
- Turning on Private Message Initiated does not deliver anything.
- Turning on Channel Created delivers
channel_createdandprivate_message_initiated. If you only want channel lifecycle events, ignoreprivate_message_initiatedin your handler — and note that until you do, your endpoint is receiving the identities of both participants of every private conversation opened in your rooms.
Filter on the event string, never on the switch you think you turned on.
chatroom_deleted has no switch
chatroom_deleted is sent when a chat room is deleted, but Settings -> Webhooks has no switch
for it, so it cannot be turned on from the dashboard and is off by default. If you need this event,
contact support.
Payload limitations
A few payloads are missing fields you might expect. They are covered in detail in Payloads, and summarised here:
user_left_chatroomcarries no room identifier, so it cannot tell you which room the user left.chatroom_message_like_togglecarries no room or channel identifier, only the message id.- The message events identify their room with the internal
_id, not the publicroomIdthat the REST API uses. new_channel_messageand the other channel message events identify the channel but not the chat room.new_private_messagehas no message id, conversation id or timestamp.- Only the current state is ever sent.
chatroom_updatedandchannel_updateddo not tell you which fields changed or what the previous values were.