Outbound webhooks

Subscribe an HTTPS endpoint to Kustomer events. Create webhooks with the API, in Settings or from an app definition, then receive signed JSON for every customer, conversation, message, user, team and tag change.

An outbound webhook is a URL plus a list of events. When one of those events happens in your org, Kustomer sends the event envelope to the URL as a signed POST.

  1. Expose an HTTPS endpoint

    It must accept POST with a JSON body and answer with a 2xx within a few seconds. Verify the signature before trusting the body.

  2. Create the webhook

    Use the API, Settings › Platform › Outbound webhooks, or the outboundWebhooks section of an app definition.

  3. Store the token

    The response includes a token. It's the HMAC key for X-Kustomer-Webhook-Signature. Keep it in your secret store.

  4. Watch deliveries

    List recent delivery attempts per webhook to debug failures.

Create a webhook with the API

post/v1/outbound-webhooks
curl -X POST "https://acme.api.kustomerapp.com/v1/outbound-webhooks" \
  -H "Authorization: Bearer $KUSTOMER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Conversation sync",
    "url": "https://hooks.example.com/kustomer",
    "events": ["kustomer.conversation.create", "kustomer.conversation.update", "kustomer.message.create"],
    "headers": [{ "name": "X-Source", "value": "kustomer" }]
  }'
Request body
namestringrequired
urlstringrequired
eventsstring[]required
headers{ name, value }[]
enabledboolean
201 Created
{
  "data": {
    "type": "outbound-webhook",
    "id": "5f3e8f9b2b3fc60013f6b836",
    "attributes": {
      "name": "Conversation sync",
      "enabled": true,
      "url": "https://hooks.example.com/kustomer",
      "isError": false,
      "events": ["kustomer.conversation.create", "kustomer.conversation.update", "kustomer.message.create"],
      "headers": [{ "name": "X-Source", "value": "kustomer" }],
      "token": "f1253ac0dacd0a8fdbc5b8caac814865b53b164acb83f9163d5adad0195a6771…",
      "createdAt": "2026-10-21T14:58:35.499Z",
      "updatedAt": "2026-10-21T14:58:35.499Z"
    }
  }
}

isError is true while Kustomer has automatically disabled the webhook.

Receive events

A minimal receiver verifies the signature against the raw body, acknowledges immediately, then processes the event asynchronously.

import crypto from 'node:crypto'
import express from 'express'

const app = express()
const TOKEN = process.env.KUSTOMER_WEBHOOK_TOKEN!

app.post('/kustomer', express.raw({ type: 'application/json' }), (req, res) => {
  const expected = crypto.createHmac('sha256', TOKEN).update(req.body).digest('hex')
  const received = req.get('X-Kustomer-Webhook-Signature') ?? ''
  if (received.length !== expected.length || !crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected))) {
    return res.sendStatus(401)
  }
  res.sendStatus(200)
  queue.publish(JSON.parse(req.body.toString('utf8')))
})

Read Delivery and security before going to production. It covers retries, duplicates, ordering and automatic disabling.

Manage webhooks

TaskEndpoint
List webhooksGET /v1/outbound-webhooks
Get one, including its tokenGET /v1/outbound-webhooks/{id}
Change URL, events or headers, or set enabledPATCH /v1/outbound-webhooks/{id}
DeleteDELETE /v1/outbound-webhooks/{id}
List events you can subscribe toGET /v1/outbound-webhooks/events
See the 25 most recent delivery attempts for one webhookGET /v1/outbound-webhooks/{webhookId}/transactions
See recent delivery attempts across all webhooksGET /v1/outbound-webhooks/transactions

Pause a webhook during maintenance with PATCH { "enabled": false }. Events that happen while it's disabled are not queued for later, so reconcile afterwards with incremental sync.

Define webhooks in an app

Apps can create webhooks when they're installed. Add an outboundWebhooks array to the app definition with the same fields:

app definition
{
  "app": "ecommstore",
  "version": "1.2.0",
  "title": "E-comm Store",
  "outboundWebhooks": [
    {
      "name": "Send conversation events to E-comm Store",
      "url": "https://api.ecommstore.example/kustomer/events",
      "headers": [{ "name": "X-Source", "value": "kustomer" }],
      "events": ["kustomer.conversation.create", "kustomer.conversation.update"]
    }
  ]
}

Webhooks or workflows?

Outbound webhooks send every event of the subscribed types, with a fixed payload. If you only care about a subset ("conversations tagged vip that just closed") or need a different payload shape, use a workflow with a condition and a REST API step instead. Workflows can also react to events webhooks don't offer, such as custom objects and notes.