C
Chatty

Webhooks

Chatty can POST a JSON payload to your server whenever a key event occurs — no polling required.

Registering a webhook

Go to Dashboard → Settings → Webhooks and add your endpoint URL. You can also use the API:

Register via API
curl -X POST \
  "https://api.personaliai.com/api/v1/webhooks" \
  -H "Authorization: Bearer chatty_sk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-server.com/chatty-webhook",
    "events": ["lead.created", "message.assistant"]
  }'

Events

EventTrigger
lead.createdA new lead is captured by the bot.
message.userA visitor sends a message.
message.assistantThe bot replies.
session.startedFirst message in a new session.
session.endedSession inactive for 30 minutes.

Payload format

Every webhook POST has the same envelope:

{
  "event": "lead.created",
  "bot_id": "a1b2c3d4-...",
  "session_id": "visitor-xyz-789",
  "timestamp": "2026-07-07T12:34:56Z",
  "data": { ... }
}

lead.created data

{
  "id": "ld_001abc",
  "name": "Sarah Chen",
  "email": "sarah@example.com",
  "phone": "+1-555-0123",
  "extra": {}
}

message.assistant data

{
  "message_id": "msg-uuid-011",
  "role": "assistant",
  "content": "Yes! Our Enterprise plan includes unlimited bots, SSO, and dedicated support.",
  "latency_ms": 820
}

Signature verification

Every request includes an X-Chatty-Signature header — an HMAC-SHA256 of the raw request body signed with your webhook secret.

Python — verify signature
import hmac, hashlib
 
def verify(payload: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(secret.encode(), payload, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature)
Node.js — verify signature
import crypto from "crypto"
 
function verify(payload: Buffer, signature: string, secret: string): boolean {
  const expected = crypto.createHmac("sha256", secret)
    .update(payload).digest("hex")
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature))
}
Always verify the signature before processing the payload. Reject requests where verification fails with a 401 response.

Retries

Chatty retries failed deliveries (non-2xx or timeout) with exponential back-off: after 1s, 5s, 30s, 5min, 30min, 2h, 8h. After 7 attempts the event is dropped.

Return a 200 as fast as possible — offload processing to a queue. Webhooks time out after 10 seconds.

Testing locally

Use a tunnel like ngrok or Cloudflare Tunnel to expose your local server:

ngrok http 3000
# Chatty webhook URL: https://abc123.ngrok.io/chatty-webhook