Browse the help centre

Webhooks

Subscribe an endpoint to workspace events, what we POST, and how to receive it safely today.

Reference

On this page

A webhook subscription POSTs to your endpoint when something happens in the workspace, so another system can react without polling.

Subscribing

Settings → Webhooks → New subscription: an event and an https:// endpoint. One subscription is one event — subscribe several times for several events.

The endpoint is validated when you save it, not when we first call it: it must be a well-formed public https:// URL. Private and loopback addresses are refused, and the refusal is a security control rather than a formatting rule.

Events

EventFires when
conversation.createdA conversation is opened
conversation.updatedStatus, priority or assignee changes
message.createdA message is sent or received
message.status_changedAn outbound message is delivered, read or fails
order.createdAn order is created
order.verifiedAn order is verified
order.refundedAn order is refunded
insight.emittedRevenue intelligence emits an insight

What we send

POST, Content-Type: application/json:

{
  "event": "message.created",
  "payload": { "…": "the object the event is about" },
  "timestamp": "2026-08-21T09:14:22.000Z",
  "delivery_id": "…"
}

With these headers:

HeaderMeaning
X-Juno-EventThe event name, so you can route without parsing the body
X-Juno-Signaturesha256=<hex> — HMAC-SHA256 over the exact body bytes
X-Juno-Delivery-IdStable across retries of the same event — your deduplication key

Delivery is at-least-once. The same delivery_id can arrive more than once, so make your handler idempotent: record the id and ignore a repeat. Manual redeliveries (the Redeliver button) carry no delivery_id, because they are not a retry of anything.

Return a 2xx quickly. Anything else is recorded as the subscription's last status and is visible on its row — which is where to look first when an integration has gone quiet.

Receiving it safely — read this before you act on a payload

The delivery is signed, but the signing key is not yet exposed anywhere you can read it: it is derived per workspace on the server, and no screen or endpoint returns it. Until that ships you cannot verify X-Juno-Signature, and an endpoint that acts on an unverified POST will act on anybody's POST.

So, today:

  • Treat the body as a notification, not as data. Take the object's id from it and re-read the object through the API with an API key. That is authenticated, and it is also how you avoid acting on a payload that was already superseded.
  • Keep the endpoint unguessable, and rate-limit it.
  • Never let it perform anything destructive or financial on the strength of the POST alone.

This is a real limitation rather than an oversight in the documentation, and it is written here plainly because the alternative — describing signature verification you cannot actually perform — would leave you believing an endpoint is protected when it is not.