Webhook events
When you enable the Send Webhook on Event skill, Lexey sends HTTP POST requests to your configured URL when conversation events occur.
Event types
The following event type is currently supported:
conversation.escalated— Fired when the support agent escalates a conversation to a human (due to customer frustration, unresolvable query, or a configured escalation trigger).
When enabling the webhook skill, you choose which events to subscribe to.
Payload format
All webhook payloads are JSON. Here is an example conversation.escalated payload:
{
"event": "conversation.escalated",
"timestamp": "2026-02-19T04:30:00.000Z",
"conversation": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "escalated",
"customerIdentifier": "user@example.com",
"createdAt": "2026-02-19T04:00:00.000Z"
},
"messages": [
{
"role": "user",
"content": "I need to speak to a manager about my refund.",
"createdAt": "2026-02-19T04:00:10.000Z"
},
{
"role": "assistant",
"content": "I understand your frustration. Let me escalate this to our team.",
"createdAt": "2026-02-19T04:00:12.000Z"
}
],
"payload": {
"reason": "Customer requested manager for refund dispute"
}
}
Payload fields:
event— The event type (conversation.escalated).timestamp— When the event occurred (UTC ISO 8601).conversation— Conversation metadata including ID, status, customer identifier, and creation time.messages— The full message history (role, content, and timestamp for each message).payload— Event-specific data. For escalation events this contains areasonfield.
HMAC signature verification
If you configure a shared secret when enabling the webhook skill, every request includes an X-Lexey-Signature header for verification:
X-Lexey-Signature: sha256=a1b2c3d4e5f6...
The signature is an HMAC-SHA256 hex digest of the raw request body using your shared secret as the key.
Verification example (Node.js):
import { createHmac, timingSafeEqual } from "crypto";
function verifySignature(body: string, signature: string, secret: string): boolean {
const expected = "sha256=" + createHmac("sha256", secret).update(body).digest("hex");
return timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}
Always use constant-time comparison (
timingSafeEqual) to prevent timing attacks when verifying signatures.
Request details
- Method: POST
- Content-Type: application/json
- User-Agent: Lexey-Webhook/1.0
Your endpoint should return a 2xx status promptly. Failed deliveries are retried automatically.
Integration tips
- Return a 2xx status quickly from your endpoint — do any heavy processing asynchronously.
- Use the
conversation.idas an idempotency key to handle potential duplicate deliveries. - Log the
X-Lexey-Signatureheader and raw body for debugging signature verification issues. - All event timestamps are in UTC ISO 8601 format.