Open navigation

SupportMesh Docs

Developers / APIProduct guide

Webhooks

Work with the implemented webhook system as it exists today, including the actual event names, signature format, and the separate inbound email webhook route.

Endpoint basics

Webhook endpoints are workspace-scoped and require HTTPS. SupportMesh rejects unsafe targets such as localhost, inline credentials, and private-network destinations.

Current outbound event catalog

  • ticket.created
  • ticket.updated
  • ticket.assigned
  • ticket.status_changed
  • ticket.resolved
  • ticket.closed
  • ticket.reopened
  • ticket.comment.created
  • estimate.submitted
  • estimate.approved
  • estimate.rejected
  • defect.created
  • defect.updated
  • defect.fixed
  • release.published
  • download.published
  • knowledge_base.article.published
  • client.created
  • client.updated

Current payload envelope

Outbound webhook payloads are minimal versioned event envelopes. The current payload builder includes `event_id`, `event_type`, `event_version`, `occurred_at`, `tenant_id`, and `data`.

{
  "event_id": "11111111-1111-1111-1111-111111111111",
  "event_type": "ticket.created",
  "event_version": 1,
  "occurred_at": "2026-07-27T10:30:00.000Z",
  "tenant_id": "22222222-2222-2222-2222-222222222222",
  "data": {
    "ticket_id": "33333333-3333-3333-3333-333333333333"
  }
}

Signature headers and verification

  • X-SupportMesh-Delivery-Id
  • X-SupportMesh-Event-Id
  • X-SupportMesh-Event-Type
  • X-SupportMesh-Signature
  • X-SupportMesh-Timestamp

SupportMesh signs each outbound request as `sha256=<hex>` using an HMAC SHA-256 digest of `<timestamp>.<raw-body>`.

import { createHmac } from "node:crypto";

function verify(body: string, timestamp: string, secret: string, provided: string) {
  const expected = "sha256=" + createHmac("sha256", secret)
    .update(`${timestamp}.${body}`, "utf8")
    .digest("hex");
  return expected === provided;
}

Inbound Resend webhook route

SupportMesh also exposes an internal inbound route at `/api/webhooks/resend/inbound` for email intake. That route accepts only the Resend event types listed below after Svix verification.

  • email.received
  • inbound_email.received
  • svix-id
  • svix-signature
  • svix-timestamp