Events

Handoff events

handoff.requested and handoff.resolved — a visitor wanted a person.

handoff.requested

Fires when a visitor asks for a human, whether they tapped the handoff card or the agent offered it after failing to answer.

{
  "conversation_id": 8214,
  "chatbot_id": 17,
  "channel": "live_chat",
  "visitor": {
    "visitor_id": "v_9f21…",
    "name": "Ada Lovelace",
    "email": "[email protected]",
    "phone": null,
    "company": null,
    "message": "I need to change my order"
  },
  "requested_at": "2026-08-26T10:07:00.000Z"
}

channel is the field that matters. It is:

  • live_chat — someone is being paged and the visitor is waiting in the widget right now. This is urgent.
  • email — nobody is being paged. Either the workspace is outside its configured hours, or live chat is not on its plan. The visitor has been told a person will follow up, and is not sitting there waiting.

Treating both the same is the mistake this field exists to prevent: routing an email handoff to a pager wakes someone for a message that expects a reply tomorrow, and treating a live_chat one as an email leaves a visitor waiting in an open widget.

Every field under visitor can be null — which fields are collected is configured per agent.

handoff.resolved

Fires when a handed-off conversation is closed.

{
  "conversation_id": 8214,
  "chatbot_id": 17,
  "previous_status": "human_active",
  "resolved_at": "2026-08-26T10:31:00.000Z"
}

previous_status distinguishes the two endings:

  • human_active — an operator joined and finished the conversation.
  • pending_handoff — it was resolved while still queued, so nobody ever picked it up.

A rising count of pending_handoff resolutions is a staffing signal, not a success metric.

handoff.resolved only fires for conversations that were actually in a handoff state. An ordinary conversation being resolved fires conversation.ended alone.