MonCha
Skip to article

Webhooks

Search MonCha documentation

Search the full guides for topics such as renewal, ticket alerts, OAuth or knowledge refresh.

MonCha POSTs signed events to your systems the moment they happen.

On this page

Available on Scale, or when webhooks are included in an active enterprise contract.

Events

  • lead.created — a visitor was scored as a lead (see the payload below).
  • conversation.handoff — a conversation requests human help; fields vary between an explicit request and a model-detected handoff.
  • message.unanswered — the bot had no relevant content for a question.
  • ticket.created — a customer opened a support ticket from the widget's Support tab.
  • booking.created — a visitor submitted an appointment request from the widget (see Bookings).

Adding one

Go to API & Agents → Webhooks, enter a public HTTPS endpoint, tick the events you want, and save. Private and internal addresses and redirects are rejected. You'll get a signing secret (whsec_…). The last delivery status is shown next to each webhook so you can spot a broken endpoint.

What you receive

POST https://yourapp.com/hooks/MonCha
X-MonCha-Event: lead.created
X-MonCha-Timestamp: 1783691750
X-MonCha-Signature: 69b291806d1023a89d4e414e…
Content-Type: application/json

{
  "event": "lead.created",
  "timestamp": 1783691750,
  "data": {
    "lead_id": "010e19a1-…",
    "session_id": "…",
    "chatbot_id": "9166406d-…",
    "score": 85,
    "band": "hot",
    "category": "pricing",
    "summary": "40-person team evaluating enterprise pricing for Q1",
    "sentiment": "positive",
    "name": "Priya Sharma",
    "email": "[email protected]",
    "phone": null,
    "country": "SG",
    "region": "Singapore",
    "external_user_id": "usr_8f21",
    "qualification": { "team_size": "40", "timeline": "Q1" },
    "captured_via": "inferred"
  }
}

Verifying the signature

Always verify before trusting a payload. The signature is the hex HMAC-SHA256 of `${timestamp}.${rawBody}`, keyed with your signing secret:

import crypto from 'crypto'

function verify(rawBody, headers, secret) {
  const ts  = headers['x-moncha-timestamp']
  const sig = headers['x-moncha-signature']
  if (!ts || !sig || !/^[0-9a-f]{64}$/i.test(sig)) return false
  const seconds = Number(ts)
  if (!Number.isFinite(seconds) || Math.abs(Date.now() / 1000 - seconds) > 300) return false
  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${ts}.${rawBody}`)
    .digest('hex')
  return crypto.timingSafeEqual(
    Buffer.from(expected, 'hex'), Buffer.from(sig, 'hex')
  )
}

Use the raw request body, not a re-serialized object — key order matters. Reject timestamps more than a few minutes old to prevent replay.

Delivery behavior

  • Delivered as a fire-and-forget POST; a slow endpoint never slows your customer's chat.
  • 10-second timeout. Respond 2xx quickly and do your work asynchronously.
  • No automatic retries today — reconcile through the API if you need guarantees.

Scoping

A webhook can listen to all bots or one specific bot. Add several webhooks if different systems care about different events.

Webhooks push events out. To let the bot pull live data during a conversation, see Functions.

Related guides

Something unclear? Tell us.

Start free trial