Webhook event reference
The five events OyeChats sends, and the exact contents of each one's `data` object.
The five events
| Event | Dashboard label | Fires when |
|---|---|---|
tier_transition | Lead qualified | A conversation crosses a qualification tier boundary. |
lead_captured | Lead captured | A visitor submits contact details. |
handoff_requested | Handoff requested | A visitor asks to speak to a human. |
meeting_booked | Meeting booked | A visitor books a meeting through the widget. |
chat_closed | Conversation closed | An operator closes or resolves a live conversation. |
Subscribe narrowly. Select only the events you handle. An endpoint subscribed to everything gets retried on payloads it ignores, which makes your delivery log harder to read when something real breaks.
tier_transition
The event most integrations are built on. new_tier is one of unqualified, mql, sal, sql.
JSON
{
"event": "tier_transition",
"bot_id": 42,
"timestamp": "2026-08-17T14:23:05.412000+00:00",
"data": {
"session_id": "session_8f3a2b1c",
"old_tier": "mql",
"new_tier": "sql",
"score": 80,
"behavioral_score": 15
}
}No contact details in this payload. This event carries scores and tiers only. To get the contact for the same conversation, either handle
lead_captured as well or call GET /leads/{session_id} with the session_id from this payload.lead_captured
JSON
{
"event": "lead_captured",
"bot_id": 42,
"timestamp": "2026-08-17T14:19:44.108000+00:00",
"data": {
"session_id": "session_8f3a2b1c",
"name": "Sarah Chen",
"email": "sarah@acme.com",
"phone": "+91 98765 43210",
"company": "Acme"
}
}Fields the visitor did not supply arrive as null. Only session_id is guaranteed non-null.
handoff_requested
JSON
{
"event": "handoff_requested",
"bot_id": 42,
"timestamp": "2026-08-17T14:21:02.771000+00:00",
"data": {
"session_id": "session_8f3a2b1c",
"reason": "Wants to discuss enterprise pricing",
"department_id": 3,
"contact": {
"name": "Sarah Chen",
"email": "sarah@acme.com",
"phone": "+91 98765 43210"
}
}
}contact is present only if the conversation had already captured details. department_id is null when the visitor was not asked to choose a department.
meeting_booked
JSON
{
"event": "meeting_booked",
"bot_id": 42,
"timestamp": "2026-08-17T14:31:19.004000+00:00",
"data": {
"session_id": "session_8f3a2b1c",
"booking_url": "https://calendly.com/acme/intro/2026-08-20T10:00:00Z",
"meeting_time": "2026-08-20T10:00:00+00:00",
"attendee_email": "sarah@acme.com"
}
}chat_closed
JSON
{
"event": "chat_closed",
"bot_id": 42,
"timestamp": "2026-08-17T14:40:55.220000+00:00",
"data": {
"session_id": "session_8f3a2b1c",
"operator_id": 7,
"resolution": "resolved"
}
}resolution is present with the value resolved when the operator ended the conversation outright, and absent when they closed it back to the chatbot. That difference is how you distinguish a finished conversation from one the visitor may continue.
Something here wrong or missing? Tell us and name this page. We will fix it.