Skip to content

Outbound webhooks

Create an outbound webhook in your workspace to receive events at your own HTTPS endpoint. Each webhook subscribes to one or more events, is scoped to a channel or the whole workspace, and is signed with a secret shown once at creation.

A message.created delivery looks like this (fields under conversation and message.direction are present for support channels):

{
"event": "message.created",
"channel": { "id": "chn_…", "name": "Website", "kind": "support" },
"message": {
"id": "msg_…",
"content_type": "text",
"created_at": "2026-07-13T12:00:00+00:00",
"direction": "visitor"
},
"conversation": {
"id": "cnv_…",
"external_reference": "order-1234",
"external_user_id": "user-42"
}
}

direction is visitor, agent, or system.

By default the payload carries no message text — only metadata. If the webhook opts into content, the payload adds:

"message": {
"content": "How can I help?",
"content_language": "en"
}

The content is the completed translation in the webhook’s preferred content_language when it’s ready, otherwise the original text — so an integration receives every crossing message already in its language.

Every delivery carries:

X-Rosetta-Signature: t=<unix>,v1=<hmac_sha256("<t>.<body>", secret)>

Recompute the HMAC over "<t>.<rawBody>" with your webhook secret and compare in constant time. Reject deliveries whose timestamp is too old (a 5-minute window is a good default) to guard against replays.

// Node.js (Express raw body)
import crypto from 'node:crypto';
function verify(rawBody, header, secret) {
const parts = Object.fromEntries(
header.split(',').map((kv) => kv.split('=')),
);
const t = parts.t;
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
const expected = crypto
.createHmac('sha256', secret)
.update(`${t}.${rawBody}`)
.digest('hex');
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}

Every delivery is recorded — status, response code, attempts — so you can debug integrations. Failed deliveries are retried with backoff, and you can manually retry a delivery from the webhook’s delivery log in workspace settings.