hand_off_conversation
Hand off the conversation to a human agent from within an action.
hand_off_conversation(context: dict, reason: str = None, phone_destination: str = None) -> dictHands off the conversation to a human agent. Once handed off, the bot stops responding and a human takes over.
This is the programmatic equivalent of the built-in transferConversation action — use it when the handoff decision depends on logic inside your action rather than the workflow instructions.
Parameters
| Name | Type | Description |
|---|---|---|
context | dict | The context object passed to your action |
reason | str or None | Optional reason for the handoff (max 500 characters) |
phone_destination | str or None | Optional phone number to forward a live phone call to (E.164 format, e.g. +15551234567). Silently ignored outside the phone channel. |
Returns
dict — {"success": bool, "message": str}
Behavior
- Once handed off, the bot will not respond to further messages in this conversation.
- If the conversation is already handed off, the operation succeeds without changes.
- Skipped in test/mock environments.
- On the phone channel, providing
phone_destinationtransfers the live call to that number instead of performing a standard handoff. The bot stops talking once the transfer fires. - Outside the phone channel,
phone_destinationis silently ignored — the call falls through to a normal handoff. This means the same action code can be reused across channels. - When a phone transfer fires, the action's return value is ignored (the bot won't see it because the call has been handed off). It is still fine and normal to return a regular
{"success": True}shape — keep the return shape consistent so the same action behaves correctly when it runs outside a phone call (e.g. on chat) or when no transfer is attempted (e.g. outside business hours).
Examples
Hand off when an API call reveals a complex case
def execute_action(context):
order = fetch_order(context["args"]["orderId"])
if order.get("hasFraudFlag"):
hand_off_conversation(context, "Order flagged for fraud review")
return {"handedOff": True, "reason": "fraud_flag"}
return orderHand off with context about what was attempted
def execute_action(context):
try:
result = process_cancellation(context["args"]["orderId"])
return result
except Exception as e:
hand_off_conversation(
context,
f"Automatic cancellation failed: {str(e)}"
)
return {"handedOff": True, "error": str(e)}Transfer a phone call during business hours, fall back to a regular handoff otherwise
from datetime import datetime
from zoneinfo import ZoneInfo
def execute_action(context):
now_et = datetime.now(ZoneInfo("America/New_York"))
within_hours = now_et.weekday() <= 5 and 9 <= now_et.hour < 20
if within_hours:
hand_off_conversation(context, phone_destination="+15551234567")
# Ignored when a phone transfer fires; useful on other channels.
return {"success": True}
hand_off_conversation(context)
return {
"success": False,
"message": (
"It's currently outside business hours (Mon–Sat 9 AM–8 PM ET). "
"Let the customer know an agent will follow up within ~24 hours, "
"and invite them to leave any details for the agent."
),
}